summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Hill <ecgh@chromium.org>2020-02-28 12:14:49 -0700
committerCommit Bot <commit-bot@chromium.org>2020-02-29 19:54:19 +0000
commit7345fbc90603f8d0d9161dc18e5579487b346593 (patch)
tree995d69d0be91684d43a5ff6ffe11ccb38b9b9e92
parent0eb3e2a0c7e71e461b2ee0375652bb61b28c1cb7 (diff)
downloadchrome-ec-7345fbc90603f8d0d9161dc18e5579487b346593.tar.gz
zork: Split mux/retimer for trembyle/dalboz
BUG=b:150099043 b:150384642 BRANCH=none TEST=none Signed-off-by: Edward Hill <ecgh@chromium.org> Change-Id: Ica9eda3f9d6a1332319b5c7ba56c0881d05eeebd Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2079353 Reviewed-by: Denis Brockus <dbrockus@chromium.org>
-rw-r--r--baseboard/zork/baseboard.c344
-rw-r--r--baseboard/zork/baseboard.h37
-rw-r--r--baseboard/zork/variant_dalboz.c18
-rw-r--r--baseboard/zork/variant_trembyle.c346
-rw-r--r--board/dalboz/gpio.inc1
-rw-r--r--driver/usb_mux/amd_fp5.c4
6 files changed, 390 insertions, 360 deletions
diff --git a/baseboard/zork/baseboard.c b/baseboard/zork/baseboard.c
index 69a61681ff..d0917d5685 100644
--- a/baseboard/zork/baseboard.c
+++ b/baseboard/zork/baseboard.c
@@ -20,9 +20,6 @@
#include "driver/charger/isl9241.h"
#include "driver/ppc/aoz1380.h"
#include "driver/ppc/nx20p348x.h"
-#include "driver/retimer/pi3dpx1207.h"
-#include "driver/retimer/ps8802.h"
-#include "driver/retimer/ps8818.h"
#include "driver/tcpm/nct38xx.h"
#include "driver/temp_sensor/sb_tsi.h"
#include "driver/usb_mux/amd_fp5.h"
@@ -131,8 +128,8 @@ const struct i2c_port_t i2c_ports[] = {
.sda = GPIO_EC_I2C_POWER_SDA,
},
{
- .name = "mux",
- .port = I2C_PORT_USB_MUX,
+ .name = "ap_mux",
+ .port = I2C_PORT_USB_AP_MUX,
.kbps = 400,
.scl = GPIO_EC_I2C_USBC_AP_MUX_SCL,
.sda = GPIO_EC_I2C_USBC_AP_MUX_SDA,
@@ -431,343 +428,6 @@ void bc12_interrupt(enum gpio_signal signal)
}
}
-/*****************************************************************************
- * Custom Zork USB-C1 Retimer/MUX driver
- */
-
-/*
- * PS8802 set mux tuning.
- * Adds in board specific gain and DP lane count configuration
- */
-static int ps8802_mux_set(const struct usb_mux *me, mux_state_t mux_state)
-{
- int rv = EC_SUCCESS;
-
- /* Make sure the PS8802 is awake */
- rv = ps8802_i2c_wake(me);
- if (rv)
- return rv;
-
- /* USB specific config */
- if (mux_state & USB_PD_MUX_USB_ENABLED) {
- /* Boost the USB gain */
- rv = ps8802_i2c_field_update16(me,
- PS8802_REG_PAGE2,
- PS8802_REG2_USB_SSEQ_LEVEL,
- PS8802_USBEQ_LEVEL_UP_MASK,
- PS8802_USBEQ_LEVEL_UP_19DB);
- if (rv)
- return rv;
- }
-
- /* DP specific config */
- if (mux_state & USB_PD_MUX_DP_ENABLED) {
- /* Boost the DP gain */
- rv = ps8802_i2c_field_update8(me,
- PS8802_REG_PAGE2,
- PS8802_REG2_DPEQ_LEVEL,
- PS8802_DPEQ_LEVEL_UP_MASK,
- PS8802_DPEQ_LEVEL_UP_19DB);
- if (rv)
- return rv;
-
- /* Enable IN_HPD on the DB */
- ioex_set_level(IOEX_USB_C1_HPD_IN_DB, 1);
- } else {
- /* Disable IN_HPD on the DB */
- ioex_set_level(IOEX_USB_C1_HPD_IN_DB, 0);
- }
-
- return rv;
-}
-
-/*
- * PS8818 set mux tuning.
- * Adds in board specific gain and DP lane count configuration
- */
-static int ps8818_mux_set(const struct usb_mux *me, mux_state_t mux_state)
-{
- int rv = EC_SUCCESS;
-
- /* USB specific config */
- if (mux_state & USB_PD_MUX_USB_ENABLED) {
- /* Boost the USB gain */
- rv = ps8818_i2c_field_update8(me,
- PS8818_REG_PAGE1,
- PS8818_REG1_APTX1EQ_10G_LEVEL,
- PS8818_EQ_LEVEL_UP_MASK,
- PS8818_EQ_LEVEL_UP_19DB);
- if (rv)
- return rv;
-
- rv = ps8818_i2c_field_update8(me,
- PS8818_REG_PAGE1,
- PS8818_REG1_APTX2EQ_10G_LEVEL,
- PS8818_EQ_LEVEL_UP_MASK,
- PS8818_EQ_LEVEL_UP_19DB);
- if (rv)
- return rv;
-
- rv = ps8818_i2c_field_update8(me,
- PS8818_REG_PAGE1,
- PS8818_REG1_APTX1EQ_5G_LEVEL,
- PS8818_EQ_LEVEL_UP_MASK,
- PS8818_EQ_LEVEL_UP_19DB);
- if (rv)
- return rv;
-
- rv = ps8818_i2c_field_update8(me,
- PS8818_REG_PAGE1,
- PS8818_REG1_APTX2EQ_5G_LEVEL,
- PS8818_EQ_LEVEL_UP_MASK,
- PS8818_EQ_LEVEL_UP_19DB);
- if (rv)
- return rv;
- }
-
- /* DP specific config */
- if (mux_state & USB_PD_MUX_DP_ENABLED) {
- /* Boost the DP gain */
- rv = ps8818_i2c_field_update8(me,
- PS8818_REG_PAGE1,
- PS8818_REG1_DPEQ_LEVEL,
- PS8818_DPEQ_LEVEL_UP_MASK,
- PS8818_DPEQ_LEVEL_UP_19DB);
- if (rv)
- return rv;
-
- /* Enable IN_HPD on the DB */
- ioex_set_level(IOEX_USB_C1_HPD_IN_DB, 1);
- } else {
- /* Disable IN_HPD on the DB */
- ioex_set_level(IOEX_USB_C1_HPD_IN_DB, 0);
- }
-
- return rv;
-}
-
-/*
- * To support both OPT1 DB with PS8818 retimer, and OPT3 DB with PS8802
- * retimer, Try both, and remember the first one that succeeds.
- */
-const struct usb_mux usbc1_ps8802;
-const struct usb_mux usbc1_ps8818;
-struct usb_mux usbc1_amd_fp5_usb_mux;
-
-enum zork_c1_retimer zork_c1_retimer = C1_RETIMER_UNKNOWN;
-static int zork_c1_detect(const struct usb_mux *me, int err_if_power_off)
-{
- int rv;
-
- /*
- * Retimers are not powered in G3 so return success if setting mux to
- * none and error otherwise.
- */
- if (chipset_in_state(CHIPSET_STATE_HARD_OFF))
- return (err_if_power_off) ? EC_ERROR_NOT_POWERED
- : EC_SUCCESS;
-
- /*
- * Identifying a PS8818 is faster than the PS8802,
- * so do it first.
- */
- rv = ps8818_detect(&usbc1_ps8818);
- if (rv == EC_SUCCESS) {
- zork_c1_retimer = C1_RETIMER_PS8818;
- ccprints("C1 PS8818 detected");
-
- /* Main MUX is FP5, secondary MUX is PS8818 */
- memcpy(&usb_muxes[USBC_PORT_C1],
- &usbc1_amd_fp5_usb_mux,
- sizeof(struct usb_mux));
- usb_muxes[USBC_PORT_C1].next_mux = &usbc1_ps8818;
- return rv;
- }
-
- rv = ps8802_detect(&usbc1_ps8802);
- if (rv == EC_SUCCESS) {
- zork_c1_retimer = C1_RETIMER_PS8802;
- ccprints("C1 PS8802 detected");
-
- /* Main MUX is PS8802, secondary MUX is modified FP5 */
- memcpy(&usb_muxes[USBC_PORT_C1],
- &usbc1_ps8802,
- sizeof(struct usb_mux));
- usb_muxes[USBC_PORT_C1].next_mux = &usbc1_amd_fp5_usb_mux;
- usbc1_amd_fp5_usb_mux.flags = USB_MUX_FLAG_SET_WITHOUT_FLIP;
- }
-
- return rv;
-}
-
-/*
- * We start off not sure which configuration we are using. We set
- * the interface to be this special primary MUX driver in order to
- * determine the actual hardware and then we patch the jump tables
- * to go to the actual drivers instead.
- *
- * "me" will always point to usb_muxes[0]. If detection is made
- * on the real device, then detect will change the tables so the
- * content of me is the real driver configuration and will setup
- * next_mux appropriately. So all we have to do on detection is
- * perform the actual call for this entry and then let the generic
- * chain traverse mechanism in usb_mux.c do any following calls.
- */
-static int zork_c1_init_mux(const struct usb_mux *me)
-{
- int rv;
-
- /* Try to detect, but don't give an error if no power */
- rv = zork_c1_detect(me, 0);
- if (rv)
- return rv;
-
- /*
- * If we detected the hardware, then call the real routine.
- * We only do this one time, after that time we will go direct
- * and avoid this special driver.
- */
- if (zork_c1_retimer != C1_RETIMER_UNKNOWN)
- if (me->driver && me->driver->init)
- rv = me->driver->init(me);
-
- return rv;
-}
-
-static int zork_c1_set_mux(const struct usb_mux *me, mux_state_t mux_state)
-{
- int rv;
-
- /*
- * Try to detect, give an error if we are setting to a
- * MUX value that is not NONE when we have no power.
- */
- rv = zork_c1_detect(me, mux_state != USB_PD_MUX_NONE);
- if (rv)
- return rv;
-
- /*
- * If we detected the hardware, then call the real routine.
- * We only do this one time, after that time we will go direct
- * and avoid this special driver.
- */
- if (zork_c1_retimer != C1_RETIMER_UNKNOWN) {
- const struct usb_mux_driver *drv = me->driver;
-
- if (drv && drv->set) {
- mux_state_t state = mux_state;
-
- if (me->flags & USB_MUX_FLAG_SET_WITHOUT_FLIP)
- state &= ~USB_PD_MUX_POLARITY_INVERTED;
-
- /* Apply Driver generic settings */
- rv = drv->set(me, state);
- if (rv)
- return rv;
-
- /* Apply Board specific settings */
- if (me->board_set)
- rv = me->board_set(me, state);
- }
- }
-
- return rv;
-}
-
-static int zork_c1_get_mux(const struct usb_mux *me, mux_state_t *mux_state)
-{
- int rv;
-
- /* Try to detect the hardware */
- rv = zork_c1_detect(me, 1);
- if (rv) {
- /*
- * Not powered is MUX_NONE, so change the values
- * and make it a good status
- */
- if (rv == EC_ERROR_NOT_POWERED) {
- *mux_state = USB_PD_MUX_NONE;
- rv = EC_SUCCESS;
- }
- return rv;
- }
-
- /*
- * If we detected the hardware, then call the real routine.
- * We only do this one time, after that time we will go direct
- * and avoid this special driver.
- */
- if (zork_c1_retimer != C1_RETIMER_UNKNOWN)
- if (me->driver && me->driver->get)
- rv = me->driver->get(me, mux_state);
-
- return rv;
-}
-
-const struct pi3dpx1207_usb_control pi3dpx1207_controls[] = {
- [USBC_PORT_C0] = {
-#ifdef VARIANT_ZORK_TREMBYLE
- .enable_gpio = IOEX_USB_C0_DATA_EN,
- .dp_enable_gpio = GPIO_USB_C0_IN_HPD,
-#endif
- },
- [USBC_PORT_C1] = {
- },
-};
-BUILD_ASSERT(ARRAY_SIZE(pi3dpx1207_controls) == USBC_PORT_COUNT);
-
-const struct usb_mux_driver zork_c1_usb_mux_driver = {
- .init = zork_c1_init_mux,
- .set = zork_c1_set_mux,
- .get = zork_c1_get_mux,
-};
-
-const struct usb_mux usbc0_pi3dpx1207_usb_retimer = {
- .usb_port = USBC_PORT_C0,
- .i2c_port = I2C_PORT_TCPC0,
- .i2c_addr_flags = PI3DPX1207_I2C_ADDR_FLAGS,
- .driver = &pi3dpx1207_usb_retimer,
-};
-
-const struct usb_mux usbc1_ps8802 = {
- .usb_port = USBC_PORT_C1,
- .i2c_port = I2C_PORT_TCPC1,
- .i2c_addr_flags = PS8802_I2C_ADDR_FLAGS,
- .driver = &ps8802_usb_mux_driver,
- .board_set = &ps8802_mux_set,
-};
-const struct usb_mux usbc1_ps8818 = {
- .usb_port = USBC_PORT_C1,
- .i2c_port = I2C_PORT_TCPC1,
- .i2c_addr_flags = PS8818_I2C_ADDR_FLAGS,
- .driver = &ps8818_usb_retimer_driver,
- .board_set = &ps8818_mux_set,
-};
-struct usb_mux usbc1_amd_fp5_usb_mux = {
- .usb_port = USBC_PORT_C1,
- .driver = &amd_fp5_usb_mux_driver,
-};
-
-struct usb_mux usb_muxes[] = {
- [USBC_PORT_C0] = {
- .usb_port = USBC_PORT_C0,
- .driver = &amd_fp5_usb_mux_driver,
- .next_mux = &usbc0_pi3dpx1207_usb_retimer,
- },
- [USBC_PORT_C1] = {
- /*
- * This is the detection driver. Once the hardware
- * has been detected, the driver will change to the
- * detected hardware driver table.
- */
- .usb_port = USBC_PORT_C1,
- .i2c_port = I2C_PORT_TCPC1,
- .driver = &zork_c1_usb_mux_driver,
- }
-};
-BUILD_ASSERT(ARRAY_SIZE(usb_muxes) == USBC_PORT_COUNT);
-
-
struct ioexpander_config_t ioex_config[] = {
[USBC_PORT_C0] = {
.i2c_host_port = I2C_PORT_TCPC0,
diff --git a/baseboard/zork/baseboard.h b/baseboard/zork/baseboard.h
index 87e48a2fbe..e9c34c8318 100644
--- a/baseboard/zork/baseboard.h
+++ b/baseboard/zork/baseboard.h
@@ -133,7 +133,6 @@
#define CONFIG_CMD_PD_CONTROL
#define CONFIG_USB_CHARGER
-#define CONFIG_USB_MUX_RUNTIME_CONFIG
#define CONFIG_USB_POWER_DELIVERY
#define CONFIG_USB_PD_ALT_MODE
#define CONFIG_USB_PD_ALT_MODE_DFP
@@ -155,15 +154,21 @@
#define CONFIG_USBC_PPC_SBU
#define CONFIG_USBC_PPC_AOZ1380
#define CONFIG_USBC_PPC_NX20P3483
-#define CONFIG_USBC_RETIMER_PI3DPX1207
-#define CONFIG_USBC_RETIMER_PS8802
-#define CONFIG_USBC_RETIMER_PS8818
#define CONFIG_USBC_SS_MUX
#define CONFIG_USBC_SS_MUX_DFP_ONLY
#define CONFIG_USBC_VCONN
#define CONFIG_USBC_VCONN_SWAP
#define CONFIG_USB_MUX_AMD_FP5
+#if defined(VARIANT_ZORK_TREMBYLE)
+ #define CONFIG_USB_MUX_RUNTIME_CONFIG
+ #define CONFIG_USBC_RETIMER_PI3DPX1207
+ #define CONFIG_USBC_RETIMER_PS8802
+ #define CONFIG_USBC_RETIMER_PS8818
+#elif defined(VARIANT_ZORK_DALBOZ)
+ #define CONFIG_USB_MUX_PS8740
+#endif
+
/* USB-A config */
#define USB_PORT_COUNT 2
#define CONFIG_USB_PORT_POWER_SMART
@@ -210,7 +215,7 @@
#define I2C_PORT_USBA1 NPCX_I2C_PORT1_0
#define I2C_PORT_BATTERY NPCX_I2C_PORT2_0
#define I2C_PORT_CHARGER I2C_PORT_BATTERY
-#define I2C_PORT_USB_MUX NPCX_I2C_PORT3_0
+#define I2C_PORT_USB_AP_MUX NPCX_I2C_PORT3_0
#define I2C_PORT_THERMAL NPCX_I2C_PORT4_1
#define I2C_PORT_SENSOR NPCX_I2C_PORT5_0
#define I2C_PORT_ACCEL I2C_PORT_SENSOR
@@ -288,18 +293,18 @@ enum sensor_id {
SENSOR_COUNT,
};
-/* Private
- * Main intent is to indicate the retimer type attached
- * but is also needed to determine the HPD from the port
- */
-enum zork_c1_retimer {
- C1_RETIMER_UNKNOWN,
- C1_RETIMER_PS8802,
- C1_RETIMER_PS8818,
-};
-extern enum zork_c1_retimer zork_c1_retimer;
-
#if defined(VARIANT_ZORK_TREMBYLE)
+ /* Private
+ * Main intent is to indicate the retimer type attached
+ * but is also needed to determine the HPD from the port
+ */
+ enum zork_c1_retimer {
+ C1_RETIMER_UNKNOWN,
+ C1_RETIMER_PS8802,
+ C1_RETIMER_PS8818,
+ };
+ extern enum zork_c1_retimer zork_c1_retimer;
+
#define PORT_TO_HPD(port) ((port == 0) \
? GPIO_USB_C0_HPD \
: (zork_c1_retimer == C1_RETIMER_PS8802) \
diff --git a/baseboard/zork/variant_dalboz.c b/baseboard/zork/variant_dalboz.c
index e3d1a7417d..1d1a403203 100644
--- a/baseboard/zork/variant_dalboz.c
+++ b/baseboard/zork/variant_dalboz.c
@@ -5,10 +5,12 @@
#include "common.h"
#include "console.h"
+#include "driver/usb_mux/amd_fp5.h"
#include "gpio.h"
#include "hooks.h"
#include "i2c.h"
#include "ioexpander.h"
+#include "usb_mux.h"
static void usba_retimer_on(void)
{
@@ -21,3 +23,19 @@ static void usba_retimer_off(void)
ioex_set_level(IOEX_USB_A1_RETIMER_EN, 0);
}
DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, usba_retimer_off, HOOK_PRIO_DEFAULT);
+
+const struct usb_mux usb_muxes[] = {
+ [USBC_PORT_C0] = {
+ .usb_port = USBC_PORT_C0,
+ .i2c_port = I2C_PORT_USB_AP_MUX,
+ .i2c_addr_flags = AMD_FP5_MUX_I2C_ADDR_FLAGS,
+ .driver = &amd_fp5_usb_mux_driver,
+ },
+ [USBC_PORT_C1] = {
+ .usb_port = USBC_PORT_C1,
+ .i2c_port = I2C_PORT_TCPC1,
+ .i2c_addr_flags = 0x10,
+ .driver = &ps874x_usb_mux_driver,
+ }
+};
+BUILD_ASSERT(ARRAY_SIZE(usb_muxes) == USBC_PORT_COUNT);
diff --git a/baseboard/zork/variant_trembyle.c b/baseboard/zork/variant_trembyle.c
index 2b6e520136..1df084e5df 100644
--- a/baseboard/zork/variant_trembyle.c
+++ b/baseboard/zork/variant_trembyle.c
@@ -3,9 +3,14 @@
* found in the LICENSE file.
*/
+#include "chipset.h"
#include "common.h"
#include "console.h"
+#include "driver/retimer/pi3dpx1207.h"
+#include "driver/retimer/ps8802.h"
#include "driver/retimer/ps8811.h"
+#include "driver/retimer/ps8818.h"
+#include "driver/usb_mux/amd_fp5.h"
#include "fan.h"
#include "fan_chip.h"
#include "gpio.h"
@@ -13,6 +18,7 @@
#include "i2c.h"
#include "ioexpander.h"
#include "timer.h"
+#include "usb_mux.h"
#define CPRINTSUSB(format, args...) cprints(CC_USBCHARGE, format, ## args)
#define CPRINTFUSB(format, args...) cprintf(CC_USBCHARGE, format, ## args)
@@ -150,3 +156,343 @@ void mst_hpd_interrupt(enum ioex_signal signal)
/* Debounce for 2 msec. */
hook_call_deferred(&mst_hpd_handler_data, (2 * MSEC));
}
+
+/*****************************************************************************
+ * Custom Zork USB-C1 Retimer/MUX driver
+ */
+
+/*
+ * PS8802 set mux tuning.
+ * Adds in board specific gain and DP lane count configuration
+ */
+static int ps8802_mux_set(const struct usb_mux *me, mux_state_t mux_state)
+{
+ int rv = EC_SUCCESS;
+
+ /* Make sure the PS8802 is awake */
+ rv = ps8802_i2c_wake(me);
+ if (rv)
+ return rv;
+
+ /* USB specific config */
+ if (mux_state & USB_PD_MUX_USB_ENABLED) {
+ /* Boost the USB gain */
+ rv = ps8802_i2c_field_update16(me,
+ PS8802_REG_PAGE2,
+ PS8802_REG2_USB_SSEQ_LEVEL,
+ PS8802_USBEQ_LEVEL_UP_MASK,
+ PS8802_USBEQ_LEVEL_UP_19DB);
+ if (rv)
+ return rv;
+ }
+
+ /* DP specific config */
+ if (mux_state & USB_PD_MUX_DP_ENABLED) {
+ /* Boost the DP gain */
+ rv = ps8802_i2c_field_update8(me,
+ PS8802_REG_PAGE2,
+ PS8802_REG2_DPEQ_LEVEL,
+ PS8802_DPEQ_LEVEL_UP_MASK,
+ PS8802_DPEQ_LEVEL_UP_19DB);
+ if (rv)
+ return rv;
+
+ /* Enable IN_HPD on the DB */
+ ioex_set_level(IOEX_USB_C1_HPD_IN_DB, 1);
+ } else {
+ /* Disable IN_HPD on the DB */
+ ioex_set_level(IOEX_USB_C1_HPD_IN_DB, 0);
+ }
+
+ return rv;
+}
+
+/*
+ * PS8818 set mux tuning.
+ * Adds in board specific gain and DP lane count configuration
+ */
+static int ps8818_mux_set(const struct usb_mux *me, mux_state_t mux_state)
+{
+ int rv = EC_SUCCESS;
+
+ /* USB specific config */
+ if (mux_state & USB_PD_MUX_USB_ENABLED) {
+ /* Boost the USB gain */
+ rv = ps8818_i2c_field_update8(me,
+ PS8818_REG_PAGE1,
+ PS8818_REG1_APTX1EQ_10G_LEVEL,
+ PS8818_EQ_LEVEL_UP_MASK,
+ PS8818_EQ_LEVEL_UP_19DB);
+ if (rv)
+ return rv;
+
+ rv = ps8818_i2c_field_update8(me,
+ PS8818_REG_PAGE1,
+ PS8818_REG1_APTX2EQ_10G_LEVEL,
+ PS8818_EQ_LEVEL_UP_MASK,
+ PS8818_EQ_LEVEL_UP_19DB);
+ if (rv)
+ return rv;
+
+ rv = ps8818_i2c_field_update8(me,
+ PS8818_REG_PAGE1,
+ PS8818_REG1_APTX1EQ_5G_LEVEL,
+ PS8818_EQ_LEVEL_UP_MASK,
+ PS8818_EQ_LEVEL_UP_19DB);
+ if (rv)
+ return rv;
+
+ rv = ps8818_i2c_field_update8(me,
+ PS8818_REG_PAGE1,
+ PS8818_REG1_APTX2EQ_5G_LEVEL,
+ PS8818_EQ_LEVEL_UP_MASK,
+ PS8818_EQ_LEVEL_UP_19DB);
+ if (rv)
+ return rv;
+ }
+
+ /* DP specific config */
+ if (mux_state & USB_PD_MUX_DP_ENABLED) {
+ /* Boost the DP gain */
+ rv = ps8818_i2c_field_update8(me,
+ PS8818_REG_PAGE1,
+ PS8818_REG1_DPEQ_LEVEL,
+ PS8818_DPEQ_LEVEL_UP_MASK,
+ PS8818_DPEQ_LEVEL_UP_19DB);
+ if (rv)
+ return rv;
+
+ /* Enable IN_HPD on the DB */
+ ioex_set_level(IOEX_USB_C1_HPD_IN_DB, 1);
+ } else {
+ /* Disable IN_HPD on the DB */
+ ioex_set_level(IOEX_USB_C1_HPD_IN_DB, 0);
+ }
+
+ return rv;
+}
+
+/*
+ * To support both OPT1 DB with PS8818 retimer, and OPT3 DB with PS8802
+ * retimer, Try both, and remember the first one that succeeds.
+ */
+const struct usb_mux usbc1_ps8802;
+const struct usb_mux usbc1_ps8818;
+struct usb_mux usbc1_amd_fp5_usb_mux;
+
+enum zork_c1_retimer zork_c1_retimer = C1_RETIMER_UNKNOWN;
+static int zork_c1_detect(const struct usb_mux *me, int err_if_power_off)
+{
+ int rv;
+
+ /*
+ * Retimers are not powered in G3 so return success if setting mux to
+ * none and error otherwise.
+ */
+ if (chipset_in_state(CHIPSET_STATE_HARD_OFF))
+ return (err_if_power_off) ? EC_ERROR_NOT_POWERED
+ : EC_SUCCESS;
+
+ /*
+ * Identifying a PS8818 is faster than the PS8802,
+ * so do it first.
+ */
+ rv = ps8818_detect(&usbc1_ps8818);
+ if (rv == EC_SUCCESS) {
+ zork_c1_retimer = C1_RETIMER_PS8818;
+ ccprints("C1 PS8818 detected");
+
+ /* Main MUX is FP5, secondary MUX is PS8818 */
+ memcpy(&usb_muxes[USBC_PORT_C1],
+ &usbc1_amd_fp5_usb_mux,
+ sizeof(struct usb_mux));
+ usb_muxes[USBC_PORT_C1].next_mux = &usbc1_ps8818;
+ return rv;
+ }
+
+ rv = ps8802_detect(&usbc1_ps8802);
+ if (rv == EC_SUCCESS) {
+ zork_c1_retimer = C1_RETIMER_PS8802;
+ ccprints("C1 PS8802 detected");
+
+ /* Main MUX is PS8802, secondary MUX is modified FP5 */
+ memcpy(&usb_muxes[USBC_PORT_C1],
+ &usbc1_ps8802,
+ sizeof(struct usb_mux));
+ usb_muxes[USBC_PORT_C1].next_mux = &usbc1_amd_fp5_usb_mux;
+ usbc1_amd_fp5_usb_mux.flags = USB_MUX_FLAG_SET_WITHOUT_FLIP;
+ }
+
+ return rv;
+}
+
+/*
+ * We start off not sure which configuration we are using. We set
+ * the interface to be this special primary MUX driver in order to
+ * determine the actual hardware and then we patch the jump tables
+ * to go to the actual drivers instead.
+ *
+ * "me" will always point to usb_muxes[0]. If detection is made
+ * on the real device, then detect will change the tables so the
+ * content of me is the real driver configuration and will setup
+ * next_mux appropriately. So all we have to do on detection is
+ * perform the actual call for this entry and then let the generic
+ * chain traverse mechanism in usb_mux.c do any following calls.
+ */
+static int zork_c1_init_mux(const struct usb_mux *me)
+{
+ int rv;
+
+ /* Try to detect, but don't give an error if no power */
+ rv = zork_c1_detect(me, 0);
+ if (rv)
+ return rv;
+
+ /*
+ * If we detected the hardware, then call the real routine.
+ * We only do this one time, after that time we will go direct
+ * and avoid this special driver.
+ */
+ if (zork_c1_retimer != C1_RETIMER_UNKNOWN)
+ if (me->driver && me->driver->init)
+ rv = me->driver->init(me);
+
+ return rv;
+}
+
+static int zork_c1_set_mux(const struct usb_mux *me, mux_state_t mux_state)
+{
+ int rv;
+
+ /*
+ * Try to detect, give an error if we are setting to a
+ * MUX value that is not NONE when we have no power.
+ */
+ rv = zork_c1_detect(me, mux_state != USB_PD_MUX_NONE);
+ if (rv)
+ return rv;
+
+ /*
+ * If we detected the hardware, then call the real routine.
+ * We only do this one time, after that time we will go direct
+ * and avoid this special driver.
+ */
+ if (zork_c1_retimer != C1_RETIMER_UNKNOWN) {
+ const struct usb_mux_driver *drv = me->driver;
+
+ if (drv && drv->set) {
+ mux_state_t state = mux_state;
+
+ if (me->flags & USB_MUX_FLAG_SET_WITHOUT_FLIP)
+ state &= ~USB_PD_MUX_POLARITY_INVERTED;
+
+ /* Apply Driver generic settings */
+ rv = drv->set(me, state);
+ if (rv)
+ return rv;
+
+ /* Apply Board specific settings */
+ if (me->board_set)
+ rv = me->board_set(me, state);
+ }
+ }
+
+ return rv;
+}
+
+static int zork_c1_get_mux(const struct usb_mux *me, mux_state_t *mux_state)
+{
+ int rv;
+
+ /* Try to detect the hardware */
+ rv = zork_c1_detect(me, 1);
+ if (rv) {
+ /*
+ * Not powered is MUX_NONE, so change the values
+ * and make it a good status
+ */
+ if (rv == EC_ERROR_NOT_POWERED) {
+ *mux_state = USB_PD_MUX_NONE;
+ rv = EC_SUCCESS;
+ }
+ return rv;
+ }
+
+ /*
+ * If we detected the hardware, then call the real routine.
+ * We only do this one time, after that time we will go direct
+ * and avoid this special driver.
+ */
+ if (zork_c1_retimer != C1_RETIMER_UNKNOWN)
+ if (me->driver && me->driver->get)
+ rv = me->driver->get(me, mux_state);
+
+ return rv;
+}
+
+const struct pi3dpx1207_usb_control pi3dpx1207_controls[] = {
+ [USBC_PORT_C0] = {
+#ifdef VARIANT_ZORK_TREMBYLE
+ .enable_gpio = IOEX_USB_C0_DATA_EN,
+ .dp_enable_gpio = GPIO_USB_C0_IN_HPD,
+#endif
+ },
+ [USBC_PORT_C1] = {
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(pi3dpx1207_controls) == USBC_PORT_COUNT);
+
+const struct usb_mux_driver zork_c1_usb_mux_driver = {
+ .init = zork_c1_init_mux,
+ .set = zork_c1_set_mux,
+ .get = zork_c1_get_mux,
+};
+
+const struct usb_mux usbc0_pi3dpx1207_usb_retimer = {
+ .usb_port = USBC_PORT_C0,
+ .i2c_port = I2C_PORT_TCPC0,
+ .i2c_addr_flags = PI3DPX1207_I2C_ADDR_FLAGS,
+ .driver = &pi3dpx1207_usb_retimer,
+};
+
+const struct usb_mux usbc1_ps8802 = {
+ .usb_port = USBC_PORT_C1,
+ .i2c_port = I2C_PORT_TCPC1,
+ .i2c_addr_flags = PS8802_I2C_ADDR_FLAGS,
+ .driver = &ps8802_usb_mux_driver,
+ .board_set = &ps8802_mux_set,
+};
+const struct usb_mux usbc1_ps8818 = {
+ .usb_port = USBC_PORT_C1,
+ .i2c_port = I2C_PORT_TCPC1,
+ .i2c_addr_flags = PS8818_I2C_ADDR_FLAGS,
+ .driver = &ps8818_usb_retimer_driver,
+ .board_set = &ps8818_mux_set,
+};
+struct usb_mux usbc1_amd_fp5_usb_mux = {
+ .usb_port = USBC_PORT_C1,
+ .i2c_port = I2C_PORT_USB_AP_MUX,
+ .i2c_addr_flags = AMD_FP5_MUX_I2C_ADDR_FLAGS,
+ .driver = &amd_fp5_usb_mux_driver,
+};
+
+struct usb_mux usb_muxes[] = {
+ [USBC_PORT_C0] = {
+ .usb_port = USBC_PORT_C0,
+ .i2c_port = I2C_PORT_USB_AP_MUX,
+ .i2c_addr_flags = AMD_FP5_MUX_I2C_ADDR_FLAGS,
+ .driver = &amd_fp5_usb_mux_driver,
+ .next_mux = &usbc0_pi3dpx1207_usb_retimer,
+ },
+ [USBC_PORT_C1] = {
+ /*
+ * This is the detection driver. Once the hardware
+ * has been detected, the driver will change to the
+ * detected hardware driver table.
+ */
+ .usb_port = USBC_PORT_C1,
+ .i2c_port = I2C_PORT_TCPC1,
+ .driver = &zork_c1_usb_mux_driver,
+ }
+};
+BUILD_ASSERT(ARRAY_SIZE(usb_muxes) == USBC_PORT_COUNT);
diff --git a/board/dalboz/gpio.inc b/board/dalboz/gpio.inc
index 5916fc2976..b2472d09a0 100644
--- a/board/dalboz/gpio.inc
+++ b/board/dalboz/gpio.inc
@@ -60,6 +60,7 @@ IOEX(USB_C0_SBU_FAULT_ODL, EXPIN(USBC_PORT_C0, 1, 2), GPIO_INPUT) /* C0 SBU Fau
IOEX(KB_BL_EN, EXPIN(USBC_PORT_C0, 1, 3), GPIO_OUT_LOW) /* KB Backlight Enable */
IOEX(EN_USB_A0_5V, EXPIN(USBC_PORT_C0, 1, 5), GPIO_OUT_LOW) /* A0 5V Source Enable */
IOEX(USB_A0_CHARGE_EN_L, EXPIN(USBC_PORT_C0, 1, 6), GPIO_OUT_HIGH) /* A0 5V High Current Enable */
+IOEX(USB_C0_SBU_FLIP, EXPIN(USBC_PORT_C0, 1, 7), GPIO_OUT_LOW) /* C0 SBU Flip */
IOEX(USB_A1_RETIMER_EN, EXPIN(USBC_PORT_C1, 0, 0), GPIO_OUT_LOW) /* A1 Retimer Enable */
IOEX(USB_C1_HPD_IN_DB, EXPIN(USBC_PORT_C1, 0, 2), GPIO_OUT_LOW) /* C1 HPD */
diff --git a/driver/usb_mux/amd_fp5.c b/driver/usb_mux/amd_fp5.c
index 1f61f7c765..ecba47851f 100644
--- a/driver/usb_mux/amd_fp5.c
+++ b/driver/usb_mux/amd_fp5.c
@@ -16,7 +16,7 @@ static inline int amd_fp5_mux_read(const struct usb_mux *me, uint8_t *val)
uint8_t buf[3] = { 0 };
int rv;
- rv = i2c_xfer(I2C_PORT_USB_MUX, AMD_FP5_MUX_I2C_ADDR_FLAGS,
+ rv = i2c_xfer(me->i2c_port, me->i2c_addr_flags,
NULL, 0, buf, 3);
if (rv)
return rv;
@@ -28,7 +28,7 @@ static inline int amd_fp5_mux_read(const struct usb_mux *me, uint8_t *val)
static inline int amd_fp5_mux_write(const struct usb_mux *me, uint8_t val)
{
- return i2c_write8(I2C_PORT_USB_MUX, AMD_FP5_MUX_I2C_ADDR_FLAGS,
+ return i2c_write8(me->i2c_port, me->i2c_addr_flags,
me->usb_port, val);
}