1313#include <linux/module.h>
1414#include <linux/of.h>
1515#include <linux/of_address.h>
16+ #include <linux/of_graph.h>
1617#include <linux/phy/phy.h>
1718#include <linux/platform_device.h>
1819#include <linux/regulator/consumer.h>
@@ -1739,6 +1740,26 @@ static const u8 qmp_dp_v6_pre_emphasis_hbr_rbr[4][4] = {
17391740 { 0x22 , 0xff , 0xff , 0xff }
17401741};
17411742
1743+ struct qmp_combo_lane_mapping {
1744+ unsigned int lanes_count ;
1745+ enum typec_orientation orientation ;
1746+ u32 lanes [4 ];
1747+ };
1748+
1749+ static const struct qmp_combo_lane_mapping usb3_data_lanes [] = {
1750+ { 2 , TYPEC_ORIENTATION_NORMAL , { 1 , 0 }},
1751+ { 2 , TYPEC_ORIENTATION_REVERSE , { 2 , 3 }},
1752+ };
1753+
1754+ static const struct qmp_combo_lane_mapping dp_data_lanes [] = {
1755+ { 1 , TYPEC_ORIENTATION_NORMAL , { 3 }},
1756+ { 1 , TYPEC_ORIENTATION_REVERSE , { 0 }},
1757+ { 2 , TYPEC_ORIENTATION_NORMAL , { 3 , 2 }},
1758+ { 2 , TYPEC_ORIENTATION_REVERSE , { 0 , 1 }},
1759+ { 4 , TYPEC_ORIENTATION_NORMAL , { 3 , 2 , 1 , 0 }},
1760+ { 4 , TYPEC_ORIENTATION_REVERSE , { 0 , 1 , 2 , 3 }},
1761+ };
1762+
17421763struct qmp_combo ;
17431764
17441765struct qmp_combo_offsets {
@@ -4079,6 +4100,84 @@ static struct phy *qmp_combo_phy_xlate(struct device *dev, const struct of_phand
40794100 return ERR_PTR (- EINVAL );
40804101}
40814102
4103+ static void qmp_combo_find_lanes_orientation (const struct qmp_combo_lane_mapping * mapping ,
4104+ unsigned int mapping_count ,
4105+ u32 * lanes , unsigned int lanes_count ,
4106+ enum typec_orientation * orientation )
4107+ {
4108+ int i ;
4109+
4110+ for (i = 0 ; i < mapping_count ; i ++ ) {
4111+ if (mapping [i ].lanes_count != lanes_count )
4112+ continue ;
4113+ if (!memcmp (mapping [i ].lanes , lanes , sizeof (u32 ) * lanes_count )) {
4114+ * orientation = mapping [i ].orientation ;
4115+ return ;
4116+ }
4117+ }
4118+ }
4119+
4120+ static int qmp_combo_get_dt_lanes_mapping (struct device * dev , unsigned int endpoint ,
4121+ u32 * data_lanes , unsigned int max ,
4122+ unsigned int * count )
4123+ {
4124+ struct device_node * ep __free (device_node ) = NULL ;
4125+ int ret ;
4126+
4127+ ep = of_graph_get_endpoint_by_regs (dev -> of_node , 0 , endpoint );
4128+ if (!ep )
4129+ return - EINVAL ;
4130+
4131+ ret = of_property_count_u32_elems (ep , "data-lanes" );
4132+ if (ret < 0 )
4133+ return ret ;
4134+
4135+ * count = ret ;
4136+ if (* count > max )
4137+ return - EINVAL ;
4138+
4139+ return of_property_read_u32_array (ep , "data-lanes" , data_lanes ,
4140+ min_t (unsigned int , * count , max ));
4141+ }
4142+
4143+ static int qmp_combo_get_dt_dp_orientation (struct device * dev ,
4144+ enum typec_orientation * orientation )
4145+ {
4146+ unsigned int count ;
4147+ u32 data_lanes [4 ];
4148+ int ret ;
4149+
4150+ /* DP is described on the first endpoint of the first port */
4151+ ret = qmp_combo_get_dt_lanes_mapping (dev , 0 , data_lanes , 4 , & count );
4152+ if (ret < 0 )
4153+ return ret == - EINVAL ? 0 : ret ;
4154+
4155+ /* Search for a match and only update orientation if found */
4156+ qmp_combo_find_lanes_orientation (dp_data_lanes , ARRAY_SIZE (dp_data_lanes ),
4157+ data_lanes , count , orientation );
4158+
4159+ return 0 ;
4160+ }
4161+
4162+ static int qmp_combo_get_dt_usb3_orientation (struct device * dev ,
4163+ enum typec_orientation * orientation )
4164+ {
4165+ unsigned int count ;
4166+ u32 data_lanes [2 ];
4167+ int ret ;
4168+
4169+ /* USB3 is described on the second endpoint of the first port */
4170+ ret = qmp_combo_get_dt_lanes_mapping (dev , 1 , data_lanes , 2 , & count );
4171+ if (ret < 0 )
4172+ return ret == - EINVAL ? 0 : ret ;
4173+
4174+ /* Search for a match and only update orientation if found */
4175+ qmp_combo_find_lanes_orientation (usb3_data_lanes , ARRAY_SIZE (usb3_data_lanes ),
4176+ data_lanes , count , orientation );
4177+
4178+ return 0 ;
4179+ }
4180+
40824181static int qmp_combo_probe (struct platform_device * pdev )
40834182{
40844183 struct qmp_combo * qmp ;
@@ -4130,9 +4229,41 @@ static int qmp_combo_probe(struct platform_device *pdev)
41304229 if (ret )
41314230 goto err_node_put ;
41324231
4133- ret = qmp_combo_typec_register (qmp );
4134- if (ret )
4135- goto err_node_put ;
4232+ qmp -> qmpphy_mode = QMPPHY_MODE_USB3DP ;
4233+
4234+ if (of_property_present (dev -> of_node , "mode-switch" ) ||
4235+ of_property_present (dev -> of_node , "orientation-switch" )) {
4236+ ret = qmp_combo_typec_register (qmp );
4237+ if (ret )
4238+ goto err_node_put ;
4239+ } else {
4240+ enum typec_orientation dp_orientation = TYPEC_ORIENTATION_NONE ;
4241+ enum typec_orientation usb3_orientation = TYPEC_ORIENTATION_NONE ;
4242+
4243+ ret = qmp_combo_get_dt_dp_orientation (dev , & dp_orientation );
4244+ if (ret )
4245+ goto err_node_put ;
4246+
4247+ ret = qmp_combo_get_dt_usb3_orientation (dev , & usb3_orientation );
4248+ if (ret )
4249+ goto err_node_put ;
4250+
4251+ if (dp_orientation == TYPEC_ORIENTATION_NONE &&
4252+ usb3_orientation != TYPEC_ORIENTATION_NONE ) {
4253+ qmp -> qmpphy_mode = QMPPHY_MODE_USB3_ONLY ;
4254+ qmp -> orientation = usb3_orientation ;
4255+ } else if (usb3_orientation == TYPEC_ORIENTATION_NONE &&
4256+ dp_orientation != TYPEC_ORIENTATION_NONE ) {
4257+ qmp -> qmpphy_mode = QMPPHY_MODE_DP_ONLY ;
4258+ qmp -> orientation = dp_orientation ;
4259+ } else if (dp_orientation != TYPEC_ORIENTATION_NONE &&
4260+ dp_orientation == usb3_orientation ) {
4261+ qmp -> qmpphy_mode = QMPPHY_MODE_USB3DP ;
4262+ qmp -> orientation = dp_orientation ;
4263+ } else {
4264+ dev_warn (dev , "unable to determine orientation & mode from data-lanes" );
4265+ }
4266+ }
41364267
41374268 ret = drm_aux_bridge_register (dev );
41384269 if (ret )
@@ -4152,11 +4283,6 @@ static int qmp_combo_probe(struct platform_device *pdev)
41524283 if (ret )
41534284 goto err_node_put ;
41544285
4155- /*
4156- * The hw default is USB3_ONLY, but USB3+DP mode lets us more easily
4157- * check both sub-blocks' init tables for blunders at probe time.
4158- */
4159- qmp -> qmpphy_mode = QMPPHY_MODE_USB3DP ;
41604286
41614287 qmp -> usb_phy = devm_phy_create (dev , usb_np , & qmp_combo_usb_phy_ops );
41624288 if (IS_ERR (qmp -> usb_phy )) {
0 commit comments