diff options
author | Daisuke Nojiri <dnojiri@chromium.org> | 2017-01-25 18:39:39 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-02-09 22:50:50 -0800 |
commit | 4ff544a573302336b1e2d8b55bfa8a32f847de4e (patch) | |
tree | 1951ca71b4247a18d3f306dcd37879f6bd8a2c4b | |
parent | b889e47410698986822712078ec232c1715b4845 (diff) | |
download | chrome-ec-4ff544a573302336b1e2d8b55bfa8a32f847de4e.tar.gz |
Add host command to get PD chip information
This patch adds a host command to get PD chip info.
For PS8751, tcpci_get_chip_info will fail if the chip is in
low power mode. It can 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
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 tcpc_get_chip_info without worrying about
chip states.
localhost ~ # ectool pdchipinfo 0
vendor_id: 0xaaaa
product_id: 0x3429
device_id: 0xad
fw_version: 0x15
localhost ~ # ectool pdchipinfo 1
vendor_id: 0x1da0
product_id: 0x8751
device_id: 0x1
fw_version: 0x37
BUG=chrome-os-partner:62383
BRANCH=none
TEST=ectool pdchipinfo 0/1. make buildall
Change-Id: I3f1667d00ce1826936d90882ada1df6ed6b0ea37
Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/433166
-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}, |