diff options
author | Scott <scollyer@chromium.org> | 2015-06-04 16:03:28 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-06-23 19:18:44 +0000 |
commit | 99e964c018eec1cba83022361866dd0b14d47610 (patch) | |
tree | 67cb7b386101bbd2abf2f45fc66ffdfd8d1bceb9 | |
parent | 0e2176304f3af2b78e8e0b12dab8feb82abccd8f (diff) | |
download | chrome-ec-99e964c018eec1cba83022361866dd0b14d47610.tar.gz |
pd: Add support for TCPC Alert and Alert_Mask registers
Changed the alert function to hold the ec_int line until
all of the alert bits are cleared. Added support for the
alert_mask register. In addition, created ec_int_status
variable to distinguish which of 3 ec_int sources is
driving the pd_mcu_int line.
BUG=none
BRANCH=tot
TEST=Tested Zinger to Glados and Zinger to Samus and verified
that it established a power contract in both cases. Did not
test Oak, but put exact same changes in board.c as in glados.
Change-Id: I372e75b8fd5d66a0c01db18b46100b86fd9ac064
Signed-off-by: Scott Collyer <scollyer@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/278256
Reviewed-by: Alec Berg <alecaberg@chromium.org>
-rw-r--r-- | board/glados_pd/board.c | 48 | ||||
-rw-r--r-- | board/oak_pd/board.c | 51 | ||||
-rw-r--r-- | common/host_command_pd.c | 58 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 83 | ||||
-rw-r--r-- | common/usb_pd_tcpc.c | 94 | ||||
-rw-r--r-- | common/usb_pd_tcpm.c | 27 | ||||
-rw-r--r-- | common/usb_pd_tcpm_stub.c | 21 | ||||
-rw-r--r-- | include/ec_commands.h | 5 | ||||
-rw-r--r-- | include/usb_pd_tcpm.h | 59 |
9 files changed, 320 insertions, 126 deletions
diff --git a/board/glados_pd/board.c b/board/glados_pd/board.c index 776e30a29b..42e8958538 100644 --- a/board/glados_pd/board.c +++ b/board/glados_pd/board.c @@ -21,17 +21,13 @@ #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) +static uint32_t ec_int_status; + void pd_send_ec_int(void) { - gpio_set_level(GPIO_EC_INT, 0); - - /* - * Delay long enough to guarantee EC see's the change. - * TODO: make sure this delay is sufficient. - */ - usleep(5); + /* If any of 3 sources are active, then drive the line low */ + gpio_set_level(GPIO_EC_INT, !ec_int_status); - gpio_set_level(GPIO_EC_INT, 1); } void vbus0_evt(enum gpio_signal signal) @@ -84,8 +80,27 @@ const struct i2c_port_t i2c_ports[] = { }; const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); -void tcpc_alert(void) +void tcpc_alert(int port) { + /* + * This function is called when the TCPC sets one of + * bits in the Alert register and that bit's corresponding + * location in the Alert_Mask register is set. + */ + atomic_or(&ec_int_status, port ? + PD_STATUS_TCPC_ALERT_1 : PD_STATUS_TCPC_ALERT_0); + pd_send_ec_int(); +} + +void tcpc_alert_clear(int port) +{ + /* + * The TCPM has acknowledged all Alert bits and the + * Alert# line needs to be set inactive. Clear + * the corresponding port's bit in the static variable. + */ + atomic_clear(&ec_int_status, port ? + PD_STATUS_TCPC_ALERT_1 : PD_STATUS_TCPC_ALERT_0); pd_send_ec_int(); } @@ -93,6 +108,8 @@ void tcpc_alert(void) /* Console commands */ static int command_ec_int(int argc, char **argv) { + /* Indicate that ec_int gpio is active due to host command */ + atomic_or(&ec_int_status, PD_STATUS_HOST_EVENT); pd_send_ec_int(); return EC_SUCCESS; @@ -107,12 +124,19 @@ static int ec_status_host_cmd(struct host_cmd_handler_args *args) struct ec_response_pd_status *r = args->response; /* - * TODO: use state here to notify EC of host events, tcpc port - * 0 alert and tcpc port 1 alert. + * ec_int_status is used to store state for HOST_EVENT, + * TCPC 0 Alert, and TCPC 1 Alert bits. */ - r->status = 0; + r->status = ec_int_status; args->response_size = sizeof(*r); + /* + * If the source of the EC int line was HOST_EVENT, it has + * been acknowledged so can always clear HOST_EVENT bit + * from the ec_int_status variable + */ + atomic_clear(&ec_int_status, PD_STATUS_HOST_EVENT); + return EC_RES_SUCCESS; } DECLARE_HOST_COMMAND(EC_CMD_PD_EXCHANGE_STATUS, ec_status_host_cmd, diff --git a/board/oak_pd/board.c b/board/oak_pd/board.c index 8d346661b5..df550b4e26 100644 --- a/board/oak_pd/board.c +++ b/board/oak_pd/board.c @@ -20,17 +20,16 @@ #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) +/* Variable used to indicate which source is driving the ec_int line */ +static uint32_t ec_int_status; + void pd_send_ec_int(void) { - gpio_set_level(GPIO_EC_INT, 0); - - /* - * Delay long enough to guarantee EC see's the change. - * TODO: make sure this delay is sufficient. - */ - usleep(5); + /* Indicate that ec_int gpio is active due to host command */ + atomic_or(&ec_int_status, PD_STATUS_HOST_EVENT); + /* If any sources are active, then drive the line low */ + gpio_set_level(GPIO_EC_INT, !ec_int_status); - gpio_set_level(GPIO_EC_INT, 1); } void vbus0_evt(enum gpio_signal signal) @@ -85,8 +84,27 @@ const struct i2c_port_t i2c_ports[] = { }; const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); -void tcpc_alert(void) +void tcpc_alert(int port) { + /* + * This function is called when the TCPC sets one of + * bits in the Alert register and that bit's corresponding + * location in the Alert_Mask register is set. + */ + atomic_or(&ec_int_status, port ? + PD_STATUS_TCPC_ALERT_1 : PD_STATUS_TCPC_ALERT_0); + pd_send_ec_int(); +} + +void tcpc_alert_clear(int port) +{ + /* + * The TCPM has acknowledged all Alert bits and the + * Alert# line needs to be set inactive. Clear + * the corresponding port's bit in the static variable. + */ + atomic_clear(&ec_int_status, port ? + PD_STATUS_TCPC_ALERT_1 : PD_STATUS_TCPC_ALERT_0); pd_send_ec_int(); } @@ -94,6 +112,8 @@ void tcpc_alert(void) /* Console commands */ static int command_ec_int(int argc, char **argv) { + /* Indicate that ec_int gpio is active due to host command */ + atomic_or(&ec_int_status, PD_STATUS_HOST_EVENT); pd_send_ec_int(); return EC_SUCCESS; @@ -108,12 +128,19 @@ static int ec_status_host_cmd(struct host_cmd_handler_args *args) struct ec_response_pd_status *r = args->response; /* - * TODO: use state here to notify EC of host events, tcpc port - * 0 alert and tcpc port 1 alert. + * ec_int_status is used to store state for HOST_EVENT, + * TCPC 0 Alert, and TCPC 1 Alert bits. */ - r->status = 0; + r->status = ec_int_status; args->response_size = sizeof(*r); + /* + * If the source of the EC int line was HOST_EVENT, it has + * been acknowledged so can always clear HOST_EVENT bit + * from the ec_int_status variable + */ + atomic_clear(&ec_int_status, PD_STATUS_HOST_EVENT); + return EC_RES_SUCCESS; } DECLARE_HOST_COMMAND(EC_CMD_PD_EXCHANGE_STATUS, ec_status_host_cmd, diff --git a/common/host_command_pd.c b/common/host_command_pd.c index 33bdb52745..a10a591637 100644 --- a/common/host_command_pd.c +++ b/common/host_command_pd.c @@ -8,6 +8,7 @@ #include "charge_state.h" #include "common.h" #include "console.h" +#include "gpio.h" #include "host_command.h" #include "lightbar.h" #include "panic.h" @@ -45,11 +46,31 @@ void host_command_pd_send_status(enum pd_charge_state new_chg_state) task_set_event(TASK_ID_PDCMD, TASK_EVENT_EXCHANGE_PD_STATUS, 0); } +static int pd_send_host_command(struct ec_params_pd_status *ec_status, + struct ec_response_pd_status *pd_status) +{ + int rv; + + rv = pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 1, ec_status, + sizeof(struct ec_params_pd_status), pd_status, + sizeof(struct ec_response_pd_status)); + + /* If PD doesn't support new command version, try old version */ + if (rv == -EC_RES_INVALID_VERSION) + rv = pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 0, ec_status, + sizeof(struct ec_params_pd_status), pd_status, + sizeof(struct ec_response_pd_status)); + return rv; +} + static void pd_exchange_status(void) { struct ec_params_pd_status ec_status; struct ec_response_pd_status pd_status; int rv = 0; +#ifdef CONFIG_USB_PD_TCPM_TCPCI + int loop_count; +#endif #ifdef CONFIG_HOSTCMD_PD_PANIC static int pd_in_rw; #endif @@ -63,15 +84,7 @@ static void pd_exchange_status(void) else ec_status.batt_soc = -1; - rv = pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 1, &ec_status, - sizeof(struct ec_params_pd_status), &pd_status, - sizeof(struct ec_response_pd_status)); - - /* If PD doesn't support new command version, try old version */ - if (rv == -EC_RES_INVALID_VERSION) - rv = pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 0, &ec_status, - sizeof(struct ec_params_pd_status), &pd_status, - sizeof(struct ec_response_pd_status)); + rv = pd_send_host_command(&ec_status, &pd_status); if (rv < 0) { CPRINTS("Host command to PD MCU failed"); @@ -124,7 +137,32 @@ static void pd_exchange_status(void) host_set_single_event(EC_HOST_EVENT_PD_MCU); #ifdef CONFIG_USB_PD_TCPM_TCPCI - tcpc_alert(); + /* + * Loop here until all Alerts from either port have been handled. + * This is necessary to prevent the case where Alert bits are set + * and the GPIO line is held low, which would prevent a new edge + * event which prevents tcpc_alert() from being called and that + * in turn prevents the GPIO line from being released. + */ + while (!gpio_get_level(GPIO_PD_MCU_INT)) { + /* + * If TCPC is not present on this MCU, then check + * to see if either PD port is signallng an + * Alert# to the TCPM. + */ + if (pd_status.status & PD_STATUS_TCPC_ALERT_0) + tcpc_alert(0); + if (pd_status.status & PD_STATUS_TCPC_ALERT_1) + tcpc_alert(1); + if (loop_count++) { + usleep(50*MSEC); + rv = pd_send_host_command(&ec_status, &pd_status); + if (rv < 0) { + CPRINTS("Host command to PD MCU failed"); + return; + } + } + } #endif } diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index f87e5010a5..deeb683630 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -304,7 +304,7 @@ static void inc_id(int port) static void pd_transmit_complete(int port, int status) { - if (status & TCPC_REG_ALERT1_TX_SUCCESS) + if (status & TCPC_REG_ALERT_TX_SUCCESS) inc_id(port); pd[port].tx_status = status; @@ -329,7 +329,7 @@ static int pd_transmit(int port, enum tcpm_transmit_type type, return -1; /* TODO: give different error condition for failed vs discarded */ - return pd[port].tx_status & TCPC_REG_ALERT1_TX_SUCCESS ? 1 : -1; + return pd[port].tx_status & TCPC_REG_ALERT_TX_SUCCESS ? 1 : -1; } static void pd_update_roles(int port) @@ -1299,6 +1299,25 @@ void pd_set_new_power_request(int port) #error "Backwards compatible DFP does not support USB" #endif +int tcpm_init_alert_mask(int port) +{ + uint16_t mask; + int rv; + + /* + * Create mask of alert events that will cause the TCPC to + * signal the TCPM via the Alert# gpio line. + */ + mask = TCPC_REG_ALERT_TX_SUCCESS | TCPC_REG_ALERT_TX_FAILED | + TCPC_REG_ALERT_TX_DISCARDED | TCPC_REG_ALERT_RX_STATUS | + TCPC_REG_ALERT_RX_HARD_RST | TCPC_REG_ALERT_CC_STATUS; + /* Set the alert mask in TCPC */ + rv = tcpm_alert_mask_set(port, TCPC_REG_ALERT_MASK, mask); + + return rv; +} + + void pd_task(void) { int head; @@ -1330,6 +1349,9 @@ void pd_task(void) tcpm_init(port); CPRINTF("[%T TCPC p%d ready]\n", port); + /* Initialize TCPC alert mask register via the TCPM */ + tcpm_init_alert_mask(port); + /* Disable TCPC RX until connection is established */ tcpm_set_rx_enable(port, 0); @@ -2389,39 +2411,38 @@ void pd_task(void) } } -void tcpc_alert(void) +void tcpc_alert(int port) { - int status, i; + int status; - /* loop over ports and check alert status */ - for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) { - tcpm_alert_status(i, TCPC_REG_ALERT1, (uint8_t *)&status); - if (status & TCPC_REG_ALERT1_CC_STATUS) { - /* CC status changed, wake task */ - task_set_event(PD_PORT_TO_TASK_ID(i), PD_EVENT_CC, 0); - } - if (status & TCPC_REG_ALERT1_RX_STATUS) { - /* message received */ - /* - * If TCPC is compiled in, then we will have already - * received PD_EVENT_RX from phy layer in - * pd_rx_event(), so we don't need to set another - * event. If TCPC is not running on this MCU, then - * this needs to wake the PD task. - */ + /* Read the Alert register from the TCPC */ + tcpm_alert_status(port, TCPC_REG_ALERT, (uint16_t *)&status); + + if (status & TCPC_REG_ALERT_CC_STATUS) { + /* CC status changed, wake task */ + task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0); + } + if (status & TCPC_REG_ALERT_RX_STATUS) { + /* message received */ + /* + * If TCPC is compiled in, then we will have already + * received PD_EVENT_RX from phy layer in + * pd_rx_event(), so we don't need to set another + * event. If TCPC is not running on this MCU, then + * this needs to wake the PD task. + */ #ifndef CONFIG_USB_PD_TCPC - task_set_event(PD_PORT_TO_TASK_ID(i), PD_EVENT_RX, 0); + task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0); #endif - } - if (status & TCPC_REG_ALERT1_RX_HARD_RST) { - /* hard reset received */ - execute_hard_reset(i); - task_wake(PD_PORT_TO_TASK_ID(i)); - } - if (status & TCPC_REG_ALERT1_TX_COMPLETE) { - /* transmit complete */ - pd_transmit_complete(i, status); - } + } + if (status & TCPC_REG_ALERT_RX_HARD_RST) { + /* hard reset received */ + execute_hard_reset(port); + task_wake(PD_PORT_TO_TASK_ID(port)); + } + if (status & TCPC_REG_ALERT_TX_COMPLETE) { + /* transmit complete */ + pd_transmit_complete(port, status); } } diff --git a/common/usb_pd_tcpc.c b/common/usb_pd_tcpc.c index c9cbf03896..307f7c7c0e 100644 --- a/common/usb_pd_tcpc.c +++ b/common/usb_pd_tcpc.c @@ -187,7 +187,7 @@ static const uint8_t dec4b5b[] = { #define TYPE_C_SRC_3000_THRESHOLD 1230 /* mV */ /* Convert TCPC Alert register to index into pd.alert[] */ -#define ALERT_REG_TO_INDEX(reg) (reg - TCPC_REG_ALERT1) +#define ALERT_REG_TO_INDEX(reg) (reg - TCPC_REG_ALERT) /* PD transmit errors */ enum pd_tx_errors { @@ -209,7 +209,8 @@ static struct pd_port_controller { /* CC status */ uint8_t cc_status[2]; /* TCPC alert status */ - uint8_t alert[2]; + uint16_t alert; + uint16_t alert_mask; /* RX enabled */ uint8_t rx_enabled; @@ -696,10 +697,16 @@ static int cc_voltage_to_status(int port, int cc_volt) return 0; } -static void alert(int port, int reg, int mask) +static void alert(int port, int mask) { - pd[port].alert[ALERT_REG_TO_INDEX(reg)] |= mask; - tcpc_alert(); + /* Always update the Alert status register */ + pd[port].alert |= mask; + /* + * Only send interrupt to TCPM if corresponding + * bit in the alert_enable register is set. + */ + if (pd[port].alert_mask & mask) + tcpc_alert(port); } void tcpc_init(int port) @@ -726,10 +733,9 @@ int tcpc_run(int port, int evt) handle_request(port, pd[port].rx_head, pd[port].rx_payload); - alert(port, TCPC_REG_ALERT1, TCPC_REG_ALERT1_RX_STATUS); + alert(port, TCPC_REG_ALERT_RX_STATUS); } else if (pd[port].rx_head == PD_RX_ERR_HARD_RESET) { - alert(port, TCPC_REG_ALERT1, - TCPC_REG_ALERT1_RX_HARD_RST); + alert(port, TCPC_REG_ALERT_RX_HARD_RST); } } @@ -754,14 +760,11 @@ int tcpc_run(int port, int evt) /* send appropriate alert for tx completion */ if (res >= 0) - alert(port, TCPC_REG_ALERT1, - TCPC_REG_ALERT1_TX_SUCCESS); + alert(port, TCPC_REG_ALERT_TX_SUCCESS); else if (res == PD_TX_ERR_GOODCRC) - alert(port, TCPC_REG_ALERT1, - TCPC_REG_ALERT1_TX_FAILED); + alert(port, TCPC_REG_ALERT_TX_FAILED); else - alert(port, TCPC_REG_ALERT1, - TCPC_REG_ALERT1_TX_DISCARDED); + alert(port, TCPC_REG_ALERT_TX_DISCARDED); } else { /* If we have nothing to transmit, then sample CC lines */ @@ -778,8 +781,7 @@ int tcpc_run(int port, int evt) cc = cc_voltage_to_status(port, cc); if (pd[port].cc_status[i] != cc) { pd[port].cc_status[i] = cc; - alert(port, TCPC_REG_ALERT1, - TCPC_REG_ALERT1_CC_STATUS); + alert(port, TCPC_REG_ALERT_CC_STATUS); } } } @@ -820,17 +822,33 @@ void pd_rx_event(int port) task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0); } -int tcpc_alert_status(int port, int alert_reg, uint8_t *alert) +int tcpc_alert_status(int port, uint16_t *alert) { - int ret = pd[port].alert[ALERT_REG_TO_INDEX(alert_reg)]; - - /* TODO: Need to use alert mask to know which bits to let through */ - /* TODO: Alert register is read-clear for now, but shouldn't be */ - pd[port].alert[ALERT_REG_TO_INDEX(alert_reg)] = 0; + /* return the value of the TCPC Alert register */ + uint16_t ret = pd[port].alert; *alert = ret; return EC_SUCCESS; } +int tcpc_alert_status_clear(int port, uint16_t mask) +{ + /* clear only the bits specified by the TCPM */ + pd[port].alert &= ~mask; +#ifndef CONFIG_USB_POWER_DELIVERY + /* Set Alert# inactive if all alert bits clear */ + if (!pd[port].alert) + tcpc_alert_clear(port); +#endif + return EC_SUCCESS; +} + +int tcpc_alert_mask_update(int port, uint16_t mask) +{ + /* Update the alert mask as specificied by the TCPM */ + pd[port].alert_mask = mask; + return EC_SUCCESS; +} + int tcpc_set_cc(int port, int pull) { /* If CC pull resistor not changing, then nothing to do */ @@ -929,6 +947,7 @@ int tcpc_get_message(int port, uint32_t *payload, int *head) #ifndef CONFIG_USB_POWER_DELIVERY static void tcpc_i2c_write(int port, int reg, int len, uint8_t *payload) { + uint16_t alert; switch (reg) { case TCPC_REG_ROLE_CTRL: tcpc_set_cc(port, TCPC_REG_ROLE_CTRL_CC1(payload[1])); @@ -943,9 +962,16 @@ static void tcpc_i2c_write(int port, int reg, int len, uint8_t *payload) TCPC_REG_MSG_HDR_INFO_PROLE(payload[1]), TCPC_REG_MSG_HDR_INFO_DROLE(payload[1])); break; - case TCPC_REG_ALERT1: - case TCPC_REG_ALERT2: - /* TODO: clear alert status reg when writtent to */ + case TCPC_REG_ALERT: + alert = payload[1]; + alert |= (payload[2] << 8); + /* clear alert bits specified by the TCPM */ + tcpc_alert_status_clear(port, alert); + break; + case TCPC_REG_ALERT_MASK: + alert = payload[1]; + alert |= (payload[2] << 8); + tcpc_alert_mask_update(port, alert); break; case TCPC_REG_RX_DETECT: tcpc_set_rx_enable(port, payload[1] & @@ -967,6 +993,7 @@ static void tcpc_i2c_write(int port, int reg, int len, uint8_t *payload) static int tcpc_i2c_read(int port, int reg, uint8_t *payload) { int cc1, cc2; + uint16_t alert; switch (reg) { case TCPC_REG_VENDOR_ID: @@ -995,14 +1022,19 @@ static int tcpc_i2c_read(int port, int reg, uint8_t *payload) payload[0] = TCPC_REG_MSG_HDR_INFO_SET(pd[port].data_role, pd[port].power_role); return 1; - case TCPC_REG_ALERT1: - case TCPC_REG_ALERT2: - tcpc_alert_status(port, reg, payload); - return 1; case TCPC_REG_RX_DETECT: payload[0] = pd[port].rx_enabled ? TCPC_REG_RX_DETECT_SOP_HRST_MASK : 0; return 1; + case TCPC_REG_ALERT: + tcpc_alert_status(port, &alert); + payload[0] = alert & 0xff; + payload[1] = (alert >> 8) & 0xff; + return 2; + case TCPC_REG_ALERT_MASK: + payload[0] = pd[port].alert_mask & 0xff; + payload[1] = (pd[port].alert_mask >> 8) & 0xff; + return 2; case TCPC_REG_RX_BYTE_CNT: payload[0] = 4*PD_HEADER_CNT(pd[port].rx_head); return 1; @@ -1113,11 +1145,11 @@ static int command_tcpc(int argc, char **argv) return EC_SUCCESS; } else if (!strncasecmp(argv[2], "state", 5)) { ccprintf("Port C%d, %s - CC:%d, CC0:%d, CC1:%d, " - "Alert: 0x%02x 0x%02x\n", port, + "Alert: 0x%02x\n", port, pd[port].rx_enabled ? "Ena" : "Dis", pd[port].cc_pull, pd[port].cc_status[0], pd[port].cc_status[1], - pd[port].alert[0], pd[port].alert[1]); + pd[port].alert); } return EC_SUCCESS; diff --git a/common/usb_pd_tcpm.c b/common/usb_pd_tcpm.c index d7458fabfe..7d2c38774b 100644 --- a/common/usb_pd_tcpm.c +++ b/common/usb_pd_tcpm.c @@ -92,10 +92,20 @@ int tcpm_set_msg_header(int port, int power_role, int data_role) TCPC_REG_MSG_HDR_INFO_SET(data_role, power_role)); } -int tcpm_alert_status(int port, int alert_reg, uint8_t *alert) +int tcpm_alert_status(int port, int alert_reg, uint16_t *alert) { - return i2c_read8(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), + int rv; + /* Read TCPC Alert register */ + rv = i2c_read16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), alert_reg, (int *)alert); + /* + * The PD protocol layer will process all alert bits + * returned by this function. Therefore, these bits + * can now be cleared from the TCPC register. + */ + i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), + alert_reg, *alert); + return rv; } int tcpm_set_rx_enable(int port, int enable) @@ -106,6 +116,19 @@ int tcpm_set_rx_enable(int port, int enable) enable ? TCPC_REG_RX_DETECT_SOP_HRST_MASK : 0); } +int tcpm_alert_mask_set(int port, int reg, uint16_t mask) +{ + int rv; + /* write to the Alert Mask register */ + rv = i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), + reg, mask); + + if (rv) + return rv; + + return rv; +} + int tcpm_get_message(int port, uint32_t *payload, int *head) { int rv, cnt, reg = TCPC_REG_RX_DATA; diff --git a/common/usb_pd_tcpm_stub.c b/common/usb_pd_tcpm_stub.c index dc0843fa10..60651670a5 100644 --- a/common/usb_pd_tcpm_stub.c +++ b/common/usb_pd_tcpm_stub.c @@ -8,7 +8,11 @@ #include "usb_pd.h" #include "usb_pd_tcpm.h" -extern int tcpc_alert_status(int port, int alert_reg, uint8_t *alert); +#include "console.h" + +extern int tcpc_alert_status(int port, uint16_t *alert); +extern int tcpc_alert_status_clear(int port, uint16_t mask); +extern int tcpc_alert_mask_update(int port, uint16_t mask); extern int tcpc_get_cc(int port, int *cc1, int *cc2); extern int tcpc_set_cc(int port, int pull); extern int tcpc_set_polarity(int port, int polarity); @@ -51,9 +55,15 @@ int tcpm_set_msg_header(int port, int power_role, int data_role) return tcpc_set_msg_header(port, power_role, data_role); } -int tcpm_alert_status(int port, int alert_reg, uint8_t *alert) +int tcpm_alert_status(int port, int alert_reg, uint16_t *alert) { - return tcpc_alert_status(port, alert_reg, alert); + int rv; + + /* Read TCPC Alert register */ + rv = tcpc_alert_status(port, alert); + /* Clear all bits being processed by the protocol layer */ + tcpc_alert_status_clear(port, *alert); + return rv; } int tcpm_set_rx_enable(int port, int enable) @@ -61,6 +71,11 @@ int tcpm_set_rx_enable(int port, int enable) return tcpc_set_rx_enable(port, enable); } +int tcpm_alert_mask_set(int port, int reg, uint16_t mask) +{ + return tcpc_alert_mask_update(port, mask); +} + int tcpm_get_message(int port, uint32_t *payload, int *head) { return tcpc_get_message(port, payload, head); diff --git a/include/ec_commands.h b/include/ec_commands.h index de603e6d1e..4bfbbb0e39 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -3015,6 +3015,11 @@ struct ec_params_pd_status { #define PD_STATUS_HOST_EVENT (1 << 0) /* Forward host event to AP */ #define PD_STATUS_IN_RW (1 << 1) /* Running RW image */ #define PD_STATUS_JUMPED_TO_IMAGE (1 << 2) /* Current image was jumped to */ +#define PD_STATUS_TCPC_ALERT_0 (1 << 3) /* Alert active in port 0 TCPC */ +#define PD_STATUS_TCPC_ALERT_1 (1 << 4) /* Alert active in port 1 TCPC */ +#define PD_STATUS_EC_INT_ACTIVE (PD_STATUS_TCPC_ALERT_0 | \ + PD_STATUS_TCPC_ALERT_1 | \ + PD_STATUS_HOST_EVENT) struct ec_response_pd_status { uint32_t status; /* PD MCU status */ uint32_t curr_lim_ma; /* input current limit */ diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h index c73ca100e1..71f0610ece 100644 --- a/include/usb_pd_tcpm.h +++ b/include/usb_pd_tcpm.h @@ -24,27 +24,26 @@ #define TCPC_REG_DEV_CAP_2 0xd #define TCPC_REG_DEV_CAP_3 0xe #define TCPC_REG_DEV_CAP_4 0xf -#define TCPC_REG_ALERT1 0x10 -#define TCPC_REG_ALERT1_SLEEP_EXITED (1<<7) -#define TCPC_REG_ALERT1_POWER_STATUS (1<<6) -#define TCPC_REG_ALERT1_CC_STATUS (1<<5) -#define TCPC_REG_ALERT1_RX_STATUS (1<<4) -#define TCPC_REG_ALERT1_RX_HARD_RST (1<<3) -#define TCPC_REG_ALERT1_TX_SUCCESS (1<<2) -#define TCPC_REG_ALERT1_TX_DISCARDED (1<<1) -#define TCPC_REG_ALERT1_TX_FAILED (1<<0) -#define TCPC_REG_ALERT1_TX_COMPLETE (TCPC_REG_ALERT1_TX_SUCCESS | \ - TCPC_REG_ALERT1_TX_DISCARDED | \ - TCPC_REG_ALERT1_TX_FAILED) +#define TCPC_REG_ALERT 0x10 +#define TCPC_REG_ALERT_GPIO_CHANGE (1<<10) +#define TCPC_REG_ALERT_V_ALARM_LO (1<<9) +#define TCPC_REG_ALERT_V_ALARM_HI (1<<8) +#define TCPC_REG_ALERT_SLEEP_EXITED (1<<7) +#define TCPC_REG_ALERT_POWER_STATUS (1<<6) +#define TCPC_REG_ALERT_CC_STATUS (1<<5) +#define TCPC_REG_ALERT_RX_STATUS (1<<4) +#define TCPC_REG_ALERT_RX_HARD_RST (1<<3) +#define TCPC_REG_ALERT_TX_SUCCESS (1<<2) +#define TCPC_REG_ALERT_TX_DISCARDED (1<<1) +#define TCPC_REG_ALERT_TX_FAILED (1<<0) +#define TCPC_REG_ALERT_TX_COMPLETE (TCPC_REG_ALERT_TX_SUCCESS | \ + TCPC_REG_ALERT_TX_DISCARDED | \ + TCPC_REG_ALERT_TX_FAILED) -#define TCPC_REG_ALERT2 0x11 -#define TCPC_REG_ALERT3 0x12 -#define TCPC_REG_ALERT4 0x13 -#define TCPC_REG_ALERT_MASK_1 0x14 -#define TCPC_REG_ALERT_MASK_2 0x15 -#define TCPC_REG_POWER_STATUS_MASK 0x16 -#define TCPC_REG_CC1_STATUS 0x18 -#define TCPC_REG_CC2_STATUS 0x19 +#define TCPC_REG_ALERT_MASK 0x12 +#define TCPC_REG_POWER_STATUS_MASK 0x14 +#define TCPC_REG_CC1_STATUS 0x16 +#define TCPC_REG_CC2_STATUS 0x17 #define TCPC_REG_CC_STATUS_SET(term, volt) \ ((term) << 3 | volt) #define TCPC_REG_CC_STATUS_TERM(reg) (((reg) & 0x38) >> 3) @@ -130,8 +129,8 @@ enum tcpm_transmit_type { /** * TCPC is asserting alert */ -void tcpc_alert(void); - +void tcpc_alert(int port); +void tcpc_alert_clear(int port); /** * Initialize TCPC. * @@ -152,13 +151,23 @@ int tcpc_run(int port, int evt); * Read TCPC alert status * * @param port Type-C port number - * @param alert_reg Alert register to read + * @param reg TCPC register address * @param alert Pointer to location to store alert status - * + * @return EC_SUCCESS or error */ -int tcpm_alert_status(int port, int alert_reg, uint8_t *alert); +int tcpm_alert_status(int port, int reg, uint16_t *alert); +/** + * Write TCPC Alert Mask register + * + * @param port Type-C port number + * @param reg TCPC register address + * @param mask bits to be set in Alert Mask register + + * @return EC_SUCCESS or error + */ +int tcpm_alert_mask_set(int port, int reg, uint16_t mask); /** * Initialize TCPM driver and wait for TCPC readiness. |