diff options
author | Edward Hill <ecgh@chromium.org> | 2020-02-28 12:14:49 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-02-29 19:54:19 +0000 |
commit | 7345fbc90603f8d0d9161dc18e5579487b346593 (patch) | |
tree | 995d69d0be91684d43a5ff6ffe11ccb38b9b9e92 | |
parent | 0eb3e2a0c7e71e461b2ee0375652bb61b28c1cb7 (diff) | |
download | chrome-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.c | 344 | ||||
-rw-r--r-- | baseboard/zork/baseboard.h | 37 | ||||
-rw-r--r-- | baseboard/zork/variant_dalboz.c | 18 | ||||
-rw-r--r-- | baseboard/zork/variant_trembyle.c | 346 | ||||
-rw-r--r-- | board/dalboz/gpio.inc | 1 | ||||
-rw-r--r-- | driver/usb_mux/amd_fp5.c | 4 |
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); } |