soc/intel/tgl,mb/google/volteer: Add API for Type-C aux bias pads

TGL boards using the Type-C subsystem for USB Type-C ports without a
retimer attached may require a DC bias on the aux lines for certain
modes to work. This patch adds native coreboot support for programming
the IOM to handle this DC bias via a simple devicetree
setting. Previously a UPD was required to tell the FSP which GPIOs were
used for the pullup and pulldown biases, but the API for this UPD was
effectively undocumented.

BUG=b:174116646
TEST=Verified on volteer2 that a Type-C flash drive is enumerated
succesfully on all ports. Verified all major power flows (boot, reboot,
powerdown and S0ix/suspend) still work as expected.

Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Change-Id: I70e36a41e760f4a435511c147cc5744a77dbccc0
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51649
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
diff --git a/src/mainboard/google/volteer/variants/eldrid/overridetree.cb b/src/mainboard/google/volteer/variants/eldrid/overridetree.cb
index ed157559..f64370a 100644
--- a/src/mainboard/google/volteer/variants/eldrid/overridetree.cb
+++ b/src/mainboard/google/volteer/variants/eldrid/overridetree.cb
@@ -15,8 +15,8 @@
 	register "TcssAuxOri" = "1"
 	register "DdiPort1Hpd" = "0"
 	register "DdiPort2Hpd" = "0"
-	register "IomTypeCPortPadCfg[0]" = "0x090E000A"
-	register "IomTypeCPortPadCfg[1]" = "0x090E000D"
+	register "typec_aux_bias_pads[0]" = "{.pad_auxp_dc = GPP_E10, .pad_auxn_dc = GPP_E13}"
+
 	#+-------------------+---------------------------+
 	#| Field             |  Value                    |
 	#+-------------------+---------------------------+
diff --git a/src/mainboard/google/volteer/variants/elemi/overridetree.cb b/src/mainboard/google/volteer/variants/elemi/overridetree.cb
index 5aba269..ae73246 100644
--- a/src/mainboard/google/volteer/variants/elemi/overridetree.cb
+++ b/src/mainboard/google/volteer/variants/elemi/overridetree.cb
@@ -3,8 +3,7 @@
 	register "TcssAuxOri" = "1"
 	register "DdiPort1Hpd" = "0"
 	register "DdiPort2Hpd" = "0"
-	register "IomTypeCPortPadCfg[0]" = "0x090E000A"
-	register "IomTypeCPortPadCfg[1]" = "0x090E000D"
+	register "typec_aux_bias_pads[0]" = "{.pad_auxp_dc = GPP_E10, .pad_auxn_dc = GPP_E13}"
 
         # Enable EMMC PCIE 5 using clk 5
         register "PcieRpEnable[4]" = "1"
diff --git a/src/mainboard/google/volteer/variants/lindar/overridetree.cb b/src/mainboard/google/volteer/variants/lindar/overridetree.cb
index 5edd6db..8274531 100644
--- a/src/mainboard/google/volteer/variants/lindar/overridetree.cb
+++ b/src/mainboard/google/volteer/variants/lindar/overridetree.cb
@@ -2,8 +2,8 @@
 	register "DdiPort1Hpd" = "0"
 	register "DdiPort2Hpd" = "0"
 	register "TcssAuxOri" = "1"
-	register "IomTypeCPortPadCfg[0]" = "0x090E000A"
-	register "IomTypeCPortPadCfg[1]" = "0x090E000D"
+	register "typec_aux_bias_pads[0]" = "{.pad_auxp_dc = GPP_E10, .pad_auxn_dc = GPP_E13}"
+
 	# USB Port Config
 	register "usb2_ports[0]" = "USB2_PORT_MID(OC_SKIP)"	# Type-A Port A0
 	register "usb2_ports[3]" = "USB2_PORT_TYPE_C(OC_SKIP)"	# Type-A / Type-C C1
diff --git a/src/mainboard/google/volteer/variants/malefor/overridetree.cb b/src/mainboard/google/volteer/variants/malefor/overridetree.cb
index 00d609f..0d25df8 100644
--- a/src/mainboard/google/volteer/variants/malefor/overridetree.cb
+++ b/src/mainboard/google/volteer/variants/malefor/overridetree.cb
@@ -12,8 +12,7 @@
 	register "SaGv" = "SaGv_Disabled"
 
 	register "TcssAuxOri" = "1"
-	register "IomTypeCPortPadCfg[0]" = "0x090E000A"
-	register "IomTypeCPortPadCfg[1]" = "0x090E000D"
+	register "typec_aux_bias_pads[0]" = "{.pad_auxp_dc = GPP_E10, .pad_auxn_dc = GPP_E13}"
 
 	# I2C Port Config
 	register "SerialIoI2cMode" = "{
diff --git a/src/mainboard/google/volteer/variants/voema/overridetree.cb b/src/mainboard/google/volteer/variants/voema/overridetree.cb
index 86b71ee..32f1a53 100644
--- a/src/mainboard/google/volteer/variants/voema/overridetree.cb
+++ b/src/mainboard/google/volteer/variants/voema/overridetree.cb
@@ -9,8 +9,7 @@
 	register "usb2_ports[4]" = "USB2_PORT_TYPE_C(OC_SKIP)"	# Type-A / Type-C Port 0
 
 	register "TcssAuxOri" = "1"
-	register "IomTypeCPortPadCfg[0]" = "0x090E000A"
-	register "IomTypeCPortPadCfg[1]" = "0x090E000D"
+	register "typec_aux_bias_pads[0]" = "{.pad_auxp_dc = GPP_E10, .pad_auxn_dc = GPP_E13}"
 
 	# Disable WLAN PCIE 7
 	register "PcieRpEnable[6]" = "0"
diff --git a/src/mainboard/google/volteer/variants/volteer/overridetree.cb b/src/mainboard/google/volteer/variants/volteer/overridetree.cb
index bce953b..786ac02 100644
--- a/src/mainboard/google/volteer/variants/volteer/overridetree.cb
+++ b/src/mainboard/google/volteer/variants/volteer/overridetree.cb
@@ -44,8 +44,7 @@
 		},
 	}"
 	register "TcssAuxOri" = "1"
-	register "IomTypeCPortPadCfg[0]" = "0x090E000A"
-	register "IomTypeCPortPadCfg[1]" = "0x090E000D"
+	register "typec_aux_bias_pads[0]" = "{.pad_auxp_dc = GPP_E10, .pad_auxn_dc = GPP_E13}"
 
 	register "HybridStorageMode" = "1"
 
diff --git a/src/mainboard/google/volteer/variants/volteer2/overridetree.cb b/src/mainboard/google/volteer/variants/volteer2/overridetree.cb
index 635a310..4e8302a 100644
--- a/src/mainboard/google/volteer/variants/volteer2/overridetree.cb
+++ b/src/mainboard/google/volteer/variants/volteer2/overridetree.cb
@@ -1,7 +1,6 @@
 chip soc/intel/tigerlake
 	register "TcssAuxOri" = "1"
-	register "IomTypeCPortPadCfg[0]" = "0x090E000A"
-	register "IomTypeCPortPadCfg[1]" = "0x090E000D"
+	register "typec_aux_bias_pads[0]" = "{.pad_auxp_dc = GPP_E10, .pad_auxn_dc = GPP_E13}"
 	register "DdiPort1Hpd" = "0"
 	register "DdiPort2Hpd" = "0"
 	#+-------------------+---------------------------+
diff --git a/src/soc/intel/common/block/include/intelblocks/tcss.h b/src/soc/intel/common/block/include/intelblocks/tcss.h
index 68e279c..29093d1 100644
--- a/src/soc/intel/common/block/include/intelblocks/tcss.h
+++ b/src/soc/intel/common/block/include/intelblocks/tcss.h
@@ -3,6 +3,8 @@
 #ifndef _TCSS_H_
 #define _TCSS_H_
 
+#include <intelblocks/gpio.h>
+
 /* PMC IPC related offsets and commands */
 #define PMC_IPC_USBC_CMD_ID		0xA7
 #define PMC_IPC_USBC_SUBCMD_ID		0x0
@@ -136,7 +138,17 @@
 	uint8_t usb3_port; /* USB3 Port Number */
 };
 
-void tcss_configure(void);
+struct typec_aux_bias_pads {
+	gpio_t pad_auxn_dc;
+	gpio_t pad_auxp_dc;
+};
+
+/*
+ * 1) Initialize TCSS muxes to disconnected state
+ * 2) Configure GPIO pads to provide DC Bias on AUX signals
+ * 3) Detect DP-over-Type-C alternate mode
+ */
+void tcss_configure(const struct typec_aux_bias_pads pads[MAX_TYPE_C_PORTS]);
 
 /*
  * Mainboard method to setup any mux config needed for TCSS display operations.
diff --git a/src/soc/intel/common/block/tcss/tcss.c b/src/soc/intel/common/block/tcss/tcss.c
index 6d1f3af..da19954 100644
--- a/src/soc/intel/common/block/tcss/tcss.c
+++ b/src/soc/intel/common/block/tcss/tcss.c
@@ -4,12 +4,18 @@
 #include <console/console.h>
 #include <device/pci.h>
 #include <intelblocks/pmc_ipc.h>
+#include <intelblocks/systemagent.h>
 #include <intelblocks/tcss.h>
 #include <inttypes.h>
 #include <security/vboot/vboot_common.h>
 #include <soc/pci_devs.h>
+#include <soc/pcr_ids.h>
+#include <soc/tcss.h>
 #include <stdlib.h>
 
+#define BIAS_CTRL_VW_INDEX_SHIFT		16
+#define BIAS_CTRL_BIT_POS_SHIFT			8
+
 static uint32_t tcss_make_conn_cmd(int u, int u3, int u2, int ufp, int hsl,
 					int sbu, int acc)
 {
@@ -307,7 +313,32 @@
 	}
 }
 
-void tcss_configure(void)
+static uint32_t calc_bias_ctrl_reg_value(gpio_t pad)
+{
+	unsigned int vw_index, vw_bit;
+	const unsigned int cpu_pid = gpio_get_pad_cpu_portid(pad);
+	if (!gpio_get_vw_info(pad, &vw_index, &vw_bit) || !cpu_pid)
+		return 0;
+
+	return vw_index << BIAS_CTRL_VW_INDEX_SHIFT |
+		vw_bit << BIAS_CTRL_BIT_POS_SHIFT |
+		cpu_pid;
+}
+
+static void tcss_configure_aux_bias_pads(
+	const struct typec_aux_bias_pads pads[MAX_TYPE_C_PORTS])
+{
+	for (size_t i = 0; i < MAX_TYPE_C_PORTS; i++) {
+		if (pads[i].pad_auxn_dc && pads[i].pad_auxp_dc) {
+			REGBAR32(PID_IOM, IOM_AUX_BIAS_CTRL_PULLUP_OFFSET(i)) =
+				calc_bias_ctrl_reg_value(pads[i].pad_auxp_dc);
+			REGBAR32(PID_IOM, IOM_AUX_BIAS_CTRL_PULLDOWN_OFFSET(i)) =
+				calc_bias_ctrl_reg_value(pads[i].pad_auxn_dc);
+		}
+	}
+}
+
+void tcss_configure(const struct typec_aux_bias_pads aux_bias_pads[MAX_TYPE_C_PORTS])
 {
 	const struct tcss_port_map *port_map;
 	size_t num_ports;
@@ -320,6 +351,9 @@
 	for (i = 0; i < num_ports; i++)
 		tcss_init_mux(i, &port_map[i]);
 
+	/* This should be performed before alternate modes are entered */
+	tcss_configure_aux_bias_pads(aux_bias_pads);
+
 	if (CONFIG(ENABLE_TCSS_DISPLAY_DETECTION))
 		tcss_configure_dp_mode(port_map, num_ports);
 }
diff --git a/src/soc/intel/tigerlake/Makefile.inc b/src/soc/intel/tigerlake/Makefile.inc
index ae6101d..787aa05 100644
--- a/src/soc/intel/tigerlake/Makefile.inc
+++ b/src/soc/intel/tigerlake/Makefile.inc
@@ -37,12 +37,12 @@
 ramstage-y += fsp_params.c
 ramstage-y += gpio.c
 ramstage-y += lockdown.c
+ramstage-y += me.c
 ramstage-y += p2sb.c
 ramstage-y += pmc.c
 ramstage-y += reset.c
 ramstage-y += soundwire.c
 ramstage-y += systemagent.c
-ramstage-y += me.c
 ramstage-y += xhci.c
 ramstage-$(CONFIG_SOC_INTEL_CRASHLOG) += crashlog_lib.c
 
diff --git a/src/soc/intel/tigerlake/chip.h b/src/soc/intel/tigerlake/chip.h
index 8c902c3..c011093 100644
--- a/src/soc/intel/tigerlake/chip.h
+++ b/src/soc/intel/tigerlake/chip.h
@@ -9,6 +9,7 @@
 #include <intelblocks/gspi.h>
 #include <intelblocks/pcie_rp.h>
 #include <intelblocks/power_limit.h>
+#include <intelblocks/tcss.h>
 #include <soc/gpe.h>
 #include <soc/gpio.h>
 #include <soc/pch.h>
@@ -335,17 +336,14 @@
 	uint8_t UsbTcPortEn;
 
 	/*
-	 * IOM Port Config
-	 * If a port orientation needs to be controlled by the SOC this setting must be
-	 * updated to reflect the correct GPIOs being used for the SOC port flipping.
-	 * There are 4 ports each with a pair of GPIOs for Pull Up and Pull Down
-	 * 0,1 are pull up and pull down for port 0
-	 * 2,3 are pull up and pull down for port 1
-	 * 4,5 are pull up and pull down for port 2
-	 * 6,7 are pull up and pull down for port 3
-	 * values to be programmed correspond to the GPIO family and offsets
+	 * These GPIOs will be programmed by the IOM to handle biasing of the
+	 * Type-C aux (SBU) signals when certain alternate modes are used.
+	 * `pad_auxn_dc` should be assigned to the GPIO pad providing negative
+	 * bias (name usually contains `AUXN_DC` or `AUX_N`); similarly,
+	 * `pad_auxp_dc` should be assigned to the GPIO providing positive bias
+	 * (name often contains `AUXP_DC` or `_AUX_P`).
 	 */
-	uint32_t IomTypeCPortPadCfg[8];
+	struct typec_aux_bias_pads typec_aux_bias_pads[MAX_TYPE_C_PORTS];
 
 	/*
 	 * SOC Aux orientation override:
diff --git a/src/soc/intel/tigerlake/fsp_params.c b/src/soc/intel/tigerlake/fsp_params.c
index 9fbf9bd..1f1f365 100644
--- a/src/soc/intel/tigerlake/fsp_params.c
+++ b/src/soc/intel/tigerlake/fsp_params.c
@@ -23,6 +23,7 @@
 #include <soc/pci_devs.h>
 #include <soc/ramstage.h>
 #include <soc/soc_chip.h>
+#include <soc/tcss.h>
 #include <string.h>
 
 /* THC assignment definition */
@@ -188,8 +189,9 @@
 
 	params->UsbTcPortEn = config->UsbTcPortEn;
 	params->TcssAuxOri = config->TcssAuxOri;
-	for (i = 0; i < 8; i++)
-		params->IomTypeCPortPadCfg[i] = config->IomTypeCPortPadCfg[i];
+
+	/* Explicitly clear this field to avoid using defaults */
+	memset(params->IomTypeCPortPadCfg, 0, sizeof(params->IomTypeCPortPadCfg));
 
 	/*
 	 * Set FSPS UPD ITbtConnectTopologyTimeoutInMs with value 0. FSP will
@@ -460,8 +462,10 @@
 		printk(BIOS_DEBUG, "FSP MultiPhaseSiInit %s/%s called\n",
 			__FILE__, __func__);
 
-		if (CONFIG(SOC_INTEL_COMMON_BLOCK_TCSS))
-			tcss_configure();
+		if (CONFIG(SOC_INTEL_COMMON_BLOCK_TCSS)) {
+			const config_t *config = config_of_soc();
+			tcss_configure(config->typec_aux_bias_pads);
+		}
 		break;
 	default:
 		break;
diff --git a/src/soc/intel/tigerlake/include/soc/tcss.h b/src/soc/intel/tigerlake/include/soc/tcss.h
new file mode 100644
index 0000000..713528b
--- /dev/null
+++ b/src/soc/intel/tigerlake/include/soc/tcss.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _SOC_TCSS_H_
+#define _SOC_TCSS_H_
+
+/* IOM aux bias control registers in REGBAR MMIO space */
+#define IOM_AUX_BIAS_CTRL_PULLUP_OFFSET_0	0x1070
+#define IOM_AUX_BIAS_CTRL_PULLUP_OFFSET(x)	(IOM_AUX_BIAS_CTRL_PULLUP_OFFSET_0 + (x) * 4)
+#define IOM_AUX_BIAS_CTRL_PULLDOWN_OFFSET_0	0x1088
+#define IOM_AUX_BIAS_CTRL_PULLDOWN_OFFSET(x)	(IOM_AUX_BIAS_CTRL_PULLDOWN_OFFSET_0 + (x) * 4)
+
+#endif /* _SOC_TCSS_H_ */