summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/kevin/board.h2
-rw-r--r--common/usb_pd_protocol.c33
-rw-r--r--driver/tcpm/anx74xx.c13
-rw-r--r--driver/tcpm/ps8751.c2
-rw-r--r--driver/tcpm/tcpci.c113
-rw-r--r--driver/tcpm/tcpci.h1
-rw-r--r--driver/tcpm/tcpm.h9
-rw-r--r--include/config.h3
-rw-r--r--include/ec_commands.h13
-rw-r--r--include/usb_pd_tcpm.h12
-rw-r--r--util/ectool.c33
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},