summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usb_common.c16
-rw-r--r--common/usb_pd_protocol.c61
-rw-r--r--common/usbc/usb_tc_drp_acc_trysrc_sm.c2
-rw-r--r--driver/tcpm/anx74xx.c27
-rw-r--r--driver/tcpm/fusb302.c22
-rw-r--r--driver/tcpm/it83xx.c23
-rw-r--r--driver/tcpm/mt6370.c18
-rw-r--r--driver/tcpm/nct38xx.c121
-rw-r--r--driver/tcpm/stub.c2
-rw-r--r--driver/tcpm/tcpci.c141
-rw-r--r--driver/tcpm/tcpci.h41
-rw-r--r--driver/tcpm/tcpm.h10
-rw-r--r--include/usb_common.h18
-rw-r--r--include/usb_pd.h8
-rw-r--r--include/usb_pd_tcpm.h12
-rw-r--r--include/usb_tc_sm.h2
16 files changed, 316 insertions, 208 deletions
diff --git a/common/usb_common.c b/common/usb_common.c
index 760ffc2063..946f5ffbdd 100644
--- a/common/usb_common.c
+++ b/common/usb_common.c
@@ -63,7 +63,7 @@ struct pd_pref_config_t __maybe_unused pd_pref_config;
* DTS USB-C @ 3 A Rp3A0 RpUSB
*/
-typec_current_t usb_get_typec_current_limit(enum pd_cc_polarity_type polarity,
+typec_current_t usb_get_typec_current_limit(enum tcpc_cc_polarity polarity,
enum tcpc_cc_voltage_status cc1, enum tcpc_cc_voltage_status cc2)
{
typec_current_t charge = 0;
@@ -96,9 +96,12 @@ typec_current_t usb_get_typec_current_limit(enum pd_cc_polarity_type polarity,
return charge;
}
-enum pd_cc_polarity_type get_snk_polarity(enum tcpc_cc_voltage_status cc1,
+enum tcpc_cc_polarity get_snk_polarity(enum tcpc_cc_voltage_status cc1,
enum tcpc_cc_voltage_status cc2)
{
+ if (cc_is_open(cc1, cc2))
+ return POLARITY_NONE;
+
/* The following assumes:
*
* TYPEC_CC_VOLT_RP_3_0 > TYPEC_CC_VOLT_RP_1_5
@@ -108,6 +111,15 @@ enum pd_cc_polarity_type get_snk_polarity(enum tcpc_cc_voltage_status cc1,
return cc2 > cc1;
}
+enum tcpc_cc_polarity get_src_polarity(enum tcpc_cc_voltage_status cc1,
+ enum tcpc_cc_voltage_status cc2)
+{
+ if (cc_is_open(cc1, cc2))
+ return POLARITY_NONE;
+
+ return cc1 != TYPEC_CC_VOLT_RD;
+}
+
enum pd_cc_states pd_get_cc_state(
enum tcpc_cc_voltage_status cc1, enum tcpc_cc_voltage_status cc2)
{
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 5538b8d1fc..9779b7617d 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -174,8 +174,8 @@ static struct pd_protocol {
uint8_t data_role;
/* 3-bit rolling message ID counter */
uint8_t msg_id;
- /* Port polarity : 0 => CC1 is CC line, 1 => CC2 is CC line */
- uint8_t polarity;
+ /* port polarity */
+ enum tcpc_cc_polarity polarity;
/* PD state for port */
enum pd_states task_state;
/* PD state when we run state handler the last time */
@@ -411,7 +411,7 @@ int pd_is_debug_acc(int port)
pd[port].cc_state == PD_CC_DFP_DEBUG_ACC;
}
-static void set_polarity(int port, int polarity)
+static void set_polarity(int port, enum tcpc_cc_polarity polarity)
{
tcpm_set_polarity(port, polarity);
#ifdef CONFIG_USBC_PPC_POLARITY
@@ -716,6 +716,7 @@ static inline void set_state(int port, enum pd_states next_state)
#ifdef CONFIG_LOW_POWER_IDLE
int i;
#endif
+ int not_auto_toggling = 1;
set_state_timeout(port, 0, 0);
pd[port].task_state = next_state;
@@ -739,9 +740,12 @@ static inline void set_state(int port, enum pd_states next_state)
#ifdef CONFIG_USB_PD_DUAL_ROLE
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
- /* Clear flag to allow DRP auto toggle when possible */
if (last_state != PD_STATE_DRP_AUTO_TOGGLE)
+ /* Clear flag to allow DRP auto toggle when possible */
pd[port].flags &= ~PD_FLAGS_TCPC_DRP_TOGGLE;
+ else
+ /* This is an auto toggle instead of disconnect */
+ not_auto_toggling = 0;
#endif
/* Ignore dual-role toggling between sink and source */
@@ -845,12 +849,26 @@ static inline void set_state(int port, enum pd_states next_state)
/* Invalidate message IDs. */
invalidate_last_message_id(port);
+ if (not_auto_toggling) {
+ /*
+ * On disconnect set the resistor on both CC lines so
+ * we can detect a connection with either polarity.
+ * If we are in dual role toggle, then this will happen
+ * automatically as it needs, so don't adjust the role
+ * in that case.
+ */
+ pd[port].polarity = POLARITY_NONE;
+ if (tcpm_set_polarity(port, POLARITY_NONE))
+ CPRINTS("C%d failed to set polarity",
+ port);
+
+ /* Disable Auto Discharge Disconnect */
+ tcpm_enable_auto_discharge_disconnect(port, 0);
+ }
+
/* detect USB PD cc disconnect */
if (IS_ENABLED(CONFIG_COMMON_RUNTIME))
hook_notify(HOOK_USB_PD_DISCONNECT);
-
- /* Disable Auto Discharge Disconnect */
- tcpm_enable_auto_discharge_disconnect(port, 0);
}
#ifdef CONFIG_LOW_POWER_IDLE
@@ -2611,7 +2629,7 @@ static void pd_partner_port_reset(int port)
}
#endif /* CONFIG_USB_PD_DUAL_ROLE */
-int pd_get_polarity(int port)
+enum tcpc_cc_polarity pd_get_polarity(int port)
{
return pd[port].polarity;
}
@@ -2879,6 +2897,9 @@ void pd_task(void *u)
pd[port].flags |= PD_FLAGS_LPM_ENGAGED;
#endif
+ /* Start as not connected */
+ pd[port].polarity = POLARITY_NONE;
+
#ifdef CONFIG_COMMON_RUNTIME
pd_init_tasks();
#endif
@@ -3127,7 +3148,7 @@ void pd_task(void *u)
port);
} else {
pd[port].polarity =
- (cc1 != TYPEC_CC_VOLT_RD);
+ get_src_polarity(cc1, cc2);
}
} else
#endif /* CONFIG_USB_PD_DUAL_ROLE */
@@ -3377,7 +3398,7 @@ void pd_task(void *u)
port);
} else {
pd[port].polarity =
- (cc1 != TYPEC_CC_VOLT_RD);
+ get_src_polarity(cc1, cc2);
}
set_polarity(port, pd[port].polarity);
@@ -4615,11 +4636,31 @@ void pd_task(void *u)
}
if (next_state == DRP_TC_UNATTACHED_SNK) {
+ /*
+ * The TCPCI comes out of auto toggle with
+ * a prospective connection. It is expecting
+ * us to set the CC lines to what it is
+ * thinking is best or it goes direct back to
+ * unattached. So get the SNK polarity to
+ * be able to setup the CC lines to avoid this.
+ */
+ pd[port].polarity = get_snk_polarity(cc1, cc2);
+
tcpm_set_cc(port, TYPEC_CC_RD);
pd_set_power_role(port, PD_ROLE_SINK);
timeout = 2*MSEC;
set_state(port, PD_STATE_SNK_DISCONNECTED);
} else if (next_state == DRP_TC_UNATTACHED_SRC) {
+ /*
+ * The TCPCI comes out of auto toggle with
+ * a prospective connection. It is expecting
+ * us to set the CC lines to what it is
+ * thinking is best or it goes direct back to
+ * unattached. So get the SNK polarity to
+ * be able to setup the CC lines to avoid this.
+ */
+ pd[port].polarity = get_src_polarity(cc1, cc2);
+
tcpm_set_cc(port, TYPEC_CC_RP);
pd_set_power_role(port, PD_ROLE_SOURCE);
timeout = 2*MSEC;
diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
index caf16d3ad3..0f7ca21e1c 100644
--- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c
+++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
@@ -654,7 +654,7 @@ int pd_fetch_acc_log_entry(int port)
return EC_RES_SUCCESS;
}
-int pd_get_polarity(int port)
+enum tcpc_cc_polarity pd_get_polarity(int port)
{
return tc[port].polarity;
}
diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c
index 0e7ec021d8..2e37d65a13 100644
--- a/driver/tcpm/anx74xx.c
+++ b/driver/tcpm/anx74xx.c
@@ -45,9 +45,6 @@ struct anx_state {
static struct anx_state anx[CONFIG_USB_PD_PORT_MAX_COUNT];
-/* Save the selected rp value */
-static int selected_rp[CONFIG_USB_PD_PORT_MAX_COUNT];
-
#ifdef CONFIG_USB_PD_DECODE_SOP
/* Save the message address */
static int msg_sop[CONFIG_USB_PD_PORT_MAX_COUNT];
@@ -699,8 +696,10 @@ static int anx74xx_rp_control(int port, int rp)
static int anx74xx_tcpm_select_rp_value(int port, int rp)
{
+ /* Keep track of current RP value */
+ tcpci_set_cached_rp(port, rp);
+
/* For ANX3429 cannot get cc correctly when Rp != USB_Default */
- selected_rp[port] = rp;
return EC_SUCCESS;
}
@@ -728,6 +727,9 @@ static int anx74xx_tcpm_set_cc(int port, int pull)
int rv = EC_SUCCESS;
int reg;
+ /* Keep track of current CC pull value */
+ tcpci_set_cached_pull(port, pull);
+
/* Enable CC software Control */
rv = anx74xx_cc_software_ctrl(port, 1);
if (rv)
@@ -758,10 +760,20 @@ static int anx74xx_tcpm_set_cc(int port, int pull)
return rv;
}
-static int anx74xx_tcpm_set_polarity(int port, int polarity)
+static int anx74xx_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity)
{
int reg, mux_state, rv = EC_SUCCESS;
+ /*
+ * TCPCI sets the CC lines based on polarity. If it is set to
+ * no connection then both CC lines are driven, otherwise only
+ * one is driven. This driver does not appear to do this. If
+ * that changes, this would be the location you would want to
+ * adjust the CC lines for the current polarity
+ */
+ if (polarity == POLARITY_NONE)
+ return EC_SUCCESS;
+
rv |= tcpc_read(port, ANX74XX_REG_CC_SOFTWARE_CTRL, &reg);
if (polarity) /* Inform ANX to use CC2 */
reg &= ~ANX74XX_REG_SELECT_CC1;
@@ -836,7 +848,7 @@ static int anx74xx_tcpm_set_rx_enable(int port, int enable)
if (enable) {
reg &= ~(ANX74XX_REG_IRQ_CC_MSG_INT);
anx74xx_tcpm_set_auto_good_crc(port, 1);
- anx74xx_rp_control(port, selected_rp[port]);
+ anx74xx_rp_control(port, tcpci_get_cached_rp(port));
} else {
/* Disable RX message by masking interrupt */
reg |= (ANX74XX_REG_IRQ_CC_MSG_INT);
@@ -1033,6 +1045,9 @@ static int anx74xx_tcpm_init(int port)
{
int rv = 0, reg;
+ /* Start with an unknown connection */
+ tcpci_set_cached_pull(port, TYPEC_CC_OPEN);
+
memset(&anx[port], 0, sizeof(struct anx_state));
/* Bring chip in normal mode to work */
anx74xx_set_power_mode(port, ANX74XX_NORMAL_MODE);
diff --git a/driver/tcpm/fusb302.c b/driver/tcpm/fusb302.c
index c6465cd162..3514b2e865 100644
--- a/driver/tcpm/fusb302.c
+++ b/driver/tcpm/fusb302.c
@@ -11,6 +11,7 @@
#include "fusb302.h"
#include "task.h"
#include "hooks.h"
+#include "tcpci.h"
#include "tcpm.h"
#include "timer.h"
#include "usb_charge.h"
@@ -351,6 +352,9 @@ static int fusb302_tcpm_select_rp_value(int port, int rp)
int rv;
uint8_t vnc, rd;
+ /* Keep track of current RP value */
+ tcpci_set_cached_rp(port, rp);
+
rv = tcpc_read(port, TCPC_REG_CONTROL0, &reg);
if (rv)
return rv;
@@ -383,6 +387,9 @@ static int fusb302_tcpm_init(int port)
{
int reg;
+ /* Start with an unknown connection */
+ tcpci_set_cached_pull(port, TYPEC_CC_OPEN);
+
/* set default */
state[port].cc_polarity = -1;
@@ -485,6 +492,9 @@ static int fusb302_tcpm_set_cc(int port, int pull)
{
int reg;
+ /* Keep track of current CC pull value */
+ tcpci_set_cached_pull(port, pull);
+
/* NOTE: FUSB302 toggles a single pull-up between CC1 and CC2 */
/* NOTE: FUSB302 Does not support Ra. */
switch (pull) {
@@ -553,11 +563,21 @@ static int fusb302_tcpm_set_cc(int port, int pull)
return 0;
}
-static int fusb302_tcpm_set_polarity(int port, int polarity)
+static int fusb302_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity)
{
/* Port polarity : 0 => CC1 is CC line, 1 => CC2 is CC line */
int reg;
+ /*
+ * TCPCI sets the CC lines based on polarity. If it is set to
+ * no connection then both CC lines are driven, otherwise only
+ * one is driven. This driver does not appear to do this. If
+ * that changes, this would be the location you would want to
+ * adjust the CC lines for the current polarity
+ */
+ if (polarity == POLARITY_NONE)
+ return EC_SUCCESS;
+
tcpc_read(port, TCPC_REG_SWITCHES0, &reg);
/* clear VCONN switch bits */
diff --git a/driver/tcpm/it83xx.c b/driver/tcpm/it83xx.c
index 14e7571dc6..dd18bc2f70 100644
--- a/driver/tcpm/it83xx.c
+++ b/driver/tcpm/it83xx.c
@@ -12,6 +12,7 @@
#include "registers.h"
#include "system.h"
#include "task.h"
+#include "tcpci.h"
#include "timer.h"
#include "util.h"
#include "usb_pd.h"
@@ -418,6 +419,9 @@ static int it83xx_set_cc(enum usbpd_port port, int pull)
static int it83xx_tcpm_init(int port)
{
+ /* Start with an unknown connection */
+ tcpci_set_cached_pull(port, TYPEC_CC_OPEN);
+
/* Initialize physical layer */
it83xx_init(port, PD_ROLE_DEFAULT(port));
@@ -441,6 +445,10 @@ static int it83xx_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1,
static int it83xx_tcpm_select_rp_value(int port, int rp_sel)
{
uint8_t rp;
+
+ /* Keep track of current RP value */
+ tcpci_set_cached_rp(port, rp_sel);
+
/*
* bit[3-2]: CC output current (when Rp selected)
* 00: reserved
@@ -467,11 +475,24 @@ static int it83xx_tcpm_select_rp_value(int port, int rp_sel)
static int it83xx_tcpm_set_cc(int port, int pull)
{
+ /* Keep track of current CC pull value */
+ tcpci_set_cached_pull(port, pull);
+
return it83xx_set_cc(port, pull);
}
-static int it83xx_tcpm_set_polarity(int port, int polarity)
+static int it83xx_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity)
{
+ /*
+ * TCPCI sets the CC lines based on polarity. If it is set to
+ * no connection then both CC lines are driven, otherwise only
+ * one is driven. This driver does not appear to do this. If
+ * that changes, this would be the location you would want to
+ * adjust the CC lines for the current polarity
+ */
+ if (polarity == POLARITY_NONE)
+ return EC_SUCCESS;
+
it83xx_select_polarity(port, polarity);
return EC_SUCCESS;
diff --git a/driver/tcpm/mt6370.c b/driver/tcpm/mt6370.c
index 8a50b480f6..26bfdd9690 100644
--- a/driver/tcpm/mt6370.c
+++ b/driver/tcpm/mt6370.c
@@ -32,6 +32,9 @@ static int mt6370_init(int port)
{
int rv, val;
+ /* Start with an unknown connection */
+ tcpci_set_cached_pull(port, TYPEC_CC_OPEN);
+
rv = tcpc_read(port, MT6370_REG_IDLE_CTRL, &val);
/* Only do soft-reset in shipping mode. (b:122017882) */
@@ -138,6 +141,9 @@ static int mt6370_get_cc(int port, enum tcpc_cc_voltage_status *cc1,
static int mt6370_set_cc(int port, int pull)
{
+ /* Keep track of current CC pull value */
+ tcpci_set_cached_pull(port, pull);
+
if (pull == TYPEC_CC_RD)
mt6370_init_cc_params(port, TYPEC_CC_VOLT_RP_DEF);
return tcpci_tcpm_set_cc(port, pull);
@@ -159,10 +165,20 @@ static int mt6370_enter_low_power_mode(int port)
}
#endif
-static int mt6370_set_polarity(int port, int polarity)
+static int mt6370_set_polarity(int port, enum tcpc_cc_polarity polarity)
{
enum tcpc_cc_voltage_status cc1, cc2;
+ /*
+ * TCPCI sets the CC lines based on polarity. If it is set to
+ * no connection then both CC lines are driven, otherwise only
+ * one is driven. This driver does not appear to do this. If
+ * that changes, this would be the location you would want to
+ * adjust the CC lines for the current polarity
+ */
+ if (polarity == POLARITY_NONE)
+ return EC_SUCCESS;
+
mt6370_polarity = polarity;
mt6370_get_cc(port, &cc1, &cc2);
return tcpci_tcpm_set_polarity(port, polarity);
diff --git a/driver/tcpm/nct38xx.c b/driver/tcpm/nct38xx.c
index 6630d570c9..1281c16d71 100644
--- a/driver/tcpm/nct38xx.c
+++ b/driver/tcpm/nct38xx.c
@@ -22,25 +22,14 @@
#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-#define POLARITY_NORMAL 0
-#define POLARITY_FLIPPED 1
-#define POLARITY_NONE 3
-
-static int cable_polarity[CONFIG_USB_PD_PORT_MAX_COUNT];
static unsigned char txBuf[33];
static unsigned char rxBuf[33];
-/* Save the selected rp value */
-static int selected_rp[CONFIG_USB_PD_PORT_MAX_COUNT];
-static int selected_pull[CONFIG_USB_PD_PORT_MAX_COUNT];
static int nct38xx_tcpm_init(int port)
{
int rv = 0;
int reg;
- cable_polarity[port] = POLARITY_NONE;
- selected_pull[port] = TYPEC_CC_OPEN;
-
rv = tcpci_tcpm_init(port);
if (rv)
return rv;
@@ -106,103 +95,6 @@ static int nct38xx_tcpm_init(int port)
return rv;
}
-static int tcpci_nct38xx_check_cable_polarity(int port)
-{
- int cc, rv;
-
- /* Try to check the polarity */
- rv = tcpc_read(port, TCPC_REG_CC_STATUS, &cc);
- if (rv)
- return rv;
-
- if (TCPC_REG_CC_STATUS_TERM(cc)) {
- /* TCPC is presenting RD (Sink mode) */
- if ((TCPC_REG_CC_STATUS_CC1(cc) != TYPEC_CC_VOLT_OPEN) &&
- (TCPC_REG_CC_STATUS_CC2(cc) == TYPEC_CC_VOLT_OPEN)) {
- /* CC1 active && CC2 open */
- cable_polarity[port] = POLARITY_NORMAL;
- }
- if ((TCPC_REG_CC_STATUS_CC1(cc) == TYPEC_CC_VOLT_OPEN) &&
- (TCPC_REG_CC_STATUS_CC2(cc) != TYPEC_CC_VOLT_OPEN)) {
- /* CC1 open && CC2 active */
- cable_polarity[port] = POLARITY_FLIPPED;
- }
- } else {
- /* TCPC is presenting RP (Source mode) */
- if ((TCPC_REG_CC_STATUS_CC1(cc) == TYPEC_CC_VOLT_RD) &&
- (TCPC_REG_CC_STATUS_CC2(cc) != TYPEC_CC_VOLT_RD)) {
- /* CC1 active && CC2 open */
- cable_polarity[port] = POLARITY_NORMAL;
- }
- if ((TCPC_REG_CC_STATUS_CC1(cc) != TYPEC_CC_VOLT_RD) &&
- (TCPC_REG_CC_STATUS_CC2(cc) == TYPEC_CC_VOLT_RD)) {
- /* CC1 open && CC2 active */
- cable_polarity[port] = POLARITY_FLIPPED;
- }
- }
- return rv;
-}
-
-int tcpci_nct38xx_select_rp_value(int port, int rp)
-{
- selected_rp[port] = rp;
- return EC_SUCCESS;
-}
-
- /*
- * TODO(crbug.com/951681): This code can be simplified once that bug is fixed.
- */
-static int tcpci_nct38xx_set_cc(int port, int pull)
-{
- int rv;
-
- selected_pull[port] = pull;
-
- if (cable_polarity[port] == POLARITY_NONE) {
- rv = tcpci_nct38xx_check_cable_polarity(port);
- if (rv)
- return rv;
- }
-
- if (cable_polarity[port] == POLARITY_NORMAL) {
- rv = tcpc_write(port, TCPC_REG_ROLE_CTRL,
- TCPC_REG_ROLE_CTRL_SET(0, selected_rp[port],
- pull, TYPEC_CC_OPEN));
- } else if (cable_polarity[port] == POLARITY_FLIPPED) {
- rv = tcpc_write(port, TCPC_REG_ROLE_CTRL,
- TCPC_REG_ROLE_CTRL_SET(0, selected_rp[port],
- TYPEC_CC_OPEN, pull));
- } else {
- return -1;
- }
-
- return rv;
-}
-
-/*
- * tcpci_nct38xx_set_cc() only sets the pull resistor on one CC line according
- * to polarity. This is correct when attached, but on disconnect we need to
- * set the pull resistor on both CC lines, since polarity is no longer known
- * (unless DRP toggle is enabled, since that will take care of setting both
- * CC lines to do the toggling).
- * TODO(crbug.com/951681): This code can be removed once that bug is fixed.
- */
-static void disconnect_hook(void)
-{
- int port = TASK_ID_TO_PD_PORT(task_get_current());
- int rv;
-
- if (pd_get_dual_role(port) != PD_DRP_TOGGLE_ON
- && selected_pull[port] != TYPEC_CC_OPEN) {
- rv = tcpc_write(port, TCPC_REG_ROLE_CTRL,
- TCPC_REG_ROLE_CTRL_SET(0, selected_rp[port],
- selected_pull[port], selected_pull[port]));
- if (rv)
- CPRINTS("C%d failed to set pull on disconnect", port);
- }
-}
-DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, disconnect_hook, HOOK_PRIO_DEFAULT);
-
static int tcpci_nct38xx_get_cc(int port, enum tcpc_cc_voltage_status *cc1,
enum tcpc_cc_voltage_status *cc2)
{
@@ -229,13 +121,6 @@ static int tcpci_nct38xx_get_cc(int port, enum tcpc_cc_voltage_status *cc1,
return rv;
}
-int tcpci_nct38xx_drp_toggle(int port)
-{
- cable_polarity[port] = POLARITY_NONE;
-
- return tcpci_tcpc_drp_toggle(port);
-}
-
int tcpci_nct38xx_transmit(int port, enum tcpm_transmit_type type,
uint16_t header, const uint32_t *data)
{
@@ -328,8 +213,8 @@ const struct tcpm_drv nct38xx_tcpm_drv = {
#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC
.get_vbus_level = &tcpci_tcpm_get_vbus_level,
#endif
- .select_rp_value = &tcpci_nct38xx_select_rp_value,
- .set_cc = &tcpci_nct38xx_set_cc,
+ .select_rp_value = &tcpci_tcpm_select_rp_value,
+ .set_cc = &tcpci_tcpm_set_cc,
.set_polarity = &tcpci_tcpm_set_polarity,
.set_vconn = &tcpci_tcpm_set_vconn,
.set_msg_header = &tcpci_tcpm_set_msg_header,
@@ -343,7 +228,7 @@ const struct tcpm_drv nct38xx_tcpm_drv = {
.tcpc_enable_auto_discharge_disconnect =
&tcpci_tcpc_enable_auto_discharge_disconnect,
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
- .drp_toggle = &tcpci_nct38xx_drp_toggle,
+ .drp_toggle = &tcpci_tcpc_drp_toggle,
#endif
#ifdef CONFIG_USBC_PPC
.set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl,
diff --git a/driver/tcpm/stub.c b/driver/tcpm/stub.c
index 3626f148fc..fcc460a8c6 100644
--- a/driver/tcpm/stub.c
+++ b/driver/tcpm/stub.c
@@ -63,7 +63,7 @@ int tcpm_set_cc(int port, int pull)
return tcpc_set_cc(port, pull);
}
-int tcpm_set_polarity(int port, int polarity)
+int tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity)
{
return tcpc_set_polarity(port, polarity);
}
diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c
index 5d16de206a..a9a62bd1ce 100644
--- a/driver/tcpm/tcpci.c
+++ b/driver/tcpm/tcpci.c
@@ -30,9 +30,9 @@ static int rx_en[CONFIG_USB_PD_PORT_MAX_COUNT];
#endif
static int tcpc_vbus[CONFIG_USB_PD_PORT_MAX_COUNT];
-/* Save the selected rp value */
-static int selected_rp[CONFIG_USB_PD_PORT_MAX_COUNT];
-
+/* Cached RP/PULL role values */
+static int cached_rp[CONFIG_USB_PD_PORT_MAX_COUNT];
+static enum tcpc_cc_pull cached_pull[CONFIG_USB_PD_PORT_MAX_COUNT];
#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
int tcpc_addr_write(int port, int i2c_addr, int reg, int val)
@@ -159,6 +159,7 @@ int tcpc_update8(int port, int reg,
pd_device_accessed(port);
return rv;
}
+
int tcpc_update16(int port, int reg,
uint16_t mask,
enum mask_update_action action)
@@ -177,6 +178,33 @@ int tcpc_update16(int port, int reg,
#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */
+/*
+ * TCPCI maintains and uses cached values for the RP and
+ * last used PULL values. Since TCPC drivers are allowed
+ * to use some of the TCPCI functionality, these global
+ * cached values need to be maintained in case part of the
+ * used TCPCI functionality relies on these values
+ */
+void tcpci_set_cached_rp(int port, int rp)
+{
+ cached_rp[port] = rp;
+}
+
+int tcpci_get_cached_rp(int port)
+{
+ return cached_rp[port];
+}
+
+void tcpci_set_cached_pull(int port, enum tcpc_cc_pull pull)
+{
+ cached_pull[port] = pull;
+}
+
+enum tcpc_cc_pull tcpci_get_cached_pull(int port)
+{
+ return cached_pull[port];
+}
+
static int init_alert_mask(int port)
{
int rv;
@@ -232,6 +260,40 @@ static int clear_power_status_mask(int port)
return tcpc_write(port, TCPC_REG_POWER_STATUS_MASK, 0);
}
+static int tcpci_tcpm_get_power_status(int port, int *status)
+{
+ return tcpc_read(port, TCPC_REG_POWER_STATUS, status);
+}
+
+int tcpci_tcpm_select_rp_value(int port, int rp)
+{
+ /* Keep track of current RP value */
+ tcpci_set_cached_rp(port, rp);
+
+ return EC_SUCCESS;
+}
+
+void tcpci_tcpc_discharge_vbus(int port, int enable)
+{
+ tcpc_update8(port,
+ TCPC_REG_POWER_CTRL,
+ TCPC_REG_POWER_CTRL_FORCE_DISCHARGE,
+ (enable) ? MASK_SET : MASK_CLR);
+}
+
+/*
+ * Auto Discharge Disconnect is supposed to be enabled when we
+ * are connected and disabled after we are disconnected and
+ * VBus is at SafeV0
+ */
+void tcpci_tcpc_enable_auto_discharge_disconnect(int port, int enable)
+{
+ tcpc_update8(port,
+ TCPC_REG_POWER_CTRL,
+ TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT,
+ (enable) ? MASK_SET : MASK_CLR);
+}
+
int tcpci_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1,
enum tcpc_cc_voltage_status *cc2)
{
@@ -262,51 +324,39 @@ int tcpci_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1,
return rv;
}
-static int tcpci_tcpm_get_power_status(int port, int *status)
+int tcpci_tcpm_set_cc(int port, int pull)
{
- return tcpc_read(port, TCPC_REG_POWER_STATUS, status);
-}
+ int cc1, cc2;
+ enum tcpc_cc_polarity polarity;
-int tcpci_tcpm_select_rp_value(int port, int rp)
-{
- selected_rp[port] = rp;
- return EC_SUCCESS;
-}
+ cc1 = cc2 = pull;
-void tcpci_tcpc_discharge_vbus(int port, int enable)
-{
- tcpc_update8(port,
- TCPC_REG_POWER_CTRL,
- TCPC_REG_POWER_CTRL_FORCE_DISCHARGE,
- (enable) ? MASK_SET : MASK_CLR);
-}
+ /* Keep track of current CC pull value */
+ tcpci_set_cached_pull(port, pull);
-/*
- * Auto Discharge Disconnect is supposed to be enabled when we
- * are connected and disabled after we are disconnected and
- * VBus is at SafeV0
- */
-void tcpci_tcpc_enable_auto_discharge_disconnect(int port, int enable)
-{
- tcpc_update8(port,
- TCPC_REG_POWER_CTRL,
- TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT,
- (enable) ? MASK_SET : MASK_CLR);
+ /*
+ * Only drive one CC line when attached crbug.com/951681
+ * and drive both when unattached.
+ */
+ polarity = pd_get_polarity(port);
+ if (polarity == POLARITY_CC1)
+ cc2 = TYPEC_CC_OPEN;
+ else if (polarity == POLARITY_CC2)
+ cc1 = TYPEC_CC_OPEN;
+
+ return tcpc_write(port, TCPC_REG_ROLE_CTRL,
+ TCPC_REG_ROLE_CTRL_SET(0,
+ tcpci_get_cached_rp(port),
+ cc1, cc2));
}
+#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
static int set_role_ctrl(int port, int toggle, int rp, int pull)
{
return tcpc_write(port, TCPC_REG_ROLE_CTRL,
TCPC_REG_ROLE_CTRL_SET(toggle, rp, pull, pull));
}
-int tcpci_tcpm_set_cc(int port, int pull)
-{
- /* Set manual control, and set both CC lines to the same pull */
- return set_role_ctrl(port, 0, selected_rp[port], pull);
-}
-
-#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
int tcpci_tcpc_drp_toggle(int port)
{
int rv;
@@ -329,8 +379,22 @@ int tcpci_enter_low_power_mode(int port)
}
#endif
-int tcpci_tcpm_set_polarity(int port, int polarity)
+int tcpci_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity)
{
+ int rv;
+
+ /*
+ * TCPCI sets the CC lines based on polarity. If it is set to
+ * no connection then both CC lines are driven, otherwise only
+ * one is driven.
+ */
+ rv = tcpm_set_cc(port, tcpci_get_cached_pull(port));
+ if (rv)
+ return rv;
+
+ if (polarity == POLARITY_NONE)
+ return EC_SUCCESS;
+
return tcpc_update8(port,
TCPC_REG_TCPC_CTRL,
TCPC_REG_TCPC_CTRL_SET(1),
@@ -873,6 +937,9 @@ int tcpci_tcpm_init(int port)
int power_status;
int tries = TCPM_INIT_TRIES;
+ /* Start with an unknown connection */
+ tcpci_set_cached_pull(port, TYPEC_CC_OPEN);
+
if (port >= board_get_usb_pd_port_count())
return EC_ERROR_INVAL;
diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h
index 566e7905e9..c6b392ba66 100644
--- a/driver/tcpm/tcpci.h
+++ b/driver/tcpm/tcpci.h
@@ -8,6 +8,7 @@
#ifndef __CROS_EC_USB_PD_TCPM_TCPCI_H
#define __CROS_EC_USB_PD_TCPM_TCPCI_H
+#include "config.h"
#include "tcpm.h"
#include "usb_mux.h"
#include "usb_pd_tcpm.h"
@@ -55,13 +56,20 @@
#define TCPC_REG_TCPC_CTRL_POLARITY(reg) ((reg) & 0x1)
#define TCPC_REG_ROLE_CTRL 0x1a
+#define TCPC_REG_ROLE_CTRL_DRP_MASK BIT(6)
+#define TCPC_REG_ROLE_CTRL_RP_MASK (BIT(5)|BIT(4))
+#define TCPC_REG_ROLE_CTRL_CC2_MASK (BIT(3)|BIT(2))
+#define TCPC_REG_ROLE_CTRL_CC1_MASK (BIT(1)|BIT(0))
#define TCPC_REG_ROLE_CTRL_SET(drp, rp, cc1, cc2) \
((drp) << 6 | (rp) << 4 | (cc2) << 2 | (cc1))
-#define TCPC_REG_ROLE_CTRL_DRP(reg) (((reg) & 0x40) >> 6)
-#define TCPC_REG_ROLE_CTRL_RP_MASK 0x30
-#define TCPC_REG_ROLE_CTRL_RP(reg) (((reg) & TCPC_REG_ROLE_CTRL_RP_MASK) >> 4)
-#define TCPC_REG_ROLE_CTRL_CC2(reg) (((reg) & 0xc) >> 2)
-#define TCPC_REG_ROLE_CTRL_CC1(reg) ((reg) & 0x3)
+#define TCPC_REG_ROLE_CTRL_DRP(reg) \
+ (((reg) & TCPC_REG_ROLE_CTRL_DRP_MASK) >> 6)
+#define TCPC_REG_ROLE_CTRL_RP(reg) \
+ (((reg) & TCPC_REG_ROLE_CTRL_RP_MASK) >> 4)
+#define TCPC_REG_ROLE_CTRL_CC2(reg) \
+ (((reg) & TCPC_REG_ROLE_CTRL_CC2_MASK) >> 2)
+#define TCPC_REG_ROLE_CTRL_CC1(reg) \
+ ((reg) & TCPC_REG_ROLE_CTRL_CC1_MASK)
#define TCPC_REG_FAULT_CTRL 0x1b
#define TCPC_REG_FAULT_CTRL_VBUS_OVP_FAULT_DIS BIT(1)
@@ -75,12 +83,20 @@
#define TCPC_REG_POWER_CTRL_VCONN(reg) ((reg) & 0x1)
#define TCPC_REG_CC_STATUS 0x1d
-#define TCPC_REG_CC_STATUS_LOOK4CONNECTION(reg) ((reg & 0x20) >> 5)
+#define TCPC_REG_CC_STATUS_LOOK4CONNECTION_MASK BIT(5)
+#define TCPC_REG_CC_STATUS_CONNECT_RESULT_MASK BIT(4)
+#define TCPC_REG_CC_STATUS_CC2_STATE_MASK (BIT(3)|BIT(2))
+#define TCPC_REG_CC_STATUS_CC1_STATE_MASK (BIT(1)|BIT(0))
#define TCPC_REG_CC_STATUS_SET(term, cc1, cc2) \
((term) << 4 | ((cc2) & 0x3) << 2 | ((cc1) & 0x3))
-#define TCPC_REG_CC_STATUS_TERM(reg) (((reg) & 0x10) >> 4)
-#define TCPC_REG_CC_STATUS_CC2(reg) (((reg) & 0xc) >> 2)
-#define TCPC_REG_CC_STATUS_CC1(reg) ((reg) & 0x3)
+#define TCPC_REG_CC_STATUS_LOOK4CONNECTION(reg) \
+ ((reg & TCPC_REG_CC_STATUS_LOOK4CONNECTION_MASK) >> 5)
+#define TCPC_REG_CC_STATUS_TERM(reg) \
+ (((reg) & TCPC_REG_CC_STATUS_CONNECT_RESULT_MASK) >> 4)
+#define TCPC_REG_CC_STATUS_CC2(reg) \
+ (((reg) & TCPC_REG_CC_STATUS_CC2_STATE_MASK) >> 2)
+#define TCPC_REG_CC_STATUS_CC1(reg) \
+ ((reg) & TCPC_REG_CC_STATUS_CC1_STATE_MASK)
#define TCPC_REG_POWER_STATUS 0x1e
#define TCPC_REG_POWER_STATUS_MASK_ALL 0xff
@@ -158,6 +174,11 @@
extern const struct tcpm_drv tcpci_tcpm_drv;
extern const struct usb_mux_driver tcpci_tcpm_usb_mux_driver;
+void tcpci_set_cached_rp(int port, int rp);
+int tcpci_get_cached_rp(int port);
+void tcpci_set_cached_pull(int port, enum tcpc_cc_pull pull);
+enum tcpc_cc_pull tcpci_get_cached_pull(int port);
+
void tcpci_tcpc_alert(int port);
int tcpci_tcpm_init(int port);
int tcpci_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1,
@@ -165,7 +186,7 @@ int tcpci_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1,
int tcpci_tcpm_get_vbus_level(int port);
int tcpci_tcpm_select_rp_value(int port, int rp);
int tcpci_tcpm_set_cc(int port, int pull);
-int tcpci_tcpm_set_polarity(int port, int polarity);
+int tcpci_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity);
int tcpci_tcpm_set_vconn(int port, int enable);
int tcpci_tcpm_set_msg_header(int port, int power_role, int data_role);
int tcpci_tcpm_set_rx_enable(int port, int enable);
diff --git a/driver/tcpm/tcpm.h b/driver/tcpm/tcpm.h
index 118275ba3d..ea7367d5c0 100644
--- a/driver/tcpm/tcpm.h
+++ b/driver/tcpm/tcpm.h
@@ -90,6 +90,7 @@ static inline int tcpc_update8(int port, int reg,
tcpc_config[port].i2c_info.addr_flags,
reg, mask, action);
}
+
static inline int tcpc_update16(int port, int reg,
uint16_t mask,
enum mask_update_action action)
@@ -99,7 +100,6 @@ static inline int tcpc_update16(int port, int reg,
reg, mask, action);
}
-
#else /* !CONFIG_USB_PD_TCPC_LOW_POWER */
int tcpc_addr_write(int port, int i2c_addr, int reg, int val);
int tcpc_write16(int port, int reg, int val);
@@ -178,7 +178,7 @@ static inline int tcpm_set_cc(int port, int pull)
return tcpc_config[port].drv->set_cc(port, pull);
}
-static inline int tcpm_set_polarity(int port, int polarity)
+static inline int tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity)
{
return tcpc_config[port].drv->set_polarity(port, polarity);
}
@@ -344,17 +344,17 @@ int tcpm_set_cc(int port, int pull);
* Set polarity
*
* @param port Type-C port number
- * @param polarity 0=> transmit on CC1, 1=> transmit on CC2
+ * @param polarity port polarity
*
* @return EC_SUCCESS or error
*/
-int tcpm_set_polarity(int port, int polarity);
+int tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity);
/**
* Set Vconn.
*
* @param port Type-C port number
- * @param polarity Polarity of the CC line to read
+ * @param enable Enable/Disable Vconn
*
* @return EC_SUCCESS or error
*/
diff --git a/include/usb_common.h b/include/usb_common.h
index 13bebc7915..b56cd2a38f 100644
--- a/include/usb_common.h
+++ b/include/usb_common.h
@@ -57,12 +57,12 @@ int usb_get_battery_soc(void);
* Returns type C current limit (mA), potentially with the DTS flag, based upon
* states of the CC lines on the partner side.
*
- * @param polarity 0 if cc1 is primary, otherwise 1
+ * @param polarity port polarity
* @param cc1 value of CC1 set by tcpm_get_cc
* @param cc2 value of CC2 set by tcpm_get_cc
* @return current limit (mA) with DTS flag set if appropriate
*/
-typec_current_t usb_get_typec_current_limit(enum pd_cc_polarity_type polarity,
+typec_current_t usb_get_typec_current_limit(enum tcpc_cc_polarity polarity,
enum tcpc_cc_voltage_status cc1, enum tcpc_cc_voltage_status cc2);
/**
@@ -70,9 +70,19 @@ typec_current_t usb_get_typec_current_limit(enum pd_cc_polarity_type polarity,
*
* @param cc1 value of CC1 set by tcpm_get_cc
* @param cc2 value of CC2 set by tcpm_get_cc
- * @return 0 if cc1 is primary, else 1 for cc2 being primary
+ * @return polarity
*/
-enum pd_cc_polarity_type get_snk_polarity(enum tcpc_cc_voltage_status cc1,
+enum tcpc_cc_polarity get_snk_polarity(enum tcpc_cc_voltage_status cc1,
+ enum tcpc_cc_voltage_status cc2);
+
+/**
+ * Returns the polarity of a Source.
+ *
+ * @param cc1 value of CC1 set by tcpm_get_cc
+ * @param cc2 value of CC2 set by tcpm_get_cc
+ * @return polarity
+ */
+enum tcpc_cc_polarity get_src_polarity(enum tcpc_cc_voltage_status cc1,
enum tcpc_cc_voltage_status cc2);
/**
diff --git a/include/usb_pd.h b/include/usb_pd.h
index c2d843863a..74cd8f27c7 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -1370,12 +1370,6 @@ enum pd_data_msg_type {
PD_DATA_VENDOR_DEF = 15,
};
-/* CC Polarity type */
-enum pd_cc_polarity_type {
- POLARITY_CC1 = 0,
- POLARITY_CC2 = 1,
-};
-
/* Protocol revision */
enum pd_rev_type {
PD_REV10,
@@ -2319,7 +2313,7 @@ void pd_transmit_complete(int port, int status);
*
* @param port USB-C port number
*/
-int pd_get_polarity(int port);
+enum tcpc_cc_polarity pd_get_polarity(int port);
/**
* Get port partner data swap capable status
diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h
index 70ef7a17cb..9d6cbec160 100644
--- a/include/usb_pd_tcpm.h
+++ b/include/usb_pd_tcpm.h
@@ -49,6 +49,12 @@ enum tcpc_rp_value {
TYPEC_RP_RESERVED = 3,
};
+enum tcpc_cc_polarity {
+ POLARITY_NONE = -1,
+ POLARITY_CC1 = 0,
+ POLARITY_CC2 = 1,
+};
+
enum tcpm_transmit_type {
TCPC_TX_SOP = 0,
TCPC_TX_SOP_PRIME = 1,
@@ -189,17 +195,17 @@ struct tcpm_drv {
* Set polarity
*
* @param port Type-C port number
- * @param polarity 0=> transmit on CC1, 1=> transmit on CC2
+ * @param polarity port polarity
*
* @return EC_SUCCESS or error
*/
- int (*set_polarity)(int port, int polarity);
+ int (*set_polarity)(int port, enum tcpc_cc_polarity polarity);
/**
* Set Vconn.
*
* @param port Type-C port number
- * @param polarity Polarity of the CC line to read
+ * @param enable Enable/Disable Vconn
*
* @return EC_SUCCESS or error
*/
diff --git a/include/usb_tc_sm.h b/include/usb_tc_sm.h
index 614269d5cd..4782dcbfe9 100644
--- a/include/usb_tc_sm.h
+++ b/include/usb_tc_sm.h
@@ -279,7 +279,7 @@ void pd_request_vconn_swap_off(int port);
* @param cc2 value of CC2 set by tcpm_get_cc
* @return 0 if cc1 is connected, else 1 for cc2
*/
-enum pd_cc_polarity_type get_snk_polarity(enum tcpc_cc_voltage_status cc1,
+enum tcpc_cc_polarity get_snk_polarity(enum tcpc_cc_voltage_status cc1,
enum tcpc_cc_voltage_status cc2);
/**