@@ -477,7 +477,9 @@ struct tcpm_port {
477477
478478 /* Alternate mode data */
479479 struct pd_mode_data mode_data ;
480+ struct pd_mode_data mode_data_prime ;
480481 struct typec_altmode * partner_altmode [ALTMODE_DISCOVERY_MAX ];
482+ struct typec_altmode * plug_prime_altmode [ALTMODE_DISCOVERY_MAX ];
481483 struct typec_altmode * port_altmode [ALTMODE_DISCOVERY_MAX ];
482484
483485 /* Deadline in jiffies to exit src_try_wait state */
@@ -1636,9 +1638,11 @@ static void svdm_consume_identity_sop_prime(struct tcpm_port *port, const u32 *p
16361638 }
16371639}
16381640
1639- static bool svdm_consume_svids (struct tcpm_port * port , const u32 * p , int cnt )
1641+ static bool svdm_consume_svids (struct tcpm_port * port , const u32 * p , int cnt ,
1642+ enum tcpm_transmit_type rx_sop_type )
16401643{
1641- struct pd_mode_data * pmdata = & port -> mode_data ;
1644+ struct pd_mode_data * pmdata = rx_sop_type == TCPC_TX_SOP_PRIME ?
1645+ & port -> mode_data_prime : & port -> mode_data ;
16421646 int i ;
16431647
16441648 for (i = 1 ; i < cnt ; i ++ ) {
@@ -1684,14 +1688,29 @@ static bool svdm_consume_svids(struct tcpm_port *port, const u32 *p, int cnt)
16841688 return false;
16851689}
16861690
1687- static void svdm_consume_modes (struct tcpm_port * port , const u32 * p , int cnt )
1691+ static void svdm_consume_modes (struct tcpm_port * port , const u32 * p , int cnt ,
1692+ enum tcpm_transmit_type rx_sop_type )
16881693{
16891694 struct pd_mode_data * pmdata = & port -> mode_data ;
16901695 struct typec_altmode_desc * paltmode ;
16911696 int i ;
16921697
1693- if (pmdata -> altmodes >= ARRAY_SIZE (port -> partner_altmode )) {
1694- /* Already logged in svdm_consume_svids() */
1698+ switch (rx_sop_type ) {
1699+ case TCPC_TX_SOP_PRIME :
1700+ pmdata = & port -> mode_data_prime ;
1701+ if (pmdata -> altmodes >= ARRAY_SIZE (port -> plug_prime_altmode )) {
1702+ /* Already logged in svdm_consume_svids() */
1703+ return ;
1704+ }
1705+ break ;
1706+ case TCPC_TX_SOP :
1707+ pmdata = & port -> mode_data ;
1708+ if (pmdata -> altmodes >= ARRAY_SIZE (port -> partner_altmode )) {
1709+ /* Already logged in svdm_consume_svids() */
1710+ return ;
1711+ }
1712+ break ;
1713+ default :
16951714 return ;
16961715 }
16971716
@@ -1729,7 +1748,28 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port)
17291748 }
17301749}
17311750
1751+ static void tcpm_register_plug_altmodes (struct tcpm_port * port )
1752+ {
1753+ struct pd_mode_data * modep = & port -> mode_data_prime ;
1754+ struct typec_altmode * altmode ;
1755+ int i ;
1756+
1757+ typec_plug_set_num_altmodes (port -> plug_prime , modep -> altmodes );
1758+
1759+ for (i = 0 ; i < modep -> altmodes ; i ++ ) {
1760+ altmode = typec_plug_register_altmode (port -> plug_prime ,
1761+ & modep -> altmode_desc [i ]);
1762+ if (IS_ERR (altmode )) {
1763+ tcpm_log (port , "Failed to register plug SVID 0x%04x" ,
1764+ modep -> altmode_desc [i ].svid );
1765+ altmode = NULL ;
1766+ }
1767+ port -> plug_prime_altmode [i ] = altmode ;
1768+ }
1769+ }
1770+
17321771#define supports_modal (port ) PD_IDH_MODAL_SUPP((port)->partner_ident.id_header)
1772+ #define supports_modal_cable (port ) PD_IDH_MODAL_SUPP((port)->cable_ident.id_header)
17331773#define supports_host (port ) PD_IDH_HOST_SUPP((port->partner_ident.id_header))
17341774
17351775/*
@@ -1807,15 +1847,24 @@ static bool tcpm_attempt_vconn_swap_discovery(struct tcpm_port *port)
18071847 return false;
18081848}
18091849
1850+
1851+ static bool tcpm_cable_vdm_supported (struct tcpm_port * port )
1852+ {
1853+ return !IS_ERR_OR_NULL (port -> cable ) &&
1854+ typec_cable_is_active (port -> cable ) &&
1855+ supports_modal_cable (port ) &&
1856+ tcpm_can_communicate_sop_prime (port );
1857+ }
1858+
18101859static int tcpm_pd_svdm (struct tcpm_port * port , struct typec_altmode * adev ,
18111860 const u32 * p , int cnt , u32 * response ,
18121861 enum adev_actions * adev_action ,
18131862 enum tcpm_transmit_type rx_sop_type ,
18141863 enum tcpm_transmit_type * response_tx_sop_type )
18151864{
18161865 struct typec_port * typec = port -> typec_port ;
1817- struct typec_altmode * pdev ;
1818- struct pd_mode_data * modep ;
1866+ struct typec_altmode * pdev , * pdev_prime ;
1867+ struct pd_mode_data * modep , * modep_prime ;
18191868 int svdm_version ;
18201869 int rlen = 0 ;
18211870 int cmd_type ;
@@ -1836,18 +1885,33 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
18361885
18371886 switch (rx_sop_type ) {
18381887 case TCPC_TX_SOP_PRIME :
1888+ modep_prime = & port -> mode_data_prime ;
1889+ pdev_prime = typec_match_altmode (port -> plug_prime_altmode ,
1890+ ALTMODE_DISCOVERY_MAX ,
1891+ PD_VDO_VID (p [0 ]),
1892+ PD_VDO_OPOS (p [0 ]));
18391893 if (!IS_ERR_OR_NULL (port -> cable )) {
18401894 svdm_version = typec_get_cable_svdm_version (typec );
18411895 if (PD_VDO_SVDM_VER (p [0 ]) < svdm_version )
18421896 typec_cable_set_svdm_version (port -> cable , svdm_version );
18431897 }
18441898 break ;
18451899 case TCPC_TX_SOP :
1900+ modep = & port -> mode_data ;
1901+ pdev = typec_match_altmode (port -> partner_altmode ,
1902+ ALTMODE_DISCOVERY_MAX ,
1903+ PD_VDO_VID (p [0 ]),
1904+ PD_VDO_OPOS (p [0 ]));
18461905 svdm_version = typec_get_negotiated_svdm_version (typec );
18471906 if (svdm_version < 0 )
18481907 return 0 ;
18491908 break ;
18501909 default :
1910+ modep = & port -> mode_data ;
1911+ pdev = typec_match_altmode (port -> partner_altmode ,
1912+ ALTMODE_DISCOVERY_MAX ,
1913+ PD_VDO_VID (p [0 ]),
1914+ PD_VDO_OPOS (p [0 ]));
18511915 svdm_version = typec_get_negotiated_svdm_version (typec );
18521916 if (svdm_version < 0 )
18531917 return 0 ;
@@ -1939,6 +2003,9 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
19392003 * SOP' Discover Identity
19402004 * SOP Discover SVIDs
19412005 * Discover Modes
2006+ * (Active Cables)
2007+ * SOP' Discover SVIDs
2008+ * Discover Modes
19422009 *
19432010 * Perform Discover SOP' if the port can communicate with cable
19442011 * plug.
@@ -2018,26 +2085,62 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
20182085 }
20192086 break ;
20202087 case CMD_DISCOVER_SVID :
2088+ * response_tx_sop_type = rx_sop_type ;
20212089 /* 6.4.4.3.2 */
2022- if (svdm_consume_svids (port , p , cnt )) {
2090+ if (svdm_consume_svids (port , p , cnt , rx_sop_type )) {
20232091 response [0 ] = VDO (USB_SID_PD , 1 , svdm_version , CMD_DISCOVER_SVID );
20242092 rlen = 1 ;
2025- } else if (modep -> nsvids && supports_modal (port )) {
2026- response [0 ] = VDO (modep -> svids [0 ], 1 , svdm_version ,
2027- CMD_DISCOVER_MODES );
2028- rlen = 1 ;
2093+ } else {
2094+ if (rx_sop_type == TCPC_TX_SOP ) {
2095+ if (modep -> nsvids && supports_modal (port )) {
2096+ response [0 ] = VDO (modep -> svids [0 ], 1 , svdm_version ,
2097+ CMD_DISCOVER_MODES );
2098+ rlen = 1 ;
2099+ }
2100+ } else if (rx_sop_type == TCPC_TX_SOP_PRIME ) {
2101+ if (modep_prime -> nsvids ) {
2102+ response [0 ] = VDO (modep_prime -> svids [0 ], 1 ,
2103+ svdm_version , CMD_DISCOVER_MODES );
2104+ rlen = 1 ;
2105+ }
2106+ }
20292107 }
20302108 break ;
20312109 case CMD_DISCOVER_MODES :
2032- /* 6.4.4.3.3 */
2033- svdm_consume_modes (port , p , cnt );
2034- modep -> svid_index ++ ;
2035- if (modep -> svid_index < modep -> nsvids ) {
2036- u16 svid = modep -> svids [modep -> svid_index ];
2037- response [0 ] = VDO (svid , 1 , svdm_version , CMD_DISCOVER_MODES );
2038- rlen = 1 ;
2039- } else {
2040- tcpm_register_partner_altmodes (port );
2110+ if (rx_sop_type == TCPC_TX_SOP ) {
2111+ /* 6.4.4.3.3 */
2112+ svdm_consume_modes (port , p , cnt , rx_sop_type );
2113+ modep -> svid_index ++ ;
2114+ if (modep -> svid_index < modep -> nsvids ) {
2115+ u16 svid = modep -> svids [modep -> svid_index ];
2116+ * response_tx_sop_type = TCPC_TX_SOP ;
2117+ response [0 ] = VDO (svid , 1 , svdm_version ,
2118+ CMD_DISCOVER_MODES );
2119+ rlen = 1 ;
2120+ } else if (tcpm_cable_vdm_supported (port )) {
2121+ * response_tx_sop_type = TCPC_TX_SOP_PRIME ;
2122+ response [0 ] = VDO (USB_SID_PD , 1 ,
2123+ typec_get_cable_svdm_version (typec ),
2124+ CMD_DISCOVER_SVID );
2125+ rlen = 1 ;
2126+ } else {
2127+ tcpm_register_partner_altmodes (port );
2128+ }
2129+ } else if (rx_sop_type == TCPC_TX_SOP_PRIME ) {
2130+ /* 6.4.4.3.3 */
2131+ svdm_consume_modes (port , p , cnt , rx_sop_type );
2132+ modep_prime -> svid_index ++ ;
2133+ if (modep_prime -> svid_index < modep_prime -> nsvids ) {
2134+ u16 svid = modep_prime -> svids [modep_prime -> svid_index ];
2135+ * response_tx_sop_type = TCPC_TX_SOP_PRIME ;
2136+ response [0 ] = VDO (svid , 1 ,
2137+ typec_get_cable_svdm_version (typec ),
2138+ CMD_DISCOVER_MODES );
2139+ rlen = 1 ;
2140+ } else {
2141+ tcpm_register_plug_altmodes (port );
2142+ tcpm_register_partner_altmodes (port );
2143+ }
20412144 }
20422145 break ;
20432146 case CMD_ENTER_MODE :
@@ -2418,6 +2521,16 @@ static void vdm_run_state_machine(struct tcpm_port *port)
24182521 tcpm_queue_vdm (port , response [0 ], & response [1 ],
24192522 0 , TCPC_TX_SOP );
24202523 break ;
2524+ /*
2525+ * If Discover SVIDs or Discover Modes fail, then
2526+ * proceed with Alt Mode discovery process on SOP.
2527+ */
2528+ case CMD_DISCOVER_SVID :
2529+ tcpm_register_partner_altmodes (port );
2530+ break ;
2531+ case CMD_DISCOVER_MODES :
2532+ tcpm_register_partner_altmodes (port );
2533+ break ;
24212534 default :
24222535 break ;
24232536 }
@@ -4124,14 +4237,20 @@ static void tcpm_typec_disconnect(struct tcpm_port *port)
41244237static void tcpm_unregister_altmodes (struct tcpm_port * port )
41254238{
41264239 struct pd_mode_data * modep = & port -> mode_data ;
4240+ struct pd_mode_data * modep_prime = & port -> mode_data_prime ;
41274241 int i ;
41284242
41294243 for (i = 0 ; i < modep -> altmodes ; i ++ ) {
41304244 typec_unregister_altmode (port -> partner_altmode [i ]);
41314245 port -> partner_altmode [i ] = NULL ;
41324246 }
4247+ for (i = 0 ; i < modep_prime -> altmodes ; i ++ ) {
4248+ typec_unregister_altmode (port -> plug_prime_altmode [i ]);
4249+ port -> plug_prime_altmode [i ] = NULL ;
4250+ }
41334251
41344252 memset (modep , 0 , sizeof (* modep ));
4253+ memset (modep_prime , 0 , sizeof (* modep_prime ));
41354254}
41364255
41374256static void tcpm_set_partner_usb_comm_capable (struct tcpm_port * port , bool capable )
0 commit comments