diff options
author | Caveh Jalali <caveh@chromium.org> | 2021-02-16 18:39:17 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-03-10 20:00:23 +0000 |
commit | 632d1e77e33f7f07f1e48585e03eb35525166210 (patch) | |
tree | 30b86bcb7ad44860b10aeea23487f0d2d0af90e9 | |
parent | ee972e4f32d3b19ed9a6104459ab420c4e8782ec (diff) | |
download | chrome-ec-632d1e77e33f7f07f1e48585e03eb35525166210.tar.gz |
brya: Add USB-C support
This adds the USB-C support subsystem code.
BRANCH=none
BUG=b:173575131
TEST=with reset of CQ-Depend patches, brya boots to AP
Cq-Depend: chromium:2700317
Change-Id: I9181b13c7ef4bb2f6bb93bd0d16369848779c198
Signed-off-by: Caveh Jalali <caveh@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2700315
Reviewed-by: Furquan Shaikh <furquan@chromium.org>
Commit-Queue: Furquan Shaikh <furquan@chromium.org>
Tested-by: Furquan Shaikh <furquan@chromium.org>
-rw-r--r-- | board/brya/board.c | 5 | ||||
-rw-r--r-- | board/brya/board.h | 23 | ||||
-rw-r--r-- | board/brya/ec.tasklist | 13 | ||||
-rw-r--r-- | board/brya/i2c.c | 6 | ||||
-rw-r--r-- | board/brya/usbc_config.c | 353 | ||||
-rw-r--r-- | board/brya/usbc_config.h | 22 |
6 files changed, 408 insertions, 14 deletions
diff --git a/board/brya/board.c b/board/brya/board.c index 720437bfe8..17242a73d6 100644 --- a/board/brya/board.c +++ b/board/brya/board.c @@ -30,3 +30,8 @@ BUILD_ASSERT(ARRAY_SIZE(usb_port_enable) == USB_PORT_COUNT); const union brya_cbi_fw_config fw_config_defaults = { .usb_db = DB_USB3_PS8815, }; + +__override void board_cbi_init(void) +{ + config_usb_db_type(); +} diff --git a/board/brya/board.h b/board/brya/board.h index b96ef610f8..486e1ab2cc 100644 --- a/board/brya/board.h +++ b/board/brya/board.h @@ -28,6 +28,9 @@ #define CONFIG_USB_PORT_POWER_DUMB /* USB Type C and USB PD defines */ + +#define CONFIG_IO_EXPANDER +#define CONFIG_IO_EXPANDER_NCT38XX #define CONFIG_IO_EXPANDER_PORT_COUNT 2 #define GPIO_AC_PRESENT GPIO_ACOK_EC_OD @@ -62,22 +65,17 @@ #define I2C_PORT_SENSOR NPCX_I2C_PORT0_0 -#define I2C_PORT_TCPC0_2 NPCX_I2C_PORT1_0 -#define I2C_PORT_USB_C0_TCPC NPCX_I2C_PORT1_0 +#define I2C_PORT_USB_C0_C2_TCPC NPCX_I2C_PORT1_0 #define I2C_PORT_USB_C1_TCPC NPCX_I2C_PORT4_1 -#define I2C_PORT_USB_C2_TCPC NPCX_I2C_PORT1_0 /* dual TCPC with C0 */ -#define I2C_PORT_USB_C0_PPC NPCX_I2C_PORT2_0 +#define I2C_PORT_USB_C0_C2_PPC NPCX_I2C_PORT2_0 #define I2C_PORT_USB_C1_PPC NPCX_I2C_PORT6_1 -#define I2C_PORT_USB_C2_PPC NPCX_I2C_PORT2_0 -#define I2C_PORT_USB_C0_BC12 NPCX_I2C_PORT2_0 +#define I2C_PORT_USB_C0_C2_BC12 NPCX_I2C_PORT2_0 #define I2C_PORT_USB_C1_BC12 NPCX_I2C_PORT6_1 -#define I2C_PORT_USB_C2_BC12 NPCX_I2C_PORT2_0 -#define I2C_PORT_USB_C0_MUX NPCX_I2C_PORT3_0 +#define I2C_PORT_USB_C0_C2_MUX NPCX_I2C_PORT3_0 #define I2C_PORT_USB_C1_MUX NPCX_I2C_PORT6_1 -#define I2C_PORT_USB_C2_MUX NPCX_I2C_PORT3_0 #define I2C_PORT_BATTERY NPCX_I2C_PORT5_0 #define I2C_PORT_CHARGER NPCX_I2C_PORT7_0 @@ -85,6 +83,12 @@ #define I2C_ADDR_EEPROM_FLAGS 0x50 +/* + * see b/174768555#comment22 + */ +#define USBC_PORT_C0_BB_RETIMER_I2C_ADDR 0x56 +#define USBC_PORT_C2_BB_RETIMER_I2C_ADDR 0x57 + /* Thermal features */ #define CONFIG_THERMISTOR #define CONFIG_TEMP_SENSOR @@ -100,6 +104,7 @@ #include "gpio_signal.h" /* needed by registers.h */ #include "registers.h" +#include "usbc_config.h" enum adc_channel { ADC_TEMP_SENSOR_1_DDR_SOC, diff --git a/board/brya/ec.tasklist b/board/brya/ec.tasklist index 4065a63bde..dda8729741 100644 --- a/board/brya/ec.tasklist +++ b/board/brya/ec.tasklist @@ -5,13 +5,24 @@ /* * See CONFIG_TASK_LIST in config.h for details. + * + * USB_CHG_Px tasks must be contiguous (see USB_CHG_PORT_TO_TASK_ID(x)). + * PD_Cx tasks must be contiguous (see PD_PORT_TO_TASK_ID(x)) */ #define CONFIG_TASK_LIST \ TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \ + TASK_ALWAYS(USB_CHG_P0, usb_charger_task, 0, TASK_STACK_SIZE) \ + TASK_ALWAYS(USB_CHG_P1, usb_charger_task, 0, TASK_STACK_SIZE) \ + TASK_ALWAYS(USB_CHG_P2, usb_charger_task, 0, TASK_STACK_SIZE) \ TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, TASK_STACK_SIZE) \ TASK_NOTEST(CHIPSET, chipset_task, NULL, LARGER_TASK_STACK_SIZE) \ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, LARGER_TASK_STACK_SIZE) \ TASK_ALWAYS(CONSOLE, console_task, NULL, VENTI_TASK_STACK_SIZE) \ TASK_ALWAYS(POWERBTN, power_button_task, NULL, LARGER_TASK_STACK_SIZE) \ - TASK_NOTEST(KEYSCAN, keyboard_scan_task, NULL, TASK_STACK_SIZE) + TASK_NOTEST(KEYSCAN, keyboard_scan_task, NULL, TASK_STACK_SIZE) \ + TASK_ALWAYS(PD_C0, pd_task, NULL, VENTI_TASK_STACK_SIZE) \ + TASK_ALWAYS(PD_C1, pd_task, NULL, VENTI_TASK_STACK_SIZE) \ + TASK_ALWAYS(PD_C2, pd_task, NULL, VENTI_TASK_STACK_SIZE) \ + TASK_ALWAYS(PD_INT_C0, pd_shared_alert_task, (BIT(2) | BIT(0)), TASK_STACK_SIZE) \ + TASK_ALWAYS(PD_INT_C1, pd_interrupt_handler_task, 1, TASK_STACK_SIZE) diff --git a/board/brya/i2c.c b/board/brya/i2c.c index 924d097a80..4358e80ff6 100644 --- a/board/brya/i2c.c +++ b/board/brya/i2c.c @@ -20,7 +20,7 @@ const struct i2c_port_t i2c_ports[] = { { /* I2C1 */ .name = "tcpc0,2", - .port = I2C_PORT_TCPC0_2, + .port = I2C_PORT_USB_C0_C2_TCPC, .kbps = 1000, .scl = GPIO_EC_I2C_USB_C0_C2_TCPC_SCL, .sda = GPIO_EC_I2C_USB_C0_C2_TCPC_SDA, @@ -28,7 +28,7 @@ const struct i2c_port_t i2c_ports[] = { { /* I2C2 */ .name = "ppc0,2", - .port = I2C_PORT_USB_C0_PPC, + .port = I2C_PORT_USB_C0_C2_PPC, .kbps = 1000, .scl = GPIO_EC_I2C_USB_C0_C2_PPC_BC_SCL, .sda = GPIO_EC_I2C_USB_C0_C2_PPC_BC_SDA, @@ -36,7 +36,7 @@ const struct i2c_port_t i2c_ports[] = { { /* I2C3 */ .name = "retimer0,2", - .port = I2C_PORT_USB_C0_MUX, + .port = I2C_PORT_USB_C0_C2_MUX, .kbps = 1000, .scl = GPIO_EC_I2C_USB_C0_C2_RT_SCL, .sda = GPIO_EC_I2C_USB_C0_C2_RT_SDA, diff --git a/board/brya/usbc_config.c b/board/brya/usbc_config.c index 6f08711bcb..3e7347bcc0 100644 --- a/board/brya/usbc_config.c +++ b/board/brya/usbc_config.c @@ -5,22 +5,373 @@ #include "common.h" +#include "cbi_ec_fw_config.h" +#include "driver/bc12/pi3usb9201_public.h" +#include "driver/ppc/nx20p348x.h" +#include "driver/ppc/syv682x_public.h" +#include "driver/retimer/bb_retimer_public.h" +#include "driver/tcpm/nct38xx.h" +#include "driver/tcpm/ps8xxx_public.h" +#include "driver/tcpm/tcpci.h" +#include "hooks.h" +#include "ioexpander.h" +#include "system.h" +#include "timer.h" +#include "usbc_config.h" +#include "usbc_ppc.h" +#include "usb_mux.h" +#include "usb_pd_tcpm.h" + +#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) +#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) + +/* USBC TCPC configuration */ +const struct tcpc_config_t tcpc_config[] = { + [USBC_PORT_C0] = { + .bus_type = EC_BUS_TYPE_I2C, + .i2c_info = { + .port = I2C_PORT_USB_C0_C2_TCPC, + .addr_flags = NCT38XX_I2C_ADDR1_1_FLAGS, + }, + .drv = &nct38xx_tcpm_drv, + .flags = TCPC_FLAGS_TCPCI_REV2_0, + }, + [USBC_PORT_C1] = { + .bus_type = EC_BUS_TYPE_I2C, + .i2c_info = { + .port = I2C_PORT_USB_C1_TCPC, + .addr_flags = PS8751_I2C_ADDR1_FLAGS, + }, + .drv = &ps8xxx_tcpm_drv, + .flags = TCPC_FLAGS_TCPCI_REV2_0 | + TCPC_FLAGS_TCPCI_REV2_0_NO_VSAFE0V, + }, + [USBC_PORT_C2] = { + .bus_type = EC_BUS_TYPE_I2C, + .i2c_info = { + .port = I2C_PORT_USB_C0_C2_TCPC, + .addr_flags = NCT38XX_I2C_ADDR2_1_FLAGS, + }, + .drv = &nct38xx_tcpm_drv, + .flags = TCPC_FLAGS_TCPCI_REV2_0, + }, +}; +BUILD_ASSERT(ARRAY_SIZE(tcpc_config) == USBC_PORT_COUNT); +BUILD_ASSERT(CONFIG_USB_PD_PORT_MAX_COUNT == USBC_PORT_COUNT); + +/* USBC PPC configuration */ +struct ppc_config_t ppc_chips[] = { + [USBC_PORT_C0] = { + .i2c_port = I2C_PORT_USB_C0_C2_PPC, + .i2c_addr_flags = SYV682X_ADDR0_FLAGS, + .drv = &syv682x_drv, + }, + [USBC_PORT_C1] = { + /* Compatible with Silicon Mitus SM536A0 */ + .i2c_port = I2C_PORT_USB_C1_PPC, + .i2c_addr_flags = NX20P3483_ADDR2_FLAGS, + .drv = &nx20p348x_drv, + }, + [USBC_PORT_C2] = { + .i2c_port = I2C_PORT_USB_C0_C2_PPC, + /* + * b/179987870 + * schematics I2C map says ADDR3 + */ + .i2c_addr_flags = SYV682X_ADDR2_FLAGS, + .drv = &syv682x_drv, + }, +}; +BUILD_ASSERT(ARRAY_SIZE(ppc_chips) == USBC_PORT_COUNT); + +unsigned int ppc_cnt = ARRAY_SIZE(ppc_chips); + +/* USBC mux configuration - Alder Lake includes internal mux */ +static const struct usb_mux usbc0_tcss_usb_mux = { + .usb_port = USBC_PORT_C0, + .driver = &virtual_usb_mux_driver, + .hpd_update = &virtual_hpd_update, +}; +static const struct usb_mux usbc2_tcss_usb_mux = { + .usb_port = USBC_PORT_C2, + .driver = &virtual_usb_mux_driver, + .hpd_update = &virtual_hpd_update, +}; + /* - * TODO(b/179513527): add USB-C support + * USB3 DB mux configuration - the top level mux still needs to be set + * to the virtual_usb_mux_driver so the AP gets notified of mux changes + * and updates the TCSS configuration on state changes. */ +static const struct usb_mux usbc1_usb3_db_retimer = { + .usb_port = USBC_PORT_C1, + .driver = &tcpci_tcpm_usb_mux_driver, + .hpd_update = &ps8xxx_tcpc_update_hpd_status, +}; + +const struct usb_mux usb_muxes[] = { + [USBC_PORT_C0] = { + .usb_port = USBC_PORT_C0, + .driver = &bb_usb_retimer, + .i2c_port = I2C_PORT_USB_C0_C2_MUX, + .i2c_addr_flags = USBC_PORT_C0_BB_RETIMER_I2C_ADDR, + .next_mux = &usbc0_tcss_usb_mux, + }, + [USBC_PORT_C1] = { + /* PS8815 DB */ + .usb_port = USBC_PORT_C1, + .driver = &virtual_usb_mux_driver, + .hpd_update = &virtual_hpd_update, + .next_mux = &usbc1_usb3_db_retimer, + }, + [USBC_PORT_C2] = { + .usb_port = USBC_PORT_C2, + .driver = &bb_usb_retimer, + .i2c_port = I2C_PORT_USB_C0_C2_MUX, + .i2c_addr_flags = USBC_PORT_C2_BB_RETIMER_I2C_ADDR, + .next_mux = &usbc2_tcss_usb_mux, + }, +}; +BUILD_ASSERT(ARRAY_SIZE(usb_muxes) == USBC_PORT_COUNT); + +/* BC1.2 charger detect configuration */ +const struct pi3usb9201_config_t pi3usb9201_bc12_chips[] = { + [USBC_PORT_C0] = { + .i2c_port = I2C_PORT_USB_C0_C2_BC12, + .i2c_addr_flags = PI3USB9201_I2C_ADDR_3_FLAGS, + }, + [USBC_PORT_C1] = { + .i2c_port = I2C_PORT_USB_C1_BC12, + .i2c_addr_flags = PI3USB9201_I2C_ADDR_3_FLAGS, + }, + [USBC_PORT_C2] = { + .i2c_port = I2C_PORT_USB_C0_C2_BC12, + .i2c_addr_flags = PI3USB9201_I2C_ADDR_1_FLAGS, + }, +}; +BUILD_ASSERT(ARRAY_SIZE(pi3usb9201_bc12_chips) == USBC_PORT_COUNT); + +/* + * USB C0 and C2 uses burnside bridge chips and have their reset + * controlled by their respective TCPC chips acting as GPIO expanders. + * + * ioex_init() is normally called before we take the TCPCs out of + * reset, so we need to start in disabled mode, then explicitly + * call ioex_init(). + */ + +struct ioexpander_config_t ioex_config[] = { + [IOEX_C0_NCT38XX] = { + .i2c_host_port = I2C_PORT_USB_C0_C2_TCPC, + .i2c_addr_flags = NCT38XX_I2C_ADDR1_1_FLAGS, + .drv = &nct38xx_ioexpander_drv, + .flags = IOEX_FLAGS_DISABLED, + }, + [IOEX_C2_NCT38XX] = { + .i2c_host_port = I2C_PORT_USB_C0_C2_TCPC, + .i2c_addr_flags = NCT38XX_I2C_ADDR2_1_FLAGS, + .drv = &nct38xx_ioexpander_drv, + .flags = IOEX_FLAGS_DISABLED, + }, +}; +BUILD_ASSERT(ARRAY_SIZE(ioex_config) == CONFIG_IO_EXPANDER_PORT_COUNT); + +void config_usb_db_type(void) +{ + enum ec_cfg_usb_db_type db_type = ec_cfg_usb_db_type(); + + /* + * TODO(b/180434685): implement multiple DB types + */ + + CPRINTS("Configured USB DB type number is %d", db_type); +} + +__override void bb_retimer_power_handle(const struct usb_mux *me, int on_off) +{ + enum ioex_signal rst_signal; + + if (me->usb_port == USBC_PORT_C0) + rst_signal = IOEX_USB_C0_RT_RST_ODL; + else if (me->usb_port == USBC_PORT_C2) + rst_signal = IOEX_USB_C2_RT_RST_ODL; + else + return; + + /* + * We do not have a load switch for the burnside bridge chips, + * so we only need to sequence reset. + */ + + if (on_off) { + /* + * Tpw, minimum time from VCC to RESET_N de-assertion is 100us. + * For boards that don't provide a load switch control, the + * retimer_init() function ensures power is up before calling + * this function. + */ + ioex_set_level(rst_signal, 1); + /* + * Allow 1ms time for the retimer to power up lc_domain + * which powers I2C controller within retimer + */ + msleep(1); + } else { + ioex_set_level(rst_signal, 0); + msleep(1); + } +} + +void board_reset_pd_mcu(void) +{ + /* + * TODO(b/179648104): figure out correct timing + */ + + gpio_set_level(GPIO_USB_C0_C2_TCPC_RST_ODL, 0); + if (ec_cfg_usb_db_type() != DB_USB_ABSENT) { + gpio_set_level(GPIO_USB_C1_RST_ODL, 0); + gpio_set_level(GPIO_USB_C1_RT_RST_R_ODL, 0); + } + + /* + * delay for power-on to reset-off and min. assertion time + */ + + msleep(20); + + gpio_set_level(GPIO_USB_C0_C2_TCPC_RST_ODL, 1); + if (ec_cfg_usb_db_type() != DB_USB_ABSENT) { + gpio_set_level(GPIO_USB_C1_RST_ODL, 1); + gpio_set_level(GPIO_USB_C1_RT_RST_R_ODL, 1); + } + + /* wait for chips to come up */ + + msleep(50); +} + +static void board_tcpc_init(void) +{ + int i; + + /* Don't reset TCPCs after initial reset */ + if (!system_jumped_late()) { + board_reset_pd_mcu(); + + for (i = 0; i < CONFIG_IO_EXPANDER_PORT_COUNT; ++i) { + ioex_config[i].flags &= ~IOEX_FLAGS_DISABLED; + ioex_init(i); + } + } + + /* Enable PPC interrupts. */ + gpio_enable_interrupt(GPIO_USB_C0_PPC_INT_ODL); + gpio_enable_interrupt(GPIO_USB_C2_PPC_INT_ODL); + + /* Enable TCPC interrupts. */ + gpio_enable_interrupt(GPIO_USB_C0_C2_TCPC_INT_ODL); + + /* Enable BC1.2 interrupts. */ + gpio_enable_interrupt(GPIO_USB_C0_BC12_INT_ODL); + gpio_enable_interrupt(GPIO_USB_C2_BC12_INT_ODL); + + if (ec_cfg_usb_db_type() != DB_USB_ABSENT) { + gpio_enable_interrupt(GPIO_USB_C1_PPC_INT_ODL); + gpio_enable_interrupt(GPIO_USB_C1_TCPC_INT_ODL); + gpio_enable_interrupt(GPIO_USB_C1_BC12_INT_ODL); + } +} +DECLARE_HOOK(HOOK_INIT, board_tcpc_init, HOOK_PRIO_INIT_CHIPSET); + +uint16_t tcpc_get_alert_status(void) +{ + uint16_t status = 0; + + if (gpio_get_level(GPIO_USB_C0_C2_TCPC_INT_ODL) == 0) + status |= PD_STATUS_TCPC_ALERT_0 | PD_STATUS_TCPC_ALERT_2; + + if ((ec_cfg_usb_db_type() != DB_USB_ABSENT) && + gpio_get_level(GPIO_USB_C1_TCPC_INT_ODL) == 0) + status |= PD_STATUS_TCPC_ALERT_1; + + return status; +} + +int ppc_get_alert_status(int port) +{ + if (port == USBC_PORT_C0) + return gpio_get_level(GPIO_USB_C0_PPC_INT_ODL) == 0; + else if ((port == USBC_PORT_C1) && + (ec_cfg_usb_db_type() != DB_USB_ABSENT)) + return gpio_get_level(GPIO_USB_C1_PPC_INT_ODL) == 0; + else if (port == USBC_PORT_C2) + return gpio_get_level(GPIO_USB_C2_PPC_INT_ODL) == 0; + return 0; +} void tcpc_alert_event(enum gpio_signal signal) { + switch (signal) { + case GPIO_USB_C0_C2_TCPC_INT_ODL: + schedule_deferred_pd_interrupt(USBC_PORT_C0); + break; + case GPIO_USB_C1_TCPC_INT_ODL: + if (ec_cfg_usb_db_type() == DB_USB_ABSENT) + break; + schedule_deferred_pd_interrupt(USBC_PORT_C1); + break; + default: + break; + } } void bc12_interrupt(enum gpio_signal signal) { + switch (signal) { + case GPIO_USB_C0_BC12_INT_ODL: + task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_BC12); + break; + case GPIO_USB_C1_BC12_INT_ODL: + if (ec_cfg_usb_db_type() == DB_USB_ABSENT) + break; + task_set_event(TASK_ID_USB_CHG_P1, USB_CHG_EVENT_BC12); + break; + case GPIO_USB_C2_BC12_INT_ODL: + task_set_event(TASK_ID_USB_CHG_P2, USB_CHG_EVENT_BC12); + break; + default: + break; + } } void ppc_interrupt(enum gpio_signal signal) { + switch (signal) { + case GPIO_USB_C0_PPC_INT_ODL: + syv682x_interrupt(USBC_PORT_C0); + break; + case GPIO_USB_C1_PPC_INT_ODL: + switch (ec_cfg_usb_db_type()) { + case DB_USB_ABSENT: + case DB_USB_ABSENT2: + break; + case DB_USB3_PS8815: + nx20p348x_interrupt(USBC_PORT_C1); + break; + } + break; + case GPIO_USB_C2_PPC_INT_ODL: + syv682x_interrupt(USBC_PORT_C2); + break; + default: + break; + } } void retimer_interrupt(enum gpio_signal signal) { + /* + * TODO(b/179513527): add USB-C support + */ } diff --git a/board/brya/usbc_config.h b/board/brya/usbc_config.h new file mode 100644 index 0000000000..5d08a446fb --- /dev/null +++ b/board/brya/usbc_config.h @@ -0,0 +1,22 @@ +/* Copyright 2021 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Brya board-specific USB-C configuration */ + +#ifndef __CROS_EC_USBC_CONFIG_H +#define __CROS_EC_USBC_CONFIG_H + +#define CONFIG_USB_PD_PORT_MAX_COUNT 3 + +enum usbc_port { + USBC_PORT_C0 = 0, + USBC_PORT_C1, + USBC_PORT_C2, + USBC_PORT_COUNT +}; + +void config_usb_db_type(void); + +#endif /* __CROS_EC_USBC_CONFIG_H */ |