diff options
-rw-r--r-- | board/kevin/board.h | 2 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 33 | ||||
-rw-r--r-- | driver/tcpm/anx74xx.c | 13 | ||||
-rw-r--r-- | driver/tcpm/ps8751.c | 2 | ||||
-rw-r--r-- | driver/tcpm/tcpci.c | 113 | ||||
-rw-r--r-- | driver/tcpm/tcpci.h | 1 | ||||
-rw-r--r-- | driver/tcpm/tcpm.h | 9 | ||||
-rw-r--r-- | include/config.h | 3 | ||||
-rw-r--r-- | include/ec_commands.h | 13 | ||||
-rw-r--r-- | include/usb_pd_tcpm.h | 12 | ||||
-rw-r--r-- | util/ectool.c | 33 |
11 files changed, 206 insertions, 28 deletions
diff --git a/board/kevin/board.h b/board/kevin/board.h index 2985609b75..6304d351eb 100644 --- a/board/kevin/board.h +++ b/board/kevin/board.h @@ -198,6 +198,8 @@ #undef CONFIG_CMD_TIMERINFO #undef CONFIG_CONSOLE_CMDHELP #undef CONFIG_CONSOLE_HISTORY +#undef CONFIG_EC_CMD_PD_CHIP_INFO + /* * Remove task profiling to improve SHI interrupt latency. * TODO(crosbug.com/p/55710): Re-define once interrupt latency is within diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index b014c5caef..2d10581801 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -1615,6 +1615,15 @@ void pd_task(void) res = tcpm_init(port); CPRINTS("TCPC p%d init %s", port, res ? "failed" : "ready"); this_state = res ? PD_STATE_SUSPENDED : PD_DEFAULT_STATE(port); +#ifndef CONFIG_USB_PD_TCPC + if (!res) { + struct ec_response_pd_chip_info *info; + tcpm_get_chip_info(port, &info); + CPRINTS("TCPC p%d VID:0x%x PID:0x%x DID:0x%x FWV:0x%x", + port, info->vendor_id, info->product_id, + info->device_id, info->fw_version); + } +#endif #ifdef CONFIG_USB_PD_DUAL_ROLE /* @@ -3676,6 +3685,30 @@ DECLARE_HOST_COMMAND(EC_CMD_USB_PD_DEV_INFO, hc_remote_pd_dev_info, EC_VER_MASK(0)); +#ifndef CONFIG_USB_PD_TCPC +#ifdef CONFIG_EC_CMD_PD_CHIP_INFO +static int hc_remote_pd_chip_info(struct host_cmd_handler_args *args) +{ + const struct ec_params_pd_chip_info *p = args->params; + struct ec_response_pd_chip_info *r = args->response, *info; + + if (p->port >= CONFIG_USB_PD_PORT_COUNT) + return EC_RES_INVALID_PARAM; + + if (tcpm_get_chip_info(p->port, &info)) + return EC_RES_ERROR; + + memcpy(r, info, sizeof(*r)); + args->response_size = sizeof(*r); + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_PD_CHIP_INFO, + hc_remote_pd_chip_info, + EC_VER_MASK(0)); +#endif +#endif + #ifdef CONFIG_USB_PD_ALT_MODE_DFP static int hc_remote_pd_set_amode(struct host_cmd_handler_args *args) { diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c index 0501788080..5854c62c8f 100644 --- a/driver/tcpm/anx74xx.c +++ b/driver/tcpm/anx74xx.c @@ -9,6 +9,7 @@ #include "anx74xx.h" #include "task.h" +#include "tcpci.h" #include "tcpm.h" #include "timer.h" #include "usb_charge.h" @@ -17,6 +18,11 @@ #include "usb_pd_tcpc.h" #include "util.h" +#if !defined(CONFIG_USB_PD_TCPM_TCPCI) +#error "ANX74xx is using part of standard TCPCI control" +#error "Please upgrade your board configuration" +#endif + struct anx_state { int polarity; int vconn_en; @@ -571,12 +577,10 @@ static int anx74xx_tcpm_set_polarity(int port, int polarity) return rv; } -#ifdef CONFIG_USB_PD_TCPC_FW_VERSION int anx74xx_tcpc_get_fw_version(int port, int *version) { return tcpc_read(port, ANX74XX_REG_FW_VERSION, version); } -#endif static int anx74xx_tcpm_set_vconn(int port, int enable) { @@ -884,9 +888,7 @@ int anx74xx_tcpm_init(int port) if (rv) return EC_ERROR_UNKNOWN; -#ifdef CONFIG_USB_PD_TCPC_FW_VERSION - board_print_tcpc_fw_version(port); -#endif + tcpm_get_chip_info(port, NULL); return EC_SUCCESS; } @@ -909,6 +911,7 @@ const struct tcpm_drv anx74xx_tcpm_drv = { #ifdef CONFIG_USB_PD_DISCHARGE_TCPC .tcpc_discharge_vbus = &anx74xx_tcpc_discharge_vbus, #endif + .get_chip_info = &tcpci_get_chip_info, }; #ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC diff --git a/driver/tcpm/ps8751.c b/driver/tcpm/ps8751.c index f889f17134..66b895696e 100644 --- a/driver/tcpm/ps8751.c +++ b/driver/tcpm/ps8751.c @@ -61,12 +61,10 @@ void ps8751_tcpc_update_hpd_status(int port, int hpd_lvl, int hpd_irq) } } -#ifdef CONFIG_USB_PD_TCPC_FW_VERSION int ps8751_tcpc_get_fw_version(int port, int *version) { return tcpc_read(port, PS8751_REG_VERSION, version); } -#endif #ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC struct i2c_stress_test_dev ps8751_i2c_stress_test_dev = { diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c index a2e196351f..ad50cdbb8d 100644 --- a/driver/tcpm/tcpci.c +++ b/driver/tcpm/tcpci.c @@ -5,6 +5,9 @@ /* Type-C port manager */ +#include "anx74xx.h" +#include "ec_commands.h" +#include "ps8751.h" #include "task.h" #include "tcpci.h" #include "tcpm.h" @@ -23,7 +26,6 @@ static int selected_rp[CONFIG_USB_PD_PORT_COUNT]; static int init_alert_mask(int port) { uint16_t mask; - int rv; /* * Create mask of alert events that will cause the TCPC to @@ -37,13 +39,7 @@ static int init_alert_mask(int port) #endif ; /* Set the alert mask in TCPC */ - rv = tcpc_write16(port, TCPC_REG_ALERT_MASK, mask); - -#ifdef CONFIG_USB_PD_TCPC_FW_VERSION - board_print_tcpc_fw_version(port); -#endif - - return rv; + return tcpc_write16(port, TCPC_REG_ALERT_MASK, mask); } static int init_power_status_mask(int port) @@ -318,6 +314,72 @@ void tcpci_tcpc_alert(int port) } /* + * For PS8751, this function will fail if the chip is in low power mode. + * PS8751 has to be woken up by reading a random register first then wait for + * 10ms. + * + * This code doesn't have the wake-up read to avoid 10ms delay. Instead, we + * call this function immediately after the chip is reset or initialized + * because it'll gurantee the chip is awake. Once it's called, the chip info + * will be stored in cache, which can be accessed by tcpm_get_chip_info without + * worrying about chip states. + */ +int tcpci_get_chip_info(int port, struct ec_response_pd_chip_info **chip_info) +{ + static struct ec_response_pd_chip_info info[CONFIG_USB_PD_PORT_COUNT]; + int error; + int val; + + if (port >= CONFIG_USB_PD_PORT_COUNT) + return EC_ERROR_INVAL; + + /* If chip_info is NULL, chip info will be stored in cache and can be + * read later by another call. */ + if (chip_info) + *chip_info = &info[port]; + + if (info[port].vendor_id) + return EC_SUCCESS; + + error = tcpc_read16(port, TCPC_REG_VENDOR_ID, &val); + if (error) + return error; + info[port].vendor_id = val; + + error = tcpc_read16(port, TCPC_REG_PRODUCT_ID, &val); + if (error) + return error; + info[port].product_id = val; + + error = tcpc_read16(port, TCPC_REG_BCD_DEV, &val); + if (error) + return error; + info[port].device_id = val; + + switch(info[port].vendor_id) { +#ifdef CONFIG_USB_PD_TCPM_ANX74XX + case ANX74XX_VENDOR_ID: + error = anx74xx_tcpc_get_fw_version(port, &val); + break; +#endif +#ifdef CONFIG_USB_PD_TCPM_PS8751 + case PS8751_VENDOR_ID: + error = ps8751_tcpc_get_fw_version(port, &val); + break; +#endif + default: + /* Even if the chip doesn't implement get_fw_version, we + * return success. The version will be 0xffff. */ + return EC_SUCCESS; + } + if (error) + return error; + info[port].fw_version = val; + + return EC_SUCCESS; +} + +/* * On TCPC i2c failure, make 30 tries (at least 300ms) before giving up * in order to allow the TCPC time to boot / reset. */ @@ -325,30 +387,38 @@ void tcpci_tcpc_alert(int port) int tcpci_tcpm_init(int port) { - int rv; + int error; int power_status; int tries = TCPM_INIT_TRIES; while (1) { - rv = tcpc_read(port, TCPC_REG_POWER_STATUS, &power_status); + error = tcpc_read(port, TCPC_REG_POWER_STATUS, &power_status); /* * If read succeeds and the uninitialized bit is clear, then * initalization is complete, clear all alert bits and write * the initial alert mask. */ - if (rv == EC_SUCCESS && - !(power_status & TCPC_REG_POWER_STATUS_UNINIT)) { - tcpc_write16(port, TCPC_REG_ALERT, 0xffff); - /* Initialize power_status_mask */ - init_power_status_mask(port); - /* Update VBUS status */ - tcpc_vbus[port] = power_status & - TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0; - return init_alert_mask(port); - } else if (rv != EC_SUCCESS && --tries == 0) - return rv; + if (!error && !(power_status & TCPC_REG_POWER_STATUS_UNINIT)) + break; + else if (error && --tries == 0) + return error; msleep(10); } + + tcpc_write16(port, TCPC_REG_ALERT, 0xffff); + /* Initialize power_status_mask */ + init_power_status_mask(port); + /* Update VBUS status */ + tcpc_vbus[port] = power_status & + TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0; + error = init_alert_mask(port); + if (error) + return error; + + /* Read chip info here when we know the chip is awake. */ + tcpm_get_chip_info(port, NULL); + + return EC_SUCCESS; } #ifdef CONFIG_USB_PD_TCPM_MUX @@ -432,4 +502,5 @@ const struct tcpm_drv tcpci_tcpm_drv = { #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE .drp_toggle = &tcpci_tcpc_drp_toggle, #endif + .get_chip_info = &tcpci_get_chip_info, }; diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h index 42f851cfe2..a11050eaf0 100644 --- a/driver/tcpm/tcpci.h +++ b/driver/tcpm/tcpci.h @@ -137,5 +137,6 @@ int tcpci_tcpm_transmit(int port, enum tcpm_transmit_type type, int tcpci_tcpm_mux_init(int i2c_addr); int tcpci_tcpm_mux_set(int i2c_addr, mux_state_t mux_state); int tcpci_tcpm_mux_get(int i2c_addr, mux_state_t *mux_state); +int tcpci_get_chip_info(int port, struct ec_response_pd_chip_info **chip_info); #endif /* __CROS_EC_USB_PD_TCPM_TCPCI_H */ diff --git a/driver/tcpm/tcpm.h b/driver/tcpm/tcpm.h index 1c7c6edff3..9f8e38cbfc 100644 --- a/driver/tcpm/tcpm.h +++ b/driver/tcpm/tcpm.h @@ -9,6 +9,7 @@ #define __CROS_EC_USB_PD_TCPM_TCPM_H #include "common.h" +#include "ec_commands.h" #include "gpio.h" #include "i2c.h" #include "usb_pd_tcpm.h" @@ -162,6 +163,14 @@ static inline int tcpc_i2c_write(const int port, const int addr, } #endif +static inline int tcpm_get_chip_info(int port, + struct ec_response_pd_chip_info **info) +{ + if (tcpc_config[port].drv->get_chip_info) + return tcpc_config[port].drv->get_chip_info(port, info); + return EC_ERROR_UNIMPLEMENTED; +} + #else /** diff --git a/include/config.h b/include/config.h index 34ef75ddee..8c34cccae7 100644 --- a/include/config.h +++ b/include/config.h @@ -1272,6 +1272,9 @@ /* PD MCU supports host commands */ #undef CONFIG_HOSTCMD_PD +/* EC supports EC_CMD_PD_CHIP_INFO */ +#define CONFIG_EC_CMD_PD_CHIP_INFO + /* * Use if PD MCU controls charging (selecting charging port and input * current limit). diff --git a/include/ec_commands.h b/include/ec_commands.h index a445e54a79..1210d945cf 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -3995,6 +3995,19 @@ struct __ec_align1 ec_response_usb_pd_mux_info { uint8_t flags; /* USB_PD_MUX_*-encoded USB mux state */ }; +#define EC_CMD_PD_CHIP_INFO 0x011B + +struct __ec_align1 ec_params_pd_chip_info { + uint8_t port; /* USB-C port number */ +}; + +struct __ec_align2 ec_response_pd_chip_info { + uint16_t vendor_id; + uint16_t product_id; + uint16_t device_id; + uint16_t fw_version; +}; + #endif /* !__ACPI__ */ /*****************************************************************************/ diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h index 5960d1b62e..d95d994184 100644 --- a/include/usb_pd_tcpm.h +++ b/include/usb_pd_tcpm.h @@ -8,6 +8,8 @@ #ifndef __CROS_EC_USB_PD_TCPM_H #define __CROS_EC_USB_PD_TCPM_H +#include "ec_commands.h" + /* Default retry count for transmitting */ #define PD_RETRY_COUNT 3 @@ -195,6 +197,16 @@ struct tcpm_drv { */ int (*drp_toggle)(int port); #endif + + /** + * Get firmware version. + * + * @param port Type-C port number + * @param info Pointer to pointer to PD chip info + * + * @return EC_SUCCESS or error + */ + int (*get_chip_info)(int port, struct ec_response_pd_chip_info **info); }; enum tcpc_alert_polarity { diff --git a/util/ectool.c b/util/ectool.c index 08f0e77ea2..5b14c78203 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -154,6 +154,8 @@ const char help_str[] = " Whether or not the AP should pause in S5 on shutdown\n" " pdcontrol [suspend|resume|reset|disable]\n" " Controls the PD chip\n" + " pdchipinfo <port>\n" + " Get PD chip information\n" " pdlog\n" " Prints the PD event log entries\n" " pdwritelog <type> <port>\n" @@ -6861,6 +6863,36 @@ int cmd_pd_control(int argc, char *argv[]) return (rv < 0 ? rv : 0); } +int cmd_pd_chip_info(int argc, char *argv[]) +{ + struct ec_params_pd_chip_info p; + struct ec_response_pd_chip_info r; + char *e; + int rv; + + if (argc < 2) { + fprintf(stderr, "Usage: %s <port>\n", argv[0]); + return -1; + } + + p.port = strtol(argv[1], &e, 0); + if (e && *e) { + fprintf(stderr, "Bad port number.\n"); + return -1; + } + + rv = ec_command(EC_CMD_PD_CHIP_INFO, 0, &p, sizeof(p), &r, sizeof(r)); + if (rv < 0) + return rv; + + printf("vendor_id: 0x%x\n", r.vendor_id); + printf("product_id: 0x%x\n", r.product_id); + printf("device_id: 0x%x\n", r.device_id); + printf("fw_version: 0x%x\n", r.fw_version); + + return 0; +} + int cmd_pd_write_log(int argc, char *argv[]) { struct ec_params_pd_write_log_entry p; @@ -6954,6 +6986,7 @@ const struct command commands[] = { {"port80read", cmd_port80_read}, {"pdlog", cmd_pd_log}, {"pdcontrol", cmd_pd_control}, + {"pdchipinfo", cmd_pd_chip_info}, {"pdwritelog", cmd_pd_write_log}, {"powerinfo", cmd_power_info}, {"protoinfo", cmd_proto_info}, |