:p
atchew
Login
The Thinkpad T14s embeds a transparent 4lanes DP->HDMI transceiver connected to the third QMP Combo PHY 4 lanes. The QMP USB3/DP Combo PHY hosts an USB3 phy and a DP PHY on top of a combo glue to route either lanes to the 4 shared physical lanes. The routing of the lanes can be: - 2 DP + 2 USB3 - 4 DP - 2 USB3 We need be able to specify the lanes mapping to DisplayPort and/or USB3 peripherals when not connected to a Type-C complex. Add the documentation for data-lanes in the out endpoints amd use those in the driver to setup the right PHY mode and orientation. Finally Add all the data routing in DT, disable mode switching and specify the QMP Combo PHY should be in DP-Only mode to route the 4 lanes to the underlying DP phy. Depends on: - [1] https://lore.kernel.org/all/20250902-topic-sm8x50-fix-qmp-usb43dp-usb-switch-v1-1-5b4a51c8c5a8@linaro.org/ - [2] https://lore.kernel.org/all/20250807-topic-4ln_dp_respin-v4-0-43272d6eca92@oss.qualcomm.com/ - [3] https://lore.kernel.org/all/20250822-topic-x1e80100-4lanes-v3-0-5363acad9e32@linaro.org/ Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> --- Changes in v3: - Move the static lanes mapping in data-lanes in the out endpoints - new bindings - new drivewr implementation - new DT layout - rebased on next, fixed simple bridge rebase - added link frequencies for dp2 - Link to v2: https://lore.kernel.org/r/20250902-topic-x1e80100-hdmi-v2-0-f4ccf0ef79ab@linaro.org Changes in v2: - Model the HDMI transceiver as a simple bridge - Switch to a static lanes mapping property - Link to v1: https://lore.kernel.org/r/20250821-topic-x1e80100-hdmi-v1-0-f14ad9430e88@linaro.org --- Neil Armstrong (5): dt-bindings: display: bridge: simple: document the Realtek RTD2171 DP-to-HDMI bridge drm/bridge: simple: add Realtek RTD2171 DP-to-HDMI bridge dt-bindings: phy: qcom,sc8280xp-qmp-usb43dp-phy: Document lanes mapping when not using in USB-C complex phy: qcom: qmp-combo: get the USB3 & DisplayPort lanes mapping from DT arm64: dts: qcom: x1e78100-lenovo-thinkpad-t14s: add HDMI nodes .../bindings/display/bridge/simple-bridge.yaml | 1 + .../phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml | 59 ++++++++- .../dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi | 82 +++++++++++++ drivers/gpu/drm/bridge/simple-bridge.c | 5 + drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 132 +++++++++++++++++++-- 5 files changed, 270 insertions(+), 9 deletions(-) --- base-commit: 947efd54a86984b5f7dee9cf18c1ee82ec0361a2 change-id: 20250821-topic-x1e80100-hdmi-3bd5b5bd2d96 Best regards, -- Neil Armstrong <neil.armstrong@linaro.org>
The Realtek RTD2171 chipset is a transparent DisplayPort 1.4 to HDMI 2.0 bridge. This chipset is usually found in USB-C To HDMI Adapters and Docks, or laptops to provide HDMI display output. Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> --- Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml index XXXXXXX..XXXXXXX 100644 --- a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml +++ b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml @@ -XXX,XX +XXX,XX @@ properties: - adi,adv7123 - dumb-vga-dac - radxa,ra620 + - realtek,rtd2171 - ti,opa362 - ti,ths8134 - ti,ths8135 -- 2.34.1
Add support for the transparent Realtek RTD2171 DP-to-HDMI bridge. Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> --- drivers/gpu/drm/bridge/simple-bridge.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -XXX,XX +XXX,XX @@ static const struct of_device_id simple_bridge_match[] = { .data = &(const struct simple_bridge_info) { .connector_type = DRM_MODE_CONNECTOR_HDMIA, }, + }, { + .compatible = "realtek,rtd2171", + .data = &(const struct simple_bridge_info) { + .connector_type = DRM_MODE_CONNECTOR_HDMIA, + }, }, { .compatible = "ti,opa362", .data = &(const struct simple_bridge_info) { -- 2.34.1
The QMP USB3/DP Combo PHY hosts an USB3 phy and a DP PHY on top of a combo glue to route either lanes to the 4 shared physical lanes. The routing of the lanes can be: - 2 DP + 2 USB3 - 4 DP - 2 USB3 The layout of the lanes was designed to be mapped and swapped related to the USB-C Power Delivery negociation, so it supports a finite set of mappings inherited by the USB-C Altmode layouts. Nevertheless those QMP Comby PHY can be used to drive a DisplayPort connector, DP->HDMI bridge, USB3 A Connector, etc... without an USB-C connector and no PD events. Document the data-lanes on numbered port@0 out endpoints, allowing us to document the lanes mapping to DisplayPort and/or USB3 connectors/peripherals. Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> --- .../phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml | 59 +++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml index XXXXXXX..XXXXXXX 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml @@ -XXX,XX +XXX,XX @@ properties: ports: $ref: /schemas/graph.yaml#/properties/ports + properties: port@0: - $ref: /schemas/graph.yaml#/properties/port + $ref: /schemas/graph.yaml#/$defs/port-base description: Output endpoint of the PHY + unevaluatedProperties: false + + properties: + endpoint: + $ref: /schemas/graph.yaml#/$defs/endpoint-base + unevaluatedProperties: false + + endpoint@0: + $ref: /schemas/graph.yaml#/$defs/endpoint-base + description: Display Port Output lanes of the PHY when used with static mapping + unevaluatedProperties: false + + properties: + data-lanes: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + maxItems: 4 + oneOf: + - items: # DisplayPort 2 lanes, normal orientation + - const: 0 + - const: 1 + - items: # DisplayPort 2 lanes, flipped orientation + - const: 3 + - const: 2 + - items: # DisplayPort 4 lanes, normal orientation + - const: 0 + - const: 1 + - const: 2 + - const: 3 + - items: # DisplayPort 4 lanes, flipped orientation + - const: 3 + - const: 2 + - const: 1 + - const: 0 + required: + - data-lanes + + endpoint@1: + $ref: /schemas/graph.yaml#/$defs/endpoint-base + description: USB Output lanes of the PHY when used with static mapping + unevaluatedProperties: false + + properties: + data-lanes: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + oneOf: + - items: # USB3, normal orientation + - const: 1 + - const: 0 + - items: # USB3, flipped orientation + - const: 2 + - const: 3 + + required: + - data-lanes port@1: $ref: /schemas/graph.yaml#/properties/port -- 2.34.1
The QMP USB3/DP Combo PHY hosts an USB3 phy and a DP PHY on top of a combo glue to route either lanes to the 4 shared physical lanes. The routing of the lanes can be: - 2 DP + 2 USB3 - 4 DP - 2 USB3 Get the lanes mapping from DT and stop registering the USB-C muxes in favor of a static mode and orientation detemined by the lanes mapping. This allows supporting boards with direct connection of USB3 and DisplayPort lanes to the QMP Combo PHY lanes, not using the USB-C Altmode feature. Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 132 ++++++++++++++++++++++++++++-- 1 file changed, 124 insertions(+), 8 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -XXX,XX +XXX,XX @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_graph.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> @@ -XXX,XX +XXX,XX @@ static const u8 qmp_dp_v6_pre_emphasis_hbr_rbr[4][4] = { { 0x22, 0xff, 0xff, 0xff } }; +static const u32 usb3_data_lane_mapping[][2] = { + [TYPEC_ORIENTATION_NORMAL] = { 1, 0 }, + [TYPEC_ORIENTATION_REVERSE] = { 2, 3 }, +}; + +static const u32 dp_2_data_lanes_mapping[][2] = { + [TYPEC_ORIENTATION_NORMAL] = { 0, 1 }, + [TYPEC_ORIENTATION_REVERSE] = { 3, 2 }, +}; + +static const u32 dp_4_data_lanes_mapping[][4] = { + [TYPEC_ORIENTATION_NORMAL] = { 0, 1, 2, 3 }, + [TYPEC_ORIENTATION_REVERSE] = { 3, 2, 1, 0 }, +}; + struct qmp_combo; struct qmp_combo_offsets { @@ -XXX,XX +XXX,XX @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) goto err_node_put; - ret = qmp_combo_typec_register(qmp); - if (ret) - goto err_node_put; + qmp->qmpphy_mode = QMPPHY_MODE_USB3DP; + + if (of_find_property(dev->of_node, "mode-switch", NULL) || + of_find_property(dev->of_node, "orientation-switch", NULL)) { + ret = qmp_combo_typec_register(qmp); + if (ret) + goto err_node_put; + } else { + enum typec_orientation usb3_orientation = TYPEC_ORIENTATION_NONE; + enum typec_orientation dp_orientation = TYPEC_ORIENTATION_NONE; + struct device_node *usb3_ep, *dp_ep; + u32 data_lanes[4]; + int count, i; + + usb3_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0); + dp_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, 1); + + if (usb3_ep) { + ret = of_property_count_u32_elems(usb3_ep, "data-lanes"); + if (ret == -EINVAL) + /* Property isn't here, ignore property */ + goto usb3_mapping_done; + if (ret < 0) + goto err_node_put; + + count = ret; + if (count != 2) + /* Property size is invalid, ignore property */ + goto usb3_mapping_done; + + ret = of_property_read_u32_array(usb3_ep, "data-lanes", data_lanes, count); + if (ret) + goto err_node_put; + + for (i = TYPEC_ORIENTATION_NORMAL; i <= TYPEC_ORIENTATION_REVERSE; i++) + if (!memcmp(data_lanes, usb3_data_lane_mapping[i], sizeof(u32) * 2)) + break; + + if (i >= TYPEC_ORIENTATION_REVERSE) + /* Property value is invalid, ignore property */ + goto usb3_mapping_done; + + usb3_orientation = i; + } + +usb3_mapping_done: + of_node_put(usb3_ep); + + if (dp_ep) { + ret = of_property_count_u32_elems(dp_ep, "data-lanes"); + if (ret == -EINVAL) + /* Property isn't here, ignore property */ + goto dp_mapping_done; + if (ret < 0) + goto err_node_put; + + count = ret; + if (count != 2 && count != 4) + /* Property size is invalid, ignore property */ + goto dp_mapping_done; + + ret = of_property_read_u32_array(dp_ep, "data-lanes", data_lanes, count); + + if (ret) + goto err_node_put; + + for (i = TYPEC_ORIENTATION_NORMAL; i <= TYPEC_ORIENTATION_REVERSE; i++) { + switch (count) { + case 2: + ret = memcmp(data_lanes, dp_2_data_lanes_mapping[i], + sizeof(u32) * count); + break; + case 4: + ret = memcmp(data_lanes, dp_4_data_lanes_mapping[i], + sizeof(u32) * count); + break; + } + + if (!ret) + break; + } + + if (i >= TYPEC_ORIENTATION_REVERSE) + /* Property value is invalid, ignore property */ + goto dp_mapping_done; + + dp_orientation = i; + } + +dp_mapping_done: + of_node_put(dp_ep); + + if (dp_orientation == TYPEC_ORIENTATION_NONE && + usb3_orientation != TYPEC_ORIENTATION_NONE) { + qmp->qmpphy_mode = QMPPHY_MODE_USB3_ONLY; + qmp->orientation = usb3_orientation; + } else if (usb3_orientation == TYPEC_ORIENTATION_NONE && + dp_orientation != TYPEC_ORIENTATION_NONE) { + qmp->qmpphy_mode = QMPPHY_MODE_DP_ONLY; + qmp->orientation = dp_orientation; + } else if (dp_orientation != TYPEC_ORIENTATION_NONE && + dp_orientation == usb3_orientation) { + qmp->qmpphy_mode = QMPPHY_MODE_USB3DP; + qmp->orientation = dp_orientation; + } else { + dev_warn(dev, "unable to determine orientation & mode from data-lanes"); + } + } ret = drm_aux_bridge_register(dev); if (ret) @@ -XXX,XX +XXX,XX @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) goto err_node_put; - /* - * The hw default is USB3_ONLY, but USB3+DP mode lets us more easily - * check both sub-blocks' init tables for blunders at probe time. - */ - qmp->qmpphy_mode = QMPPHY_MODE_USB3DP; qmp->usb_phy = devm_phy_create(dev, usb_np, &qmp_combo_usb_phy_ops); if (IS_ERR(qmp->usb_phy)) { -- 2.34.1
The Thinkpad T14s embeds a transparent 4lanes DP->HDMI transceiver connected to the third QMP Combo PHY 4 lanes. Add all the data routing, disable mode switching and specify the QMP Combo PHY should be in DP-Only mode to route the 4 lanes to the underlying DP phy. Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> --- .../dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi | 82 ++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi index XXXXXXX..XXXXXXX 100644 --- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi @@ -XXX,XX +XXX,XX @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/gpio-keys.h> #include <dt-bindings/input/input.h> +#include <dt-bindings/phy/phy.h> #include <dt-bindings/pinctrl/qcom,pmic-gpio.h> #include <dt-bindings/regulator/qcom,rpmh-regulator.h> @@ -XXX,XX +XXX,XX @@ switch-lid { }; }; + hdmi-bridge { + compatible = "realtek,rtd2171"; + + pinctrl-0 = <&hdmi_hpd_default>; + pinctrl-names = "default"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + hdmi_bridge_dp_in: endpoint { + remote-endpoint = <&usb_1_ss2_qmpphy_out_dp>; + }; + }; + + port@1 { + reg = <1>; + + hdmi_bridge_tmds_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; + }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con: endpoint { + remote-endpoint = <&hdmi_bridge_tmds_out>; + }; + }; + }; + pmic-glink { compatible = "qcom,x1e80100-pmic-glink", "qcom,sm8550-pmic-glink", @@ -XXX,XX +XXX,XX @@ &mdss_dp1_out { link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; }; +&mdss_dp2 { + status = "okay"; +}; + +&mdss_dp2_out { + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; +}; + &mdss_dp3 { /delete-property/ #sound-dai-cells; @@ -XXX,XX +XXX,XX @@ &tlmm { <72 2>, /* Secure EC I2C connection (?) */ <238 1>; /* UFS Reset */ + hdmi_hpd_default: hdmi-hpd-default-state { + pins = "gpio126"; + function = "usb2_dp"; + bias-disable; + }; + eusb3_reset_n: eusb3-reset-n-state { pins = "gpio6"; function = "gpio"; @@ -XXX,XX +XXX,XX @@ &usb_1_ss0_qmpphy_out { remote-endpoint = <&retimer_ss0_ss_in>; }; +&usb_1_ss2_qmpphy { + vdda-phy-supply = <&vreg_l2j_1p2>; + vdda-pll-supply = <&vreg_l2d_0p9>; + + /delete-property/ mode-switch; + /delete-property/ orientation-switch; + + status = "okay"; + + ports { + port@0 { + #address-cells = <1>; + #size-cells = <0>; + + /delete-node/ endpoint; + + usb_1_ss2_qmpphy_out_dp: endpoint@0 { + reg = <0>; + + data-lanes = <0 1 2 3>; + remote-endpoint = <&hdmi_bridge_dp_in>; + }; + + /* No USB3 lanes connected */ + }; + }; +}; + &usb_1_ss1_hsphy { vdd-supply = <&vreg_l3j_0p8>; vdda12-supply = <&vreg_l2j_1p2>; -- 2.34.1
The Thinkpad T14s embeds a transparent 4lanes DP->HDMI transceiver connected to the third QMP Combo PHY 4 lanes. The QMP USB3/DP Combo PHY hosts an USB3 phy and a DP PHY on top of a combo glue to route either lanes to the 4 shared physical lanes. The routing of the lanes can be: - 1/2 DP + 2 USB3 - 1/2/4 DP - 2 USB3 We need be able to specify the lanes mapping to DisplayPort and/or USB3 peripherals when not connected to a Type-C complex. Add the documentation for data-lanes in the out endpoints amd use those in the driver to setup the right PHY mode and orientation. Finally Add all the data routing in DT, disable mode switching and specify the QMP Combo PHY should be in DP-Only mode to route the 4 lanes to the underlying DP phy. Depends on: - [1] https://lore.kernel.org/all/20251006-topic-sm8x50-fix-qmp-usb43dp-usb-switch-v2-1-3249e511013b@linaro.org/ - [2] https://lore.kernel.org/all/20251006-topic-sm8x50-qmp-combo-allow-mode-switch-v1-1-3d79e7ea6824@linaro.org/ Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> --- Changes in v5: - Fixed bindings tab - Add comment about exlusivity of the static lanes mapping - Fixed the single lane phy entries - Switched to of_property_present() - Moved the ss2 nodes after ss1 in DT - Link to v4: https://lore.kernel.org/r/20250930-topic-x1e80100-hdmi-v4-0-86a14e8a34ac@linaro.org Changes in v4: - Add definition for single lane DP - Fix lanes mapping for DP in bindings and driver - Add documentation on how to interpret the data-lanes numbers - Rewrite driver support for be simpler and split into helpers - Rebase DT on next and drop phy.h include, and use proper mapping - Link to v3: https://lore.kernel.org/r/20250908-topic-x1e80100-hdmi-v3-0-c53b0f2bc2fb@linaro.org Changes in v3: - Move the static lanes mapping in data-lanes in the out endpoints - new bindings - new drivewr implementation - new DT layout - rebased on next, fixed simple bridge rebase - added link frequencies for dp2 - Link to v2: https://lore.kernel.org/r/20250902-topic-x1e80100-hdmi-v2-0-f4ccf0ef79ab@linaro.org Changes in v2: - Model the HDMI transceiver as a simple bridge - Switch to a static lanes mapping property - Link to v1: https://lore.kernel.org/r/20250821-topic-x1e80100-hdmi-v1-0-f14ad9430e88@linaro.org --- Neil Armstrong (3): dt-bindings: phy: qcom,sc8280xp-qmp-usb43dp-phy: Document lanes mapping when not using in USB-C complex phy: qcom: qmp-combo: get the USB3 & DisplayPort lanes mapping from DT arm64: dts: qcom: x1e78100-lenovo-thinkpad-t14s: add HDMI nodes .../phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml | 69 +++++++++- .../dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi | 81 ++++++++++++ drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 145 +++++++++++++++++++-- 3 files changed, 286 insertions(+), 9 deletions(-) --- base-commit: 51c986f3be9de5451e172eb5f7efa53fbe9870fc change-id: 20250821-topic-x1e80100-hdmi-3bd5b5bd2d96 Best regards, -- Neil Armstrong <neil.armstrong@linaro.org>
The QMP USB3/DP Combo PHY hosts an USB3 phy and a DP PHY on top of a combo glue to route either lanes to the 4 shared physical lanes. The routing of the lanes can be: - 2 DP + 2 USB3 - 4 DP - 2 USB3 The layout of the lanes was designed to be mapped and swapped related to the USB-C Power Delivery negociation, so it supports a finite set of mappings inherited by the USB-C Altmode layouts. Nevertheless those QMP Comby PHY can be used to drive a DisplayPort connector, DP->HDMI bridge, USB3 A Connector, etc... without an USB-C connector and no PD events. Document the data-lanes on numbered port@0 out endpoints, allowing us to document the lanes mapping to DisplayPort and/or USB3 connectors/peripherals. Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> --- .../phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml | 69 +++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml index XXXXXXX..XXXXXXX 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml @@ -XXX,XX +XXX,XX @@ properties: ports: $ref: /schemas/graph.yaml#/properties/ports + properties: port@0: - $ref: /schemas/graph.yaml#/properties/port + $ref: /schemas/graph.yaml#/$defs/port-base description: Output endpoint of the PHY + unevaluatedProperties: false + + properties: + endpoint: + $ref: /schemas/graph.yaml#/$defs/endpoint-base + unevaluatedProperties: false + + endpoint@0: + $ref: /schemas/graph.yaml#/$defs/endpoint-base + description: Display Port Output lanes of the PHY when used with static mapping, + The entry index is the DP lanes index, and the number is the PHY + signal in the order RX0, TX0, TX1, RX1. + unevaluatedProperties: false + + properties: + # Static lane mappings are mutually exclusive with typec-mux/orientation-mux + data-lanes: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + maxItems: 4 + oneOf: + - items: # DisplayPort 1 lane, normal orientation + - const: 3 + - items: # DisplayPort 1 lane, flipped orientation + - const: 0 + - items: # DisplayPort 2 lanes, normal orientation + - const: 3 + - const: 2 + - items: # DisplayPort 2 lanes, flipped orientation + - const: 0 + - const: 1 + - items: # DisplayPort 4 lanes, normal orientation + - const: 3 + - const: 2 + - const: 1 + - const: 0 + - items: # DisplayPort 4 lanes, flipped orientation + - const: 0 + - const: 1 + - const: 2 + - const: 3 + required: + - data-lanes + + endpoint@1: + $ref: /schemas/graph.yaml#/$defs/endpoint-base + description: USB Output lanes of the PHY when used with static mapping. + The entry index is the USB3 lane in the order TX then RX, and the + number is the PHY signal in the order RX0, TX0, TX1, RX1. + unevaluatedProperties: false + + properties: + # Static lane mappings are mutually exclusive with typec-mux/orientation-mux + data-lanes: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + oneOf: + - items: # USB3, normal orientation + - const: 1 + - const: 0 + - items: # USB3, flipped orientation + - const: 2 + - const: 3 + + required: + - data-lanes port@1: $ref: /schemas/graph.yaml#/properties/port -- 2.34.1
The QMP USB3/DP Combo PHY hosts an USB3 phy and a DP PHY on top of a combo glue to route either lanes to the 4 shared physical lanes. The routing of the lanes can be: - 2 DP + 2 USB3 - 4 DP - 2 USB3 Get the lanes mapping from DT and stop registering the USB-C muxes in favor of a static mode and orientation detemined by the lanes mapping. This allows supporting boards with direct connection of USB3 and DisplayPort lanes to the QMP Combo PHY lanes, not using the USB-C Altmode feature. Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 145 ++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 8 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -XXX,XX +XXX,XX @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_graph.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> @@ -XXX,XX +XXX,XX @@ static const u8 qmp_dp_v6_pre_emphasis_hbr_rbr[4][4] = { { 0x22, 0xff, 0xff, 0xff } }; +struct qmp_combo_lane_mapping { + unsigned int lanes_count; + enum typec_orientation orientation; + u32 lanes[4]; +}; + +static const struct qmp_combo_lane_mapping usb3_data_lanes[] = { + { 2, TYPEC_ORIENTATION_NORMAL, { 1, 0 }}, + { 2, TYPEC_ORIENTATION_REVERSE, { 2, 3 }}, +}; + +static const struct qmp_combo_lane_mapping dp_data_lanes[] = { + { 1, TYPEC_ORIENTATION_NORMAL, { 3 }}, + { 1, TYPEC_ORIENTATION_REVERSE, { 0 }}, + { 2, TYPEC_ORIENTATION_NORMAL, { 3, 2 }}, + { 2, TYPEC_ORIENTATION_REVERSE, { 0, 1 }}, + { 4, TYPEC_ORIENTATION_NORMAL, { 3, 2, 1, 0 }}, + { 4, TYPEC_ORIENTATION_REVERSE, { 0, 1, 2, 3 }}, +}; + struct qmp_combo; struct qmp_combo_offsets { @@ -XXX,XX +XXX,XX @@ static struct phy *qmp_combo_phy_xlate(struct device *dev, const struct of_phand return ERR_PTR(-EINVAL); } +static void qmp_combo_find_lanes_orientation(const struct qmp_combo_lane_mapping *mapping, + unsigned int mapping_count, + u32 *lanes, unsigned int lanes_count, + enum typec_orientation *orientation) +{ + int i; + + for (i = 0; i < mapping_count; i++) { + if (mapping[i].lanes_count != lanes_count) + continue; + if (!memcmp(mapping[i].lanes, lanes, sizeof(u32) * lanes_count)) { + *orientation = mapping[i].orientation; + return; + } + } +} + +static int qmp_combo_get_dt_lanes_mapping(struct device *dev, unsigned int endpoint, + u32 *data_lanes, unsigned int max, + unsigned int *count) +{ + struct device_node *ep; + int ret; + + ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, endpoint); + if (!ep) + return -EINVAL; + + ret = of_property_count_u32_elems(ep, "data-lanes"); + if (ret < 0) + goto err_node_put; + + *count = ret; + + ret = of_property_read_u32_array(ep, "data-lanes", data_lanes, + max_t(unsigned int, *count, max)); + +err_node_put: + of_node_put(ep); + + return ret; +} + +static int qmp_combo_get_dt_dp_orientation(struct device *dev, + enum typec_orientation *orientation) +{ + unsigned int count; + u32 data_lanes[4]; + int ret; + + /* DP is described on the first endpoint of the first port */ + ret = qmp_combo_get_dt_lanes_mapping(dev, 0, data_lanes, 4, &count); + if (ret < 0) + return ret == -EINVAL ? 0 : ret; + + /* Search for a match and only update orientation if found */ + qmp_combo_find_lanes_orientation(dp_data_lanes, ARRAY_SIZE(dp_data_lanes), + data_lanes, count, orientation); + + return 0; +} + +static int qmp_combo_get_dt_usb3_orientation(struct device *dev, + enum typec_orientation *orientation) +{ + unsigned int count; + u32 data_lanes[2]; + int ret; + + /* USB3 is described on the second endpoint of the first port */ + ret = qmp_combo_get_dt_lanes_mapping(dev, 1, data_lanes, 2, &count); + if (ret < 0) + return ret == -EINVAL ? 0 : ret; + + /* Search for a match and only update orientation if found */ + qmp_combo_find_lanes_orientation(usb3_data_lanes, ARRAY_SIZE(usb3_data_lanes), + data_lanes, count, orientation); + + return 0; +} + static int qmp_combo_probe(struct platform_device *pdev) { struct qmp_combo *qmp; @@ -XXX,XX +XXX,XX @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) goto err_node_put; - ret = qmp_combo_typec_register(qmp); - if (ret) - goto err_node_put; + qmp->qmpphy_mode = QMPPHY_MODE_USB3DP; + + if (of_property_present(dev->of_node, "mode-switch") || + of_property_present(dev->of_node, "orientation-switch")) { + ret = qmp_combo_typec_register(qmp); + if (ret) + goto err_node_put; + } else { + enum typec_orientation dp_orientation = TYPEC_ORIENTATION_NONE; + enum typec_orientation usb3_orientation = TYPEC_ORIENTATION_NONE; + + ret = qmp_combo_get_dt_dp_orientation(dev, &dp_orientation); + if (ret) + goto err_node_put; + + ret = qmp_combo_get_dt_usb3_orientation(dev, &usb3_orientation); + if (ret) + goto err_node_put; + + if (dp_orientation == TYPEC_ORIENTATION_NONE && + usb3_orientation != TYPEC_ORIENTATION_NONE) { + qmp->qmpphy_mode = QMPPHY_MODE_USB3_ONLY; + qmp->orientation = usb3_orientation; + } else if (usb3_orientation == TYPEC_ORIENTATION_NONE && + dp_orientation != TYPEC_ORIENTATION_NONE) { + qmp->qmpphy_mode = QMPPHY_MODE_DP_ONLY; + qmp->orientation = dp_orientation; + } else if (dp_orientation != TYPEC_ORIENTATION_NONE && + dp_orientation == usb3_orientation) { + qmp->qmpphy_mode = QMPPHY_MODE_USB3DP; + qmp->orientation = dp_orientation; + } else { + dev_warn(dev, "unable to determine orientation & mode from data-lanes"); + } + } ret = drm_aux_bridge_register(dev); if (ret) @@ -XXX,XX +XXX,XX @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) goto err_node_put; - /* - * The hw default is USB3_ONLY, but USB3+DP mode lets us more easily - * check both sub-blocks' init tables for blunders at probe time. - */ - qmp->qmpphy_mode = QMPPHY_MODE_USB3DP; qmp->usb_phy = devm_phy_create(dev, usb_np, &qmp_combo_usb_phy_ops); if (IS_ERR(qmp->usb_phy)) { -- 2.34.1
The Thinkpad T14s embeds a transparent 4lanes DP->HDMI transceiver connected to the third QMP Combo PHY 4 lanes. Add all the data routing, disable mode switching and specify the QMP Combo PHY should be in DP-Only mode to route the 4 lanes to the underlying DP phy. Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> --- .../dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi | 81 ++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi index XXXXXXX..XXXXXXX 100644 --- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi @@ -XXX,XX +XXX,XX @@ switch-lid { }; }; + hdmi-bridge { + compatible = "realtek,rtd2171"; + + pinctrl-0 = <&hdmi_hpd_default>; + pinctrl-names = "default"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + hdmi_bridge_dp_in: endpoint { + remote-endpoint = <&usb_1_ss2_qmpphy_out_dp>; + }; + }; + + port@1 { + reg = <1>; + + hdmi_bridge_tmds_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; + }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con: endpoint { + remote-endpoint = <&hdmi_bridge_tmds_out>; + }; + }; + }; + pmic-glink { compatible = "qcom,x1e80100-pmic-glink", "qcom,sm8550-pmic-glink", @@ -XXX,XX +XXX,XX @@ &mdss_dp1_out { link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; }; +&mdss_dp2 { + status = "okay"; +}; + +&mdss_dp2_out { + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; +}; + &mdss_dp3 { /delete-property/ #sound-dai-cells; @@ -XXX,XX +XXX,XX @@ eusb6_reset_n: eusb6-reset-n-state { output-low; }; + hdmi_hpd_default: hdmi-hpd-default-state { + pins = "gpio126"; + function = "usb2_dp"; + bias-disable; + }; + tpad_default: tpad-default-state { pins = "gpio3"; function = "gpio"; @@ -XXX,XX +XXX,XX @@ &usb_1_ss1_qmpphy_out { remote-endpoint = <&retimer_ss1_ss_in>; }; +&usb_1_ss2_qmpphy { + vdda-phy-supply = <&vreg_l2j_1p2>; + vdda-pll-supply = <&vreg_l2d_0p9>; + + /delete-property/ mode-switch; + /delete-property/ orientation-switch; + + status = "okay"; + + ports { + port@0 { + #address-cells = <1>; + #size-cells = <0>; + + /delete-node/ endpoint; + + usb_1_ss2_qmpphy_out_dp: endpoint@0 { + reg = <0>; + + data-lanes = <3 2 1 0>; + remote-endpoint = <&hdmi_bridge_dp_in>; + }; + + /* No USB3 lanes connected */ + }; + }; +}; + &usb_2 { status = "okay"; }; -- 2.34.1