summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott <scollyer@chromium.org>2015-06-04 16:03:28 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-06-23 19:18:44 +0000
commit99e964c018eec1cba83022361866dd0b14d47610 (patch)
tree67cb7b386101bbd2abf2f45fc66ffdfd8d1bceb9
parent0e2176304f3af2b78e8e0b12dab8feb82abccd8f (diff)
downloadchrome-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.c48
-rw-r--r--board/oak_pd/board.c51
-rw-r--r--common/host_command_pd.c58
-rw-r--r--common/usb_pd_protocol.c83
-rw-r--r--common/usb_pd_tcpc.c94
-rw-r--r--common/usb_pd_tcpm.c27
-rw-r--r--common/usb_pd_tcpm_stub.c21
-rw-r--r--include/ec_commands.h5
-rw-r--r--include/usb_pd_tcpm.h59
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.