diff options
-rw-r--r-- | common/usb_common.c | 16 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 61 | ||||
-rw-r--r-- | common/usbc/usb_tc_drp_acc_trysrc_sm.c | 2 | ||||
-rw-r--r-- | driver/tcpm/anx74xx.c | 27 | ||||
-rw-r--r-- | driver/tcpm/fusb302.c | 22 | ||||
-rw-r--r-- | driver/tcpm/it83xx.c | 23 | ||||
-rw-r--r-- | driver/tcpm/mt6370.c | 18 | ||||
-rw-r--r-- | driver/tcpm/nct38xx.c | 121 | ||||
-rw-r--r-- | driver/tcpm/stub.c | 2 | ||||
-rw-r--r-- | driver/tcpm/tcpci.c | 141 | ||||
-rw-r--r-- | driver/tcpm/tcpci.h | 41 | ||||
-rw-r--r-- | driver/tcpm/tcpm.h | 10 | ||||
-rw-r--r-- | include/usb_common.h | 18 | ||||
-rw-r--r-- | include/usb_pd.h | 8 | ||||
-rw-r--r-- | include/usb_pd_tcpm.h | 12 | ||||
-rw-r--r-- | include/usb_tc_sm.h | 2 |
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, ®); 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, ®); 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, ®); /* 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); /** |