Tim Wawrzynczak submitted this change.

View Change

Approvals: build bot (Jenkins): Verified Furquan Shaikh: Looks good to me, but someone else must approve Tim Wawrzynczak: Looks good to me, approved
soc/intel/tigerlake: Add code for early tcss

In order for USB Type-C idisplays to be detected prior to loading Kernel
PMC IPC driver is needed to communicate with PMC in order to correctly set
the USB Mux settings. This patch is adding in support for early detection
of both Displays.

BUG=b:151731851
BRANCH=NONE
TEST=built and verified that TCSS MUX is being set on Volteer

Change-Id: I58e66f21210d565fb8145d140d2fc7febecdd21a
Signed-off-by: Brandon Breitenstein <brandon.breitenstein@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/42079
Reviewed-by: Furquan Shaikh <furquan@google.com>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
---
M src/soc/intel/tigerlake/Kconfig
M src/soc/intel/tigerlake/Makefile.inc
A src/soc/intel/tigerlake/early_tcss.c
M src/soc/intel/tigerlake/fsp_params.c
A src/soc/intel/tigerlake/include/soc/early_tcss.h
5 files changed, 424 insertions(+), 0 deletions(-)

diff --git a/src/soc/intel/tigerlake/Kconfig b/src/soc/intel/tigerlake/Kconfig
index f1ac774..507f871 100644
--- a/src/soc/intel/tigerlake/Kconfig
+++ b/src/soc/intel/tigerlake/Kconfig
@@ -232,4 +232,11 @@
config PRERAM_CBMEM_CONSOLE_SIZE
hex
default 0x2000
+
+config EARLY_TCSS_DISPLAY
+ bool "Enable early TCSS display"
+ depends on RUN_FSP_GOP
+ help
+ Enable displays to be detected over Type-C ports during boot.
+
endif
diff --git a/src/soc/intel/tigerlake/Makefile.inc b/src/soc/intel/tigerlake/Makefile.inc
index 3103d60..4a41812 100644
--- a/src/soc/intel/tigerlake/Makefile.inc
+++ b/src/soc/intel/tigerlake/Makefile.inc
@@ -31,6 +31,7 @@
ramstage-y += acpi.c
ramstage-y += chip.c
ramstage-y += cpu.c
+ramstage-$(CONFIG_EARLY_TCSS_DISPLAY) += early_tcss.c
ramstage-y += elog.c
ramstage-y += espi.c
ramstage-y += finalize.c
diff --git a/src/soc/intel/tigerlake/early_tcss.c b/src/soc/intel/tigerlake/early_tcss.c
new file mode 100644
index 0000000..3944f61
--- /dev/null
+++ b/src/soc/intel/tigerlake/early_tcss.c
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <console/console.h>
+#include <device/pci.h>
+#include <intelblocks/pmc_ipc.h>
+#include <soc/early_tcss.h>
+#include <soc/pci_devs.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+
+static uint32_t tcss_make_conn_cmd(int u, int u3, int u2, int ufp, int hsl,
+ int sbu, int acc)
+{
+ return TCSS_CD_FIELD(USAGE, u) |
+ TCSS_CD_FIELD(USB3, u3) |
+ TCSS_CD_FIELD(USB2, u2) |
+ TCSS_CD_FIELD(UFP, ufp) |
+ TCSS_CD_FIELD(HSL, hsl) |
+ TCSS_CD_FIELD(SBU, sbu) |
+ TCSS_CD_FIELD(ACC, acc);
+}
+
+static uint32_t tcss_make_alt_mode_cmd_buf_0(int u, int u3, int m)
+{
+ return TCSS_ALT_FIELD(USAGE, u) |
+ TCSS_ALT_FIELD(USB3, u3) |
+ TCSS_ALT_FIELD(MODE, m);
+
+}
+
+static uint32_t tcss_make_alt_mode_cmd_buf_1(int p, int c, int ufp, int dp)
+{
+ return TCSS_ALT_FIELD(POLARITY, p) |
+ TCSS_ALT_FIELD(CABLE, c) |
+ TCSS_ALT_FIELD(UFP, ufp) |
+ TCSS_ALT_FIELD(DP_MODE, dp);
+}
+
+static uint32_t tcss_make_safe_mode_cmd(int u, int u3)
+{
+ return TCSS_CD_FIELD(USAGE, u) |
+ TCSS_CD_FIELD(USB3, u3);
+}
+
+
+static uint32_t tcss_make_hpd_mode_cmd(int u, int u3, int hpd_lvl, int hpd_irq)
+{
+ return TCSS_HPD_FIELD(USAGE, u) |
+ TCSS_HPD_FIELD(USB3, u3) |
+ TCSS_HPD_FIELD(LVL, hpd_lvl) |
+ TCSS_HPD_FIELD(IRQ, hpd_irq);
+
+}
+
+static int send_pmc_req(int cmd_type, const struct pmc_ipc_buffer *req,
+ struct pmc_ipc_buffer *res, uint32_t size)
+{
+
+ uint32_t cmd_reg;
+ uint32_t res_reg;
+ int tries = 2;
+ int r;
+
+ cmd_reg = pmc_make_ipc_cmd(PMC_IPC_USBC_CMD_ID, PMC_IPC_USBC_SUBCMD_ID,
+ size);
+
+ printk(BIOS_DEBUG, "Raw Buffer output 0 %08" PRIx32 "\n", req->buf[0]);
+ printk(BIOS_DEBUG, "Raw Buffer output 1 %08" PRIx32 "\n", req->buf[1]);
+
+ do {
+ r = pmc_send_ipc_cmd(cmd_reg, req, res);
+ if (r < 0) {
+ printk(BIOS_ERR, "pmc_send_ipc_cmd failed\n");
+ return -1;
+ }
+
+ res_reg = res->buf[0];
+ if (cmd_type == CONNECT_REQ) {
+ if (!TCSS_CONN_STATUS_HAS_FAILED(res_reg)) {
+ printk(BIOS_DEBUG, "pmc_send_ipc_cmd succeeded\n");
+ return 0;
+ }
+
+ if (TCSS_CONN_STATUS_IS_FATAL(res_reg)) {
+ printk(BIOS_ERR, "pmc_send_ipc_cmd status: fatal\n");
+ return -1;
+ }
+ } else {
+ if (!TCSS_STATUS_HAS_FAILED(res_reg)) {
+ printk(BIOS_DEBUG, "pmc_send_ipc_cmd succeeded\n");
+ return 0;
+ }
+
+ if (TCSS_STATUS_IS_FATAL(res_reg)) {
+ printk(BIOS_ERR, "pmc_send_ipc_cmd status: fatal\n");
+ return -1;
+ }
+ }
+ } while (--tries >= 0);
+
+ printk(BIOS_ERR, "pmc_send_ipc_cmd failed after retries\n");
+ return -1;
+}
+
+static int send_pmc_connect_request(int port, struct tcss_mux mux_data,
+ struct pmc_ipc_buffer *res)
+{
+ uint32_t cmd;
+ struct pmc_ipc_buffer req = { 0 };
+
+ cmd = tcss_make_conn_cmd(
+ PMC_IPC_TCSS_CONN_REQ_RES,
+ mux_data.usb3_port,
+ mux_data.usb2_port,
+ mux_data.ufp,
+ mux_data.polarity,
+ mux_data.polarity,
+ mux_data.acc);
+
+ req.buf[0] = cmd;
+
+ printk(BIOS_DEBUG, "port C%d CONN req: usage %d usb3 %d usb2 %d "
+ "ufp %d ori_hsl %d ori_sbu %d dbg_acc %d\n",
+ port,
+ GET_TCSS_CD_FIELD(USAGE, cmd),
+ GET_TCSS_CD_FIELD(USB3, cmd),
+ GET_TCSS_CD_FIELD(USB2, cmd),
+ GET_TCSS_CD_FIELD(UFP, cmd),
+ GET_TCSS_CD_FIELD(HSL, cmd),
+ GET_TCSS_CD_FIELD(SBU, cmd),
+ GET_TCSS_CD_FIELD(ACC, cmd));
+
+ return send_pmc_req(CONNECT_REQ, &req, res, PMC_IPC_CONN_REQ_SIZE);
+}
+
+static int send_pmc_safe_mode_request(int port, struct tcss_mux mux_data,
+ struct pmc_ipc_buffer *res)
+{
+ uint32_t cmd;
+ struct pmc_ipc_buffer req = { 0 };
+
+ cmd = tcss_make_safe_mode_cmd(PMC_IPC_TCSS_SAFE_MODE_REQ_RES, mux_data.usb3_port);
+
+ req.buf[0] = cmd;
+
+ printk(BIOS_DEBUG, "port C%d SAFE req: usage %d usb3 %d\n",
+ port,
+ GET_TCSS_CD_FIELD(USAGE, cmd),
+ GET_TCSS_CD_FIELD(USB3, cmd));
+
+ return send_pmc_req(SAFE_REQ, &req, res, PMC_IPC_SAFE_REQ_SIZE);
+}
+
+static int send_pmc_dp_hpd_request(int port, struct tcss_mux mux_data)
+{
+ struct pmc_ipc_buffer *res = NULL;
+ struct pmc_ipc_buffer req = { 0 };
+ uint32_t cmd;
+
+ cmd = tcss_make_hpd_mode_cmd(
+ PMC_IPC_TCSS_HPD_REQ_RES,
+ mux_data.usb3_port,
+ mux_data.hpd_lvl,
+ mux_data.hpd_irq);
+
+ req.buf[0] = cmd;
+
+ return send_pmc_req(HPD_REQ, &req, res, PMC_IPC_HPD_REQ_SIZE);
+
+}
+
+static int send_pmc_dp_mode_request(int port, struct tcss_mux mux_data,
+ struct pmc_ipc_buffer *res)
+{
+ uint32_t cmd;
+ uint8_t dp_mode;
+ int ret;
+
+ struct pmc_ipc_buffer req = { 0 };
+
+ cmd = tcss_make_alt_mode_cmd_buf_0(
+ PMC_IPC_TCSS_ALTMODE_REQ_RES,
+ mux_data.usb3_port,
+ PMC_IPC_DP_MODE);
+
+ req.buf[0] = cmd;
+
+ printk(BIOS_DEBUG, "port C%d ALT_1 req: usage %d usb3 %d dp_mode %d\n",
+ port,
+ GET_TCSS_ALT_FIELD(USAGE, cmd),
+ GET_TCSS_ALT_FIELD(USB3, cmd),
+ GET_TCSS_ALT_FIELD(MODE, cmd));
+
+ switch (mux_data.dp_mode) {
+ case MODE_DP_PIN_A:
+ dp_mode = 1;
+ break;
+ case MODE_DP_PIN_B:
+ dp_mode = 2;
+ break;
+ case MODE_DP_PIN_C:
+ dp_mode = 3;
+ break;
+ case MODE_DP_PIN_D:
+ dp_mode = 4;
+ break;
+ case MODE_DP_PIN_E:
+ dp_mode = 5;
+ break;
+ case MODE_DP_PIN_F:
+ dp_mode = 6;
+ break;
+ default:
+ dp_mode = 0;
+ break;
+ }
+
+ cmd = tcss_make_alt_mode_cmd_buf_1(
+ mux_data.polarity,
+ mux_data.cable,
+ 0, /* ufp is not supported in DP ALT Mode request */
+ dp_mode);
+
+ printk(BIOS_DEBUG, "port C%d ALT_2 req: polarity %d cable %d ufp %d "
+ "dp_mode %d\n",
+ port,
+ GET_TCSS_ALT_FIELD(POLARITY, cmd),
+ GET_TCSS_ALT_FIELD(CABLE, cmd),
+ GET_TCSS_ALT_FIELD(UFP, cmd),
+ GET_TCSS_ALT_FIELD(DP_MODE, cmd));
+
+ req.buf[1] = cmd;
+
+ ret = send_pmc_req(DP_REQ, &req, res, PMC_IPC_ALT_REQ_SIZE);
+ if (ret)
+ return ret;
+
+ send_pmc_dp_hpd_request(port, mux_data);
+ return 0;
+}
+
+void update_tcss_mux(int port, struct tcss_mux mux_data)
+{
+ struct pmc_ipc_buffer *rbuf = NULL;
+ int ret = 0;
+
+ /* check if mux has a DP device */
+ if (mux_data.dp) {
+ ret = send_pmc_connect_request(port, mux_data, rbuf);
+ if (ret) {
+ printk(BIOS_ERR, "Port %d connect request failed\n", port);
+ return;
+ }
+ ret = send_pmc_safe_mode_request(port, mux_data, rbuf);
+ if (ret) {
+ printk(BIOS_ERR, "Port %d safe mode request failed\n", port);
+ return;
+ }
+
+ ret = send_pmc_dp_mode_request(port, mux_data, rbuf);
+ }
+
+ if (ret)
+ printk(BIOS_ERR, "Port C%d mux set failed with error %d\n", port, ret);
+}
+
+__weak void mainboard_early_tcss_enable(void)
+{
+ /* to be overwritten by each mainboard that needs early tcss */
+}
diff --git a/src/soc/intel/tigerlake/fsp_params.c b/src/soc/intel/tigerlake/fsp_params.c
index 3427a61..6de098a 100644
--- a/src/soc/intel/tigerlake/fsp_params.c
+++ b/src/soc/intel/tigerlake/fsp_params.c
@@ -14,6 +14,7 @@
#include <intelblocks/xdci.h>
#include <intelpch/lockdown.h>
#include <security/vboot/vboot_common.h>
+#include <soc/early_tcss.h>
#include <soc/gpio_soc_defs.h>
#include <soc/intel/common/vbt.h>
#include <soc/pci_devs.h>
@@ -384,6 +385,11 @@
switch (phase_index) {
case 1:
/* TCSS specific initialization here */
+ printk(BIOS_DEBUG, "FSP MultiPhaseSiInit %s/%s called\n",
+ __FILE__, __func__);
+ if (CONFIG(EARLY_TCSS_DISPLAY) && (vboot_recovery_mode_enabled() ||
+ vboot_developer_mode_enabled()))
+ mainboard_early_tcss_enable();
break;
default:
break;
diff --git a/src/soc/intel/tigerlake/include/soc/early_tcss.h b/src/soc/intel/tigerlake/include/soc/early_tcss.h
new file mode 100644
index 0000000..c009e84
--- /dev/null
+++ b/src/soc/intel/tigerlake/include/soc/early_tcss.h
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* PMC IPC related offsets and commands */
+#define PMC_IPC_USBC_CMD_ID 0xA7
+#define PMC_IPC_USBC_SUBCMD_ID 0x0
+#define PMC_IPC_CMD 0x0
+#define PMC_IPC_TCSS_CONN_REQ_RES 0x0
+#define PMC_IPC_TCSS_SAFE_MODE_REQ_RES 0x2
+#define PMC_IPC_TCSS_ALTMODE_REQ_RES 0x3
+#define PMC_IPC_TCSS_HPD_REQ_RES 0x4
+#define PMC_IPC_CONN_REQ_SIZE 2
+#define PMC_IPC_ALT_REQ_SIZE 8
+#define PMC_IPC_SAFE_REQ_SIZE 1
+#define PMC_IPC_HPD_REQ_SIZE 2
+#define PMC_IPC_DP_MODE 1
+
+#define TCSS_CD_USAGE_SHIFT 0
+#define TCSS_CD_USAGE_MASK 0x0f
+#define TCSS_CD_USB3_SHIFT 4
+#define TCSS_CD_USB3_MASK 0x0f
+#define TCSS_CD_USB2_SHIFT 8
+#define TCSS_CD_USB2_MASK 0x0f
+#define TCSS_CD_UFP_SHIFT 12
+#define TCSS_CD_UFP_MASK 0x01
+#define TCSS_CD_HSL_SHIFT 13
+#define TCSS_CD_HSL_MASK 0x01
+#define TCSS_CD_SBU_SHIFT 14
+#define TCSS_CD_SBU_MASK 0x01
+#define TCSS_CD_ACC_SHIFT 15
+#define TCSS_CD_ACC_MASK 0x01
+#define TCSS_CD_FAILED_SHIFT 16
+#define TCSS_CD_FAILED_MASK 0x01
+#define TCSS_CD_FATAL_SHIFT 17
+#define TCSS_CD_FATAL_MASK 0x01
+
+#define TCSS_ALT_USAGE_SHIFT 0
+#define TCSS_ALT_USAGE_MASK 0x0f
+#define TCSS_ALT_USB3_SHIFT 4
+#define TCSS_ALT_USB3_MASK 0x0f
+#define TCSS_ALT_MODE_SHIFT 12
+#define TCSS_ALT_MODE_MASK 0x0f
+#define TCSS_ALT_POLARITY_SHIFT 1
+#define TCSS_ALT_POLARITY_MASK 0x01
+#define TCSS_ALT_CABLE_SHIFT 2
+#define TCSS_ALT_CABLE_MASK 0x01
+#define TCSS_ALT_UFP_SHIFT 3
+#define TCSS_ALT_UFP_MASK 0x01
+#define TCSS_ALT_DP_MODE_SHIFT 8
+#define TCSS_ALT_DP_MODE_MASK 0x0f
+#define TCSS_ALT_FAILED_SHIFT 8
+#define TCSS_ALT_FAILED_MASK 0x01
+#define TCSS_ALT_FATAL_SHIFT 9
+#define TCSS_ALT_FATAL_MASK 0x01
+
+#define TCSS_HPD_USAGE_SHIFT 0
+#define TCSS_HPD_USAGE_MASK 0x0f
+#define TCSS_HPD_USB3_SHIFT 4
+#define TCSS_HPD_USB3_MASK 0x0f
+#define TCSS_HPD_LVL_SHIFT 12
+#define TCSS_HPD_LVL_MASK 0x01
+#define TCSS_HPD_IRQ_SHIFT 13
+#define TCSS_HPD_IRQ_MASK 0x01
+
+#define TCSS_CD_FIELD(name, val) \
+ (((val) & TCSS_CD_##name##_MASK) << TCSS_CD_##name##_SHIFT)
+
+#define GET_TCSS_CD_FIELD(name, val) \
+ (((val) >> TCSS_CD_##name##_SHIFT) & TCSS_CD_##name##_MASK)
+
+
+#define TCSS_ALT_FIELD(name, val) \
+ (((val) & TCSS_ALT_##name##_MASK) << TCSS_ALT_##name##_SHIFT)
+
+#define TCSS_HPD_FIELD(name, val) \
+ (((val) & TCSS_HPD_##name##_MASK) << TCSS_HPD_##name##_SHIFT)
+
+#define GET_TCSS_ALT_FIELD(name, val) \
+ (((val) >> TCSS_ALT_##name##_SHIFT) & TCSS_ALT_##name##_MASK)
+
+#define TCSS_CONN_STATUS_HAS_FAILED(s) GET_TCSS_CD_FIELD(FAILED, s)
+#define TCSS_STATUS_HAS_FAILED(s) GET_TCSS_ALT_FIELD(FAILED, s)
+/* !fatal means retry */
+#define TCSS_CONN_STATUS_IS_FATAL(s) GET_TCSS_CD_FIELD(FATAL, s)
+#define TCSS_STATUS_IS_FATAL(s) GET_TCSS_ALT_FIELD(FATAL, s)
+
+#define USB_2_PORT_MASK 0x0f
+#define USB_3_PORT_MASK 0xf0
+
+/* TCSS connection modes for PMC */
+enum pmc_ipc_conn_mode {
+ PMC_IPC_TCSS_DISCONNECT_MODE,
+ PMC_IPC_TCSS_USB_MODE,
+ PMC_IPC_TCSS_ALTERNATE_MODE,
+ PMC_IPC_TCSS_SAFE_MODE,
+ PMC_IPC_TCSS_HPD_MODE,
+ PMC_IPC_TCSS_TOTAL_MODES,
+};
+
+enum pmc_ipc_command_type {
+ CONNECT_REQ,
+ SAFE_REQ,
+ DP_REQ,
+ HPD_REQ,
+};
+
+/* DP Mode pin definitions */
+#define MODE_DP_PIN_A BIT(0)
+#define MODE_DP_PIN_B BIT(1)
+#define MODE_DP_PIN_C BIT(2)
+#define MODE_DP_PIN_D BIT(3)
+#define MODE_DP_PIN_E BIT(4)
+#define MODE_DP_PIN_F BIT(5)
+
+/* struct to hold all tcss_mux related variables */
+struct tcss_mux {
+ bool dp; /* DP connected */
+ bool usb; /* USB connected */
+ bool cable; /* Activ/Passive Cable */
+ bool polarity; /* polarity of connected device */
+ bool hpd_lvl; /* HPD Level assert */
+ bool hpd_irq; /* HPD IRQ assert */
+ bool ufp;
+ bool acc;
+ uint8_t dp_mode; /* DP Operation Mode */
+ uint8_t usb3_port; /* USB2 Port Number */
+ uint8_t usb2_port; /* USB3 Port Number */
+};
+
+void update_tcss_mux(int port, struct tcss_mux mux_data);
+
+/*
+ * Weak mainboard method to setup any mux configuration needed for early TCSS operations.
+ * This function will need to obtain any mux data needed to forward to IOM/PMC and call
+ * the update_tcss_mux method which will call any PMC commands needed to connect the
+ * ports. Since the mux data may be stored differently by different mainboards this
+ * must be overridden by the mainboard with its specific mux data stored in a struct tcss_mux
+ * struct as defined above.
+ */
+void mainboard_early_tcss_enable(void);

To view, visit change 42079. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I58e66f21210d565fb8145d140d2fc7febecdd21a
Gerrit-Change-Number: 42079
Gerrit-PatchSet: 29
Gerrit-Owner: Brandon Breitenstein <brandon.breitenstein@intel.com>
Gerrit-Reviewer: Caveh Jalali <caveh@chromium.org>
Gerrit-Reviewer: Duncan Laurie <dlaurie@chromium.org>
Gerrit-Reviewer: Furquan Shaikh <furquan@google.com>
Gerrit-Reviewer: Martin Roth <martinroth@google.com>
Gerrit-Reviewer: Nick Vaccaro <nvaccaro@chromium.org>
Gerrit-Reviewer: Patrick Georgi <pgeorgi@google.com>
Gerrit-Reviewer: Patrick Rudolph <siro@das-labor.org>
Gerrit-Reviewer: Tim Wawrzynczak <twawrzynczak@chromium.org>
Gerrit-Reviewer: Tim Wawrzynczak <twawrzynczak@google.com>
Gerrit-Reviewer: build bot (Jenkins) <no-reply@coreboot.org>
Gerrit-CC: Paul Menzel <paulepanter@users.sourceforge.net>
Gerrit-CC: Tanu Malhotra <tanu.malhotra@intel.com>
Gerrit-MessageType: merged