diff options
-rw-r--r-- | common/usb_pd_protocol.c | 5 | ||||
-rw-r--r-- | common/usbc/usb_tc_drp_acc_trysrc_sm.c | 9 | ||||
-rw-r--r-- | driver/tcpm/nct38xx.c | 150 | ||||
-rw-r--r-- | driver/tcpm/tcpm.h | 6 | ||||
-rw-r--r-- | include/usb_pd.h | 9 | ||||
-rw-r--r-- | include/usb_pd_tcpm.h | 24 |
6 files changed, 147 insertions, 56 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 2658ac9641..d248c67036 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -2668,11 +2668,6 @@ enum tcpc_cc_polarity pd_get_polarity(int port) return pd[port].polarity; } -void pd_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - pd[port].polarity = polarity; -} - bool pd_get_partner_data_swap_capable(int port) { /* return data swap capable status of port partner */ diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c index 165be89450..5fd8d2727f 100644 --- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c +++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c @@ -767,11 +767,6 @@ enum tcpc_cc_polarity pd_get_polarity(int port) return tc[port].polarity; } -void pd_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - tc[port].polarity = polarity; -} - enum pd_data_role pd_get_data_role(int port) { return tc[port].data_role; @@ -2888,7 +2883,7 @@ static void tc_drp_auto_toggle_run(const int port) * the CC lines to what it is thinking is best or it goes * directly back to unattached. */ - tcpm_auto_toggle_connection(port, cc1, cc2); + tcpm_drp_toggle_connection(port, cc1, cc2); set_state_tc(port, TC_ATTACH_WAIT_SNK); break; case DRP_TC_UNATTACHED_SRC: @@ -2898,7 +2893,7 @@ static void tc_drp_auto_toggle_run(const int port) * the CC lines to what it is thinking is best or it goes * directly back to unattached. */ - tcpm_auto_toggle_connection(port, cc1, cc2); + tcpm_drp_toggle_connection(port, cc1, cc2); set_state_tc(port, TC_ATTACH_WAIT_SRC); break; case DRP_TC_DRP_AUTO_TOGGLE: diff --git a/driver/tcpm/nct38xx.c b/driver/tcpm/nct38xx.c index 9c874f5e87..0f27661371 100644 --- a/driver/tcpm/nct38xx.c +++ b/driver/tcpm/nct38xx.c @@ -14,7 +14,6 @@ #include "task.h" #include "tcpci.h" #include "usb_common.h" -#include "usb_pd.h" #if !defined(CONFIG_USB_PD_TCPM_TCPCI) #error "NCT38XX is using part of standard TCPCI control" @@ -120,29 +119,140 @@ static void nct38xx_tcpc_alert(int port) } #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE -static void nct38xx_auto_toggle_connection(int port, +static void nct38xx_drp_toggle_connection(int port, enum tcpc_cc_voltage_status cc1, enum tcpc_cc_voltage_status cc2) { - int polarity; + int rv; + int role; - /* - * Get the current polarity so we can make sure the - * PD stack will set the CC lines as we expect and - * not to setting both CC lines the same due to - * NO-POLARITY still being set in the cache. This - * will cause this chip to go back to searching - * auto toggle with an open on both CC lines. - * - * TODO(b/149415919): Consider trying to clear the DRP - * mode instead of changing the polarity - */ - if (cc_is_rp(cc1) || cc_is_rp(cc2)) - polarity = get_snk_polarity(cc1, cc2); - else - polarity = get_src_polarity(cc1, cc2); + /* Get the ROLE CONTROL value */ + rv = tcpc_read(port, TCPC_REG_ROLE_CTRL, &role); + if (rv) { + CPRINTS("C%d: %s failed to read ROLE", + port, __func__); + return; + } + + if (role & TCPC_REG_ROLE_CTRL_DRP_MASK) { + /* TODO(b/149593609) get an understanding from Nuvoton + * why this is the way it works. + * + * If DRP is set, the CC pins shall stay in + * Potential_Connect_as_Src or Potential_Connect_as_Sink + * until directed otherwise. + * + * From TCPCIr2 figure 4-20 DRP Connection Detection + * Determine CC & VCONN: + * Set RC.CC1 & RC.CC2 per potential connect decision + * Set RC.DRP=0 + * Set TCPC_CONTROl.PlugOrientation + * Set PC.AutoDischargeDisconnect=1 & PC.EnableVconn + */ + int ctrl; + enum tcpc_cc_polarity polarity; + enum tcpc_cc_voltage_status cc1_pull, cc2_pull; + enum tcpc_rp_value rp = TYPEC_RP_USB; + + switch (cc1) { + case TYPEC_CC_VOLT_OPEN: + cc1_pull = TYPEC_CC_OPEN; + break; + case TYPEC_CC_VOLT_RA: + cc1_pull = TYPEC_CC_RA; + break; + case TYPEC_CC_VOLT_RD: + cc1_pull = TYPEC_CC_RD; + break; + case TYPEC_CC_VOLT_RP_DEF: + case TYPEC_CC_VOLT_RP_1_5: + case TYPEC_CC_VOLT_RP_3_0: + rp = cc1 - TYPEC_CC_VOLT_RP_DEF; + cc1_pull = TYPEC_CC_RP; + break; + default: + CPRINTS("C%d: %s Invalid CC1 Voltage presented", + port, __func__); + return; + } + + switch (cc2) { + case TYPEC_CC_VOLT_OPEN: + cc2_pull = TYPEC_CC_OPEN; + break; + case TYPEC_CC_VOLT_RA: + cc2_pull = TYPEC_CC_RA; + break; + case TYPEC_CC_VOLT_RD: + cc2_pull = TYPEC_CC_RD; + break; + case TYPEC_CC_VOLT_RP_DEF: + case TYPEC_CC_VOLT_RP_1_5: + case TYPEC_CC_VOLT_RP_3_0: + rp = cc2 - TYPEC_CC_VOLT_RP_DEF; + cc2_pull = TYPEC_CC_RP; + break; + default: + CPRINTS("C%d: %s Invalid CC2 Voltage presented", + port, __func__); + return; + } - pd_set_polarity(port, polarity); + /* Set the CC lines */ + rv = tcpc_write(port, TCPC_REG_ROLE_CTRL, + TCPC_REG_ROLE_CTRL_SET(0, + rp, cc1_pull, cc2_pull)); + if (rv) { + CPRINTS("C%d: %s failed to write ROLE", + port, __func__); + return; + } + + /* Set the polarity */ + if (cc_is_rp(cc1) || cc_is_rp(cc2)) + polarity = get_snk_polarity(cc1, cc2); + else + polarity = get_src_polarity(cc1, cc2); + nct38xx_tcpm_drv.set_polarity(port, polarity); + + /* Set/Clear auto discharge disconnect */ + rv = tcpc_read(port, TCPC_REG_POWER_CTRL, &ctrl); + if (rv) { + CPRINTS("C%d: %s failed to read POWER_CTRL", + port, __func__); + return; + } + + if (TCPC_REG_POWER_CTRL_VCONN(ctrl)) + ctrl |= TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT; + else + ctrl &= ~TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT; + + rv = tcpc_write(port, + TCPC_REG_POWER_CTRL, + ctrl); + if (rv) { + CPRINTS("C%d: %s failed to write POWER_CTRL", + port, __func__); + return; + } + } else { + /* + * We left auto-toggle and no longer have DRP set. This + * would happen if DRP was turned off and we did not have + * a connection. We have to manually turn off that we + * are looking for a connection. + */ + rv = tcpc_update8(port, + TCPC_REG_TCPC_CTRL, + TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT, + MASK_CLR); + if (rv) { + CPRINTS("C%d: %s failed to clear Look4Connection", + port, __func__); + return; + } + } } #endif @@ -169,7 +279,7 @@ const struct tcpm_drv nct38xx_tcpm_drv = { &tcpci_tcpc_enable_auto_discharge_disconnect, #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE .drp_toggle = &tcpci_tcpc_drp_toggle, - .tcpc_auto_toggle_connection = &nct38xx_auto_toggle_connection, + .drp_toggle_connection = &nct38xx_drp_toggle_connection, #endif #ifdef CONFIG_USBC_PPC .set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl, diff --git a/driver/tcpm/tcpm.h b/driver/tcpm/tcpm.h index 2b1368e483..61a3a0f8e3 100644 --- a/driver/tcpm/tcpm.h +++ b/driver/tcpm/tcpm.h @@ -258,14 +258,14 @@ static inline int tcpm_enable_drp_toggle(int port) return tcpc_config[port].drv->drp_toggle(port); } -static inline void tcpm_auto_toggle_connection(int port, +static inline void tcpm_drp_toggle_connection(int port, enum tcpc_cc_voltage_status cc1, enum tcpc_cc_voltage_status cc2) { const struct tcpm_drv *tcpc = tcpc_config[port].drv; - if (tcpc->tcpc_auto_toggle_connection) - tcpc->tcpc_auto_toggle_connection(port, cc1, cc2); + if (tcpc->drp_toggle_connection) + tcpc->drp_toggle_connection(port, cc1, cc2); } #endif diff --git a/include/usb_pd.h b/include/usb_pd.h index d17d071ebf..b6113b3236 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -2284,15 +2284,6 @@ void pd_transmit_complete(int port, int status); enum tcpc_cc_polarity pd_get_polarity(int port); /** - * Set port polarity. This is cached by the PD stack and - * some TCPCI events may need to alter this cached value. - * - * @param port USB-C port number - * @param polarity current polarity - */ -void pd_set_polarity(int port, enum tcpc_cc_polarity polarity); - -/** * Get port partner data swap capable status * * @param port USB-C port number diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h index 9c9753ad90..d0953ab74e 100644 --- a/include/usb_pd_tcpm.h +++ b/include/usb_pd_tcpm.h @@ -327,6 +327,15 @@ struct tcpm_drv { #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE /** + * Enable TCPC auto DRP toggling. + * + * @param port Type-C port number + * + * @return EC_SUCCESS or error + */ + int (*drp_toggle)(int port); + + /** * Auto Toggle Connection * There is a connection while performing auto-toggle. * Allow a driver to do any work required to leave the @@ -336,18 +345,9 @@ struct tcpm_drv { * @param cc1 enum tcpc_cc_pull of CC1 * @param cc2 enum tcpc_cc_pull of CC2 */ - void (*tcpc_auto_toggle_connection)(int port, - enum tcpc_cc_voltage_status cc1, - enum tcpc_cc_voltage_status cc2); - - /** - * Enable TCPC auto DRP toggling. - * - * @param port Type-C port number - * - * @return EC_SUCCESS or error - */ - int (*drp_toggle)(int port); + void (*drp_toggle_connection)(int port, + enum tcpc_cc_voltage_status cc1, + enum tcpc_cc_voltage_status cc2); #endif /** |