diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index 094a6383bb779..8d980acb1a163 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -19,6 +19,7 @@ properties: oneOf: - enum: - qcom,glymur-dp + - qcom,nord-dp - qcom,sa8775p-dp - qcom,sc7180-dp - qcom,sc7280-dp diff --git a/Documentation/devicetree/bindings/display/msm/qcom,nord-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,nord-mdss.yaml new file mode 100644 index 0000000000000..7df750d9fc02b --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,nord-mdss.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,nord-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Nord display subsystem (MDSS) + +maintainers: + - Linux Kernel + +description: | + Nord display subsystem consists of MDSS (display controller), DPU 1499A + (display processing unit), and display interface controllers (DP only, no DSI). + This is MDSS 12.1, DP-only, with 2 independent DP controllers. + +properties: + compatible: + const: qcom,nord-mdss + + reg: + maxItems: 1 + + reg-names: + const: mdss + + power-domains: + maxItems: 1 + + clocks: + minItems: 3 + maxItems: 3 + + clock-names: + items: + - const: iface + - const: bus + - const: vsync + + interrupts: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 1 + + iommus: + maxItems: 1 + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + ranges: true + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + description: DPU display controller + + "^phy@[0-9a-f]+$": + type: object + description: DP PHY + +additionalProperties: false + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - interrupts + - interrupt-controller + - "#interrupt-cells" + - "#address-cells" + - "#size-cells" + +examples: + - | + mdss@ae00000 { + compatible = "qcom,nord-mdss"; + reg = <0 0xae00000 0 0xf0000>; + reg-names = "mdss"; + power-domains = <&dispcc 0>; + clocks = <&dispcc 0>, + <&dispcc 1>, + <&dispcc 2>; + clock-names = "iface", "bus", "vsync"; + interrupts = <0 83 4>; + interrupt-controller; + #interrupt-cells = <1>; + iommus = <&smmu 0x800 0x420>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + }; diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index 0bf8bf4f66acf..91d7a5c8e19af 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -19,6 +19,7 @@ properties: oneOf: - enum: - qcom,glymur-dp-phy + - qcom,nord-dp-phy - qcom,sa8775p-edp-phy - qcom,sc7280-edp-phy - qcom,sc8180x-edp-phy diff --git a/arch/arm64/boot/dts/qcom/nord-embedded.dtsi b/arch/arm64/boot/dts/qcom/nord-embedded.dtsi index 20888736be192..eb9ef5783768d 100644 --- a/arch/arm64/boot/dts/qcom/nord-embedded.dtsi +++ b/arch/arm64/boot/dts/qcom/nord-embedded.dtsi @@ -1670,6 +1670,366 @@ #power-domain-cells = <1>; }; + /* Display subsystem nodes - MDSS 12.1, DP-only (no DSI) */ + mdss: display-subsystem@ae00000 { + compatible = "qcom,nord-mdss"; + reg = <0x0 0x0ae00000 0x0 0x1000>; + reg-names = "mdss"; + + power-domains = <&dispcc0 MDSS_DISP_CC_MDSS_CORE_GDSC>; + clocks = <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&nwgcc NW_GCC_DISP_0_HF_AXI_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_MDP_CLK>; + + resets = <&dispcc0 MDSS_DISP_CC_MDSS_CORE_BCR>; + interconnects = <&mmss_noc MASTER_MDP0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&hscnoc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; + status = "disabled"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_smmu_1 0x3e0 0x2>, + <&apps_smmu_1 0x3e2 0x2>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + mdss_mdp: display-controller@ae01000 { + compatible = "qcom,nord-dpu"; + reg = <0x0 0x0ae01000 0x0 0x8f000>, + <0x0 0x0aeb0000 0x0 0x3000>; + reg-names = "mdp", + "vbif"; + + clocks = <&nwgcc NW_GCC_DISP_0_HF_AXI_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_MDP_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + interrupts = ; + interrupt-parent = <&mdss>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + assigned-clocks = <&dispcc0 MDSS_DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dpu_intf0_out: endpoint { + remote-endpoint = <&mdss_dp0_in>; + }; + }; + + port@1 { + reg = <1>; + + dpu_intf4_out: endpoint { + remote-endpoint = <&mdss_dp1_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-417000000 { + opp-hz = /bits/ 64 <417000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-532000000 { + opp-hz = /bits/ 64 <532000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + opp-710000000 { + opp-hz = /bits/ 64 <710000000>; + required-opps = <&rpmhpd_opp_turbo_l1>; + }; + }; + }; + + mdss_dp0: displayport-controller@af54000 { + compatible = "qcom,nord-dp"; + + reg = <0x0 0x0af54000 0x0 0x200>, + <0x0 0x0af54200 0x0 0x200>, + <0x0 0x0af55000 0x0 0xc00>, + <0x0 0x0af56000 0x0 0x400>, + <0x0 0x0af57000 0x0 0x400>, + <0x0 0x0af58000 0x0 0x400>, + <0x0 0x0af59000 0x0 0x400>, + <0x0 0x0af5a000 0x0 0x600>, + <0x0 0x0af5b000 0x0 0x600>; + + clocks = <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_LINK_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_LINK_INTF_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL0_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL1_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL2_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL3_CLK>; + + clock-names = "core_iface", "core_aux", + "ctrl_link", + "ctrl_link_iface", "stream_pixel", + "stream_1_pixel", "stream_2_pixel", "stream_3_pixel"; + + assigned-clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_LINK_CLK_SRC>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL2_CLK_SRC>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_PIXEL3_CLK_SRC>; + + assigned-clock-parents = <&dp0_phy 0>, + <&dp0_phy 1>, + <&dp0_phy 1>, + <&dp0_phy 1>, + <&dp0_phy 1>; + + interrupts-extended = <&mdss 12>; + + phys = <&dp0_phy>; + + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + + #sound-dai-cells = <0>; + + status = "disabled"; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; + + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + + required-opps = <&rpmhpd_opp_nom>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dp0_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dp0_out: endpoint { + }; + }; + }; + }; + + mdss_dp1: displayport-controller@af5c000 { + compatible = "qcom,nord-dp"; + + reg = <0x0 0x0af5c000 0x0 0x200>, + <0x0 0x0af5c200 0x0 0x200>, + <0x0 0x0af5d000 0x0 0xc00>, + <0x0 0x0af5e000 0x0 0x400>, + <0x0 0x0af5f000 0x0 0x400>, + <0x0 0x0af60000 0x0 0x400>, + <0x0 0x0af61000 0x0 0x400>, + <0x0 0x0af62000 0x0 0x600>, + <0x0 0x0af63000 0x0 0x600>; + + clocks = <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_AUX_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_LINK_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_LINK_INTF_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_PIXEL0_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_PIXEL1_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_PIXEL2_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_PIXEL3_CLK>; + + clock-names = "core_iface", "core_aux", + "ctrl_link", + "ctrl_link_iface", "stream_pixel", + "stream_1_pixel", "stream_2_pixel", "stream_3_pixel"; + + assigned-clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_LINK_CLK_SRC>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC>, + <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_PIXEL1_CLK_SRC>; + + assigned-clock-parents = <&dp1_phy 0>, + <&dp1_phy 1>, + <&dp1_phy 1>; + + interrupts-extended = <&mdss 13>; + + phys = <&dp1_phy>; + + phy-names = "dp"; + + operating-points-v2 = <&dp1_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + + #sound-dai-cells = <0>; + + status = "disabled"; + + dp1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; + + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + + required-opps = <&rpmhpd_opp_nom>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dp1_in: endpoint { + remote-endpoint = <&dpu_intf4_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dp1_out: endpoint { + }; + }; + }; + }; + + dp0_phy: phy@fc3a00 { + compatible = "qcom,nord-dp-phy"; + + reg = <0x0 0x0fc3a00 0x0 0x1d0>, + <0x0 0x0fc3200 0x0 0x128>, + <0x0 0x0fc3600 0x0 0x128>, + <0x0 0x0fc3000 0x0 0x200>; + + clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&tcsrcc TCSR_DP_TX_0_CLKREF_EN>; + + clock-names = "aux", + "cfg_ahb", + "ref"; + + #clock-cells = <1>; + #phy-cells = <0>; + + power-domains = <&rpmhpd RPMHPD_MX>; + + status = "disabled"; + }; + + dp1_phy: phy@fc6a00 { + compatible = "qcom,nord-dp-phy"; + + reg = <0x0 0x0fc6a00 0x0 0x200>, + <0x0 0x0fc6200 0x0 0xd0>, + <0x0 0x0fc6600 0x0 0xd0>, + <0x0 0x0fc6000 0x0 0x1c8>; + + clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_AUX_CLK>, + <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&tcsrcc TCSR_DP_TX_1_CLKREF_EN>; + + clock-names = "aux", + "cfg_ahb", + "ref"; + + #clock-cells = <1>; + #phy-cells = <0>; + + power-domains = <&rpmhpd RPMHPD_MX>; + + status = "disabled"; + }; + }; + dispcc0: clock-controller@af00000 { compatible = "qcom,nord-dispcc0"; reg = <0x0 0x0af00000 0x0 0x20000>; @@ -1681,10 +2041,10 @@ <0>, <0>, <0>, - <0>, - <0>, - <0>, - <0>, + <&dp0_phy 0>, + <&dp0_phy 1>, + <&dp1_phy 0>, + <&dp1_phy 1>, <0>, <0>, <0>, @@ -1700,6 +2060,7 @@ compatible = "qcom,nord-tcsrcc", "syscon"; reg = <0x0 0x0f1d9000 0x0 0xf00c>; + clocks = <&rpmhcc RPMH_CXO_CLK>; #clock-cells = <1>; #reset-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/nord-ride-sx.dts b/arch/arm64/boot/dts/qcom/nord-ride-sx.dts index fd3274d22bdcb..b63c9c8c50726 100644 --- a/arch/arm64/boot/dts/qcom/nord-ride-sx.dts +++ b/arch/arm64/boot/dts/qcom/nord-ride-sx.dts @@ -94,6 +94,30 @@ }; }; + dp0_connector: connector-dp0 { + compatible = "dp-connector"; + label = "eDP0"; + type = "full-size"; + + port { + dp0_connector_in: endpoint { + remote-endpoint = <&mdss_dp0_out>; + }; + }; + }; + + dp1_connector: connector-dp1 { + compatible = "dp-connector"; + label = "eDP1"; + type = "full-size"; + + port { + dp1_connector_in: endpoint { + remote-endpoint = <&mdss_dp1_out>; + }; + }; + }; + ufs_vdd_hba: regulator-ufs-vdd-hba { compatible = "regulator-fixed"; regulator-name = "ufs_vdd_hba"; @@ -570,6 +594,20 @@ }; }; +&dp0_phy { + vdda-phy-supply = <&vreg_l2h_1p2>; + vdda-pll-supply = <&vreg_l1h_0p9>; + + status = "okay"; +}; + +&dp1_phy { + vdda-phy-supply = <&vreg_l2h_1p2>; + vdda-pll-supply = <&vreg_l1h_0p9>; + + status = "okay"; +}; + &i2c9 { clock-frequency = <400000>; @@ -689,6 +727,36 @@ }; }; +&mdss { + status = "okay"; +}; + +&mdss_dp0 { + pinctrl-0 = <&dp0_hot_plug_det>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&mdss_dp0_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; + remote-endpoint = <&dp0_connector_in>; +}; + +&mdss_dp1 { + pinctrl-0 = <&dp1_hot_plug_det>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&mdss_dp1_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; + remote-endpoint = <&dp1_connector_in>; +}; + &pcie_phy { vdda-phy-a-supply = <&vreg_l6a_1p2>; vdda-phy-b-supply = <&vreg_l4a_1p2>; @@ -805,6 +873,20 @@ status = "okay"; }; +&tlmm { + dp0_hot_plug_det: dp0-hot-plug-det-state { + pins = "gpio51"; + function = "edp0_hot"; + bias-disable; + }; + + dp1_hot_plug_det: dp1-hot-plug-det-state { + pins = "gpio52"; + function = "edp1_hot"; + bias-disable; + }; +}; + &uart15 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/nord-rrd.dts b/arch/arm64/boot/dts/qcom/nord-rrd.dts index a9f08f61b4114..e75addfb51370 100644 --- a/arch/arm64/boot/dts/qcom/nord-rrd.dts +++ b/arch/arm64/boot/dts/qcom/nord-rrd.dts @@ -94,6 +94,30 @@ }; }; + dp0_connector: connector-dp0 { + compatible = "dp-connector"; + label = "eDP0"; + type = "full-size"; + + port { + dp0_connector_in: endpoint { + remote-endpoint = <&mdss_dp0_out>; + }; + }; + }; + + dp1_connector: connector-dp1 { + compatible = "dp-connector"; + label = "eDP1"; + type = "full-size"; + + port { + dp1_connector_in: endpoint { + remote-endpoint = <&mdss_dp1_out>; + }; + }; + }; + vreg_pre_reg_3p3: regulator-pre-reg-3p3 { compatible = "regulator-fixed"; regulator-name = "vreg_pre_reg_3p3"; @@ -546,6 +570,20 @@ }; }; +&dp0_phy { + vdda-phy-supply = <&vreg_l2h_1p2>; + vdda-pll-supply = <&vreg_l1h_0p9>; + + status = "okay"; +}; + +&dp1_phy { + vdda-phy-supply = <&vreg_l2h_1p2>; + vdda-pll-supply = <&vreg_l1h_0p9>; + + status = "okay"; +}; + &i2c7 { clock-frequency = <400000>; @@ -656,6 +694,36 @@ }; }; +&mdss { + status = "okay"; +}; + +&mdss_dp0 { + pinctrl-0 = <&dp0_hot_plug_det>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&mdss_dp0_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; + remote-endpoint = <&dp0_connector_in>; +}; + +&mdss_dp1 { + pinctrl-0 = <&dp1_hot_plug_det>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&mdss_dp1_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; + remote-endpoint = <&dp1_connector_in>; +}; + &pcie_phy { vdda-phy-a-supply = <&vreg_l6a_1p2>; vdda-phy-b-supply = <&vreg_l4a_1p2>; @@ -776,6 +844,20 @@ status = "okay"; }; +&tlmm { + dp0_hot_plug_det: dp0-hot-plug-det-state { + pins = "gpio51"; + function = "edp0_hot"; + bias-disable; + }; + + dp1_hot_plug_det: dp1-hot-plug-det-state { + pins = "gpio52"; + function = "edp1_hot"; + bias-disable; + }; +}; + &uart4 { status = "okay"; }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_1_nord.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_1_nord.h new file mode 100644 index 0000000000000..8eb18752f3c4b --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_1_nord.h @@ -0,0 +1,588 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. + */ + +#ifndef _DPU_12_1_NORD_H +#define _DPU_12_1_NORD_H + +/* + * NORD DPU 12.1 catalog header. Generated from hardware summary YAML for + * MDSS 12.1 - DPU 1499A (Nordschleife). This is a DP-only chip with no DSI. + * + * All register addresses and xin_id values below are borrowed from the + * reference chip (sm8750, MDSS 12.0) and precedent chips (Lemans, Glymur). + * Nord's YAML provides only block counts and feature statements, not addresses. + * See FIXME(REG_ADDR) markers throughout for borrowed values requiring + * verification against a real Nord register map before production use. + * + * Key differences vs sm8750: + * - 8 DSPP blocks (4 full + 4 lite) vs sm8750's 4 + * - 2 writeback blocks (WB1, WB2) vs sm8750's 1 (WB2) + * - 8 interfaces (INTF_0,3,4,6,7,8,9,10) vs sm8750's 4 (INTF_0,1,2,3) + * - 2 DP controllers (DP0, DP1) vs sm8750's 1 (DP0 only) + * - No DSI (removed entirely) + */ + +static const struct dpu_caps nord_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0xb, + .has_src_split = true, + .has_dim_layer = true, + .has_idle_pc = true, + .has_3d_merge = true, + .max_linewidth = 8192, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, +}; + +static const struct dpu_mdp_cfg nord_mdp = { + .name = "top_0", + .base = 0, .len = 0x494, + .clk_ctrls = { + [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, + }, +}; + +static const struct dpu_ctl_cfg nord_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x15000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x16000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x17000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, { + .name = "ctl_3", .id = CTL_3, + .base = 0x18000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, { + .name = "ctl_4", .id = CTL_4, + .base = 0x19000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, { + .name = "ctl_5", .id = CTL_5, + .base = 0x1a000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23), + }, +}; + +static const struct dpu_sspp_cfg nord_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_4, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_4, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_2", .id = SSPP_VIG2, + .base = 0x8000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_4, + .xin_id = 8, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_3", .id = SSPP_VIG3, + .base = 0xa000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_4, + .xin_id = 12, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 1, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_9", .id = SSPP_DMA1, + .base = 0x26000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 5, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_10", .id = SSPP_DMA2, + .base = 0x28000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 9, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_11", .id = SSPP_DMA3, + .base = 0x2a000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 13, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_12", .id = SSPP_DMA4, + .base = 0x2c000, .len = 0x344, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 14, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_13", .id = SSPP_DMA5, + .base = 0x2e000, .len = 0x344, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 15, + .type = SSPP_TYPE_DMA, + }, +}; + +static const struct dpu_lm_cfg nord_lm[] = { + { + .name = "lm_0", .id = LM_0, + .base = 0x44000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_1, + .pingpong = PINGPONG_0, + .dspp = DSPP_0, + }, { + .name = "lm_1", .id = LM_1, + .base = 0x45000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_0, + .pingpong = PINGPONG_1, + .dspp = DSPP_1, + }, { + .name = "lm_2", .id = LM_2, + .base = 0x46000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_3, + .pingpong = PINGPONG_2, + .dspp = DSPP_2, + }, { + .name = "lm_3", .id = LM_3, + .base = 0x47000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_2, + .pingpong = PINGPONG_3, + .dspp = DSPP_3, + }, { + .name = "lm_4", .id = LM_4, + .base = 0x48000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_5, + .pingpong = PINGPONG_4, + }, { + .name = "lm_5", .id = LM_5, + .base = 0x49000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_4, + .pingpong = PINGPONG_5, + }, { + .name = "lm_6", .id = LM_6, + .base = 0x4a000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_7, + .pingpong = PINGPONG_6, + }, { + .name = "lm_7", .id = LM_7, + .base = 0x4b000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_6, + .pingpong = PINGPONG_7, + }, +}; + +/* + * Nord has 8 DSPP blocks: 4 full-featured (DSPP0-3) and 4 lite variants + * (DSPP4-7). The driver has no separate lite-DSPP struct, so all 8 are + * modeled with the same dpu_dspp_cfg/dpu_dspp_sblk structure. Lite variants + * have reduced features, but this is handled at runtime via feature flags, + * not via separate catalog entries. + * FIXME(REG_ADDR): DSPP4-7 base addresses extended via 0x2000 stride from + * sm8750's DSPP3 base (0x5a000). Verify against real Nord register map. + */ +static const struct dpu_dspp_cfg nord_dspp[] = { + { + .name = "dspp_0", .id = DSPP_0, + .base = 0x54000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_1", .id = DSPP_1, + .base = 0x56000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_2", .id = DSPP_2, + .base = 0x58000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_3", .id = DSPP_3, + .base = 0x5a000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_4", .id = DSPP_4, + .base = 0x5c000, .len = 0x1800, /* FIXME(REG_ADDR): lite variant */ + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_5", .id = DSPP_5, + .base = 0x5e000, .len = 0x1800, /* FIXME(REG_ADDR): lite variant */ + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_6", .id = DSPP_6, + .base = 0x60000, .len = 0x1800, /* FIXME(REG_ADDR): lite variant */ + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_7", .id = DSPP_7, + .base = 0x62000, .len = 0x1800, /* FIXME(REG_ADDR): lite variant */ + .sblk = &sm8750_dspp_sblk, + }, +}; + +static const struct dpu_pingpong_cfg nord_pp[] = { + { + .name = "pingpong_0", .id = PINGPONG_0, + .base = 0x69000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + }, { + .name = "pingpong_1", .id = PINGPONG_1, + .base = 0x6a000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + }, { + .name = "pingpong_2", .id = PINGPONG_2, + .base = 0x6b000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + }, { + .name = "pingpong_3", .id = PINGPONG_3, + .base = 0x6c000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + }, { + .name = "pingpong_4", .id = PINGPONG_4, + .base = 0x6d000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), + }, { + .name = "pingpong_5", .id = PINGPONG_5, + .base = 0x6e000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), + }, { + .name = "pingpong_6", .id = PINGPONG_6, + .base = 0x6f000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 20), + }, { + .name = "pingpong_7", .id = PINGPONG_7, + .base = 0x70000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 21), + }, { + .name = "pingpong_cwb_0", .id = PINGPONG_CWB_0, + .base = 0x66000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_4, + }, { + .name = "pingpong_cwb_1", .id = PINGPONG_CWB_1, + .base = 0x66400, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_4, + }, { + .name = "pingpong_cwb_2", .id = PINGPONG_CWB_2, + .base = 0x7e000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_5, + }, { + .name = "pingpong_cwb_3", .id = PINGPONG_CWB_3, + .base = 0x7e400, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_5, + }, +}; + +static const struct dpu_merge_3d_cfg nord_merge_3d[] = { + { + .name = "merge_3d_0", .id = MERGE_3D_0, + .base = 0x4e000, .len = 0x1c, + }, { + .name = "merge_3d_1", .id = MERGE_3D_1, + .base = 0x4f000, .len = 0x1c, + }, { + .name = "merge_3d_2", .id = MERGE_3D_2, + .base = 0x50000, .len = 0x1c, + }, { + .name = "merge_3d_3", .id = MERGE_3D_3, + .base = 0x51000, .len = 0x1c, + }, { + .name = "merge_3d_4", .id = MERGE_3D_4, + .base = 0x66700, .len = 0x1c, + }, { + .name = "merge_3d_5", .id = MERGE_3D_5, + .base = 0x7e700, .len = 0x1c, + }, +}; + +/* + * NOTE: Each display compression engine (DCE) contains dual hard + * slice DSC encoders so both share same base address but with + * its own different sub block address. Nord retains sm8750's + * topology of 8 DSC instances (2 per DCE × 4). + */ +static const struct dpu_dsc_cfg nord_dsc[] = { + { + .name = "dce_0_0", .id = DSC_0, + .base = 0x80000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_0_1", .id = DSC_1, + .base = 0x80000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, { + .name = "dce_1_0", .id = DSC_2, + .base = 0x81000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_1_1", .id = DSC_3, + .base = 0x81000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, { + .name = "dce_2_0", .id = DSC_4, + .base = 0x82000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_2_1", .id = DSC_5, + .base = 0x82000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, { + .name = "dce_3_0", .id = DSC_6, + .base = 0x83000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_3_1", .id = DSC_7, + .base = 0x83000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, +}; + +/* + * Nord has 2 writeback blocks: WB2 (matches sm8750) and WB1 (new). + * WB1 base and xin_id are inferred via stride from existing WB pattern. + * FIXME(REG_ADDR): WB1 base address inferred as 0x65000 - 0x2c8 stride. + * FIXME(XIU_MAP): WB1 xin_id set to 7; verify against real hardware map. + */ +static const struct dpu_wb_cfg nord_wb[] = { + { + .name = "wb_1", .id = WB_1, + .base = 0x64800, .len = 0x2c8, /* FIXME(REG_ADDR): inferred */ + .features = WB_SDM845_MASK, + .format_list = wb2_formats_rgb_yuv, + .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), + .xin_id = 7, /* FIXME(XIU_MAP): inferred */ + .maxlinewidth = 4096, + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 3), + }, { + .name = "wb_2", .id = WB_2, + .base = 0x65000, .len = 0x2c8, + .features = WB_SDM845_MASK, + .format_list = wb2_formats_rgb_yuv, + .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), + .xin_id = 6, + .maxlinewidth = 4096, + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), + }, +}; + +static const struct dpu_cwb_cfg nord_cwb[] = { + { + .name = "cwb_0", .id = CWB_0, + .base = 0x66200, .len = 0x20, + }, + { + .name = "cwb_1", .id = CWB_1, + .base = 0x66600, .len = 0x20, + }, + { + .name = "cwb_2", .id = CWB_2, + .base = 0x7e200, .len = 0x20, + }, + { + .name = "cwb_3", .id = CWB_3, + .base = 0x7e600, .len = 0x20, + }, +}; + +/* + * Nord has 8 active interfaces (INTF_0,3,4,6,7,8,9,10) with no DSI. + * DP0 connects to INTF_0, INTF_3, INTF_6, INTF_7 (4 ports for MST). + * DP1 connects to INTF_4, INTF_8, INTF_9, INTF_10 (4 ports for MST). + * Interfaces 1, 2, 5 are skipped (removed from sm8750). + * All interface base addresses extend the stride from sm8750. + * FIXME(REG_ADDR): INTF_4,6,7,8,9,10 addresses inferred via 0x1000 stride. + */ +static const struct dpu_intf_cfg nord_intf[] = { + { + .name = "intf_0", .id = INTF_0, + .base = 0x34000, .len = 0x4bc, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_0, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25), + }, { + .name = "intf_3", .id = INTF_3, + .base = 0x37000, .len = 0x4bc, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), + }, { + .name = "intf_4", .id = INTF_4, + .base = 0x38000, .len = 0x4bc, /* FIXME(REG_ADDR): new, stride +0x1000 */ + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_1, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 20), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 21), + }, { + .name = "intf_6", .id = INTF_6, + .base = 0x3a000, .len = 0x4bc, /* FIXME(REG_ADDR): new, stride +0x3000 */ + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_0, /* second pair for DP0 MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 22), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 23), + }, { + .name = "intf_7", .id = INTF_7, + .base = 0x3b000, .len = 0x4bc, /* FIXME(REG_ADDR): new, stride +0x4000 */ + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_0, /* third pair for DP0 MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 0), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 1), + }, { + .name = "intf_8", .id = INTF_8, + .base = 0x3c000, .len = 0x4bc, /* FIXME(REG_ADDR): new, stride +0x5000 */ + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_1, /* second pair for DP1 MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 2), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 3), + }, { + .name = "intf_9", .id = INTF_9, + .base = 0x3d000, .len = 0x4bc, /* FIXME(REG_ADDR): new, stride +0x6000 */ + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_1, /* third pair for DP1 MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 4), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 5), + }, { + .name = "intf_10", .id = INTF_10, + .base = 0x3e000, .len = 0x4bc, /* FIXME(REG_ADDR): new, stride +0x7000 */ + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_1, /* fourth pair for DP1 MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 6), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 7), + }, +}; + +static const struct dpu_perf_cfg nord_perf_data = { + .max_bw_low = 18900000, + .max_bw_high = 28500000, + .min_core_ib = 2500000, + .min_llcc_ib = 0, + .min_dram_ib = 800000, + .min_prefill_lines = 35, + .danger_lut_tbl = {0x3ffff, 0x3ffff, 0x0}, + .safe_lut_tbl = {0xfe00, 0xfe00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sc7180_qos_linear), + .entries = sc7180_qos_linear + }, + {.nentry = ARRAY_SIZE(sc7180_qos_macrotile), + .entries = sc7180_qos_macrotile + }, + {.nentry = ARRAY_SIZE(sc7180_qos_nrt), + .entries = sc7180_qos_nrt + }, + /* TODO: macrotile-qseed is different from macrotile */ + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + +static const struct dpu_mdss_version nord_mdss_ver = { + .core_major_ver = 12, + .core_minor_ver = 1, +}; + +const struct dpu_mdss_cfg dpu_nord_cfg = { + .mdss_ver = &nord_mdss_ver, + .caps = &nord_dpu_caps, + .mdp = &nord_mdp, + .cdm = &dpu_cdm_5_x, + .ctl_count = ARRAY_SIZE(nord_ctl), + .ctl = nord_ctl, + .sspp_count = ARRAY_SIZE(nord_sspp), + .sspp = nord_sspp, + .mixer_count = ARRAY_SIZE(nord_lm), + .mixer = nord_lm, + .dspp_count = ARRAY_SIZE(nord_dspp), + .dspp = nord_dspp, + .pingpong_count = ARRAY_SIZE(nord_pp), + .pingpong = nord_pp, + .dsc_count = ARRAY_SIZE(nord_dsc), + .dsc = nord_dsc, + .merge_3d_count = ARRAY_SIZE(nord_merge_3d), + .merge_3d = nord_merge_3d, + .wb_count = ARRAY_SIZE(nord_wb), + .wb = nord_wb, + .cwb_count = ARRAY_SIZE(nord_cwb), + .cwb = nord_cwb, + .intf_count = ARRAY_SIZE(nord_intf), + .intf = nord_intf, + .vbif = &sm8650_vbif, + .perf = &nord_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 2e10add84fd71..8bae9f80ea5d3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -784,6 +784,7 @@ static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = { #include "catalog/dpu_10_2_milos.h" #include "catalog/dpu_12_0_sm8750.h" +#include "catalog/dpu_12_1_nord.h" #include "catalog/dpu_12_2_glymur.h" #include "catalog/dpu_12_4_eliza.h" #include "catalog/dpu_13_0_kaanapali.h" diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index f45faf87333e8..4f948b34284d5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -796,6 +796,7 @@ extern const struct dpu_mdss_cfg dpu_sa8775p_cfg; extern const struct dpu_mdss_cfg dpu_sm8550_cfg; extern const struct dpu_mdss_cfg dpu_sm8650_cfg; extern const struct dpu_mdss_cfg dpu_sm8750_cfg; +extern const struct dpu_mdss_cfg dpu_nord_cfg; extern const struct dpu_mdss_cfg dpu_x1e80100_cfg; #endif /* _DPU_HW_CATALOG_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h index 0e65bf5ddc4a6..7eccb4d2c65ef 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h @@ -226,6 +226,8 @@ enum dpu_intf { INTF_6, INTF_7, INTF_8, + INTF_9, + INTF_10, INTF_MAX }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index b27fb266ef0f4..ffa792213939a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1542,6 +1542,7 @@ static const struct of_device_id dpu_dt_match[] = { { .compatible = "qcom,sm8550-dpu", .data = &dpu_sm8550_cfg, }, { .compatible = "qcom,sm8650-dpu", .data = &dpu_sm8650_cfg, }, { .compatible = "qcom,sm8750-dpu", .data = &dpu_sm8750_cfg, }, + { .compatible = "qcom,nord-dpu", .data = &dpu_nord_cfg, }, { .compatible = "qcom,x1e80100-dpu", .data = &dpu_x1e80100_cfg, }, {} }; diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 6f21a60f251d7..583092b072932 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -113,6 +113,12 @@ static const struct msm_dp_desc msm_dp_desc_glymur[] = { {} }; +static const struct msm_dp_desc msm_dp_desc_nord[] = { + { .io_start = 0x0af54000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, + { .io_start = 0x0af5c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, + {} +}; + static const struct msm_dp_desc msm_dp_desc_sa8775p[] = { { .io_start = 0x0af54000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, { .io_start = 0x0af5c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, @@ -171,6 +177,7 @@ static const struct msm_dp_desc msm_dp_desc_x1e80100[] = { static const struct of_device_id msm_dp_dt_match[] = { { .compatible = "qcom,glymur-dp", .data = &msm_dp_desc_glymur }, + { .compatible = "qcom,nord-dp", .data = &msm_dp_desc_nord }, { .compatible = "qcom,sa8775p-dp", .data = &msm_dp_desc_sa8775p }, { .compatible = "qcom,sc7180-dp", .data = &msm_dp_desc_sc7180 }, { .compatible = "qcom,sc7280-dp", .data = &msm_dp_desc_sc7280 }, diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 03f27e6b0ae7b..86ddef2eec1e0 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -555,6 +555,7 @@ static const struct of_device_id mdss_dt_match[] = { { .compatible = "qcom,sm8550-mdss", .data = &data_57k }, { .compatible = "qcom,sm8650-mdss", .data = &data_57k }, { .compatible = "qcom,sm8750-mdss", .data = &data_57k }, + { .compatible = "qcom,nord-mdss", .data = &data_57k }, /* TODO: x1e8: Add reg_bus_bw with real value */ { .compatible = "qcom,x1e80100-mdss", .data = &data_153k6 }, {} diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index a3c893f72908f..f78d5e5adf9c0 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -41,9 +41,19 @@ #define DP_PHY_VCO_DIV 0x0074 #define DP_PHY_TX0_TX1_LANE_CTL 0x007c +/* Nord uses a different register layout; non-Nord value is 0x00a0 */ #define DP_PHY_TX2_TX3_LANE_CTL 0x00a0 +#define DP_PHY_TX2_TX3_LANE_CTL_NORD 0x00c0 +/* Nord uses a different register layout; non-Nord value is 0x00e0 */ #define DP_PHY_STATUS 0x00e0 +#define DP_PHY_STATUS_NORD 0x0110 +#define DP_PHY_LDO_CFG 0x00f0 + +/* Nord-specific TX lane registers */ +#define DP_PHY_TX_LN0_DRV_LVL_NORD 0x00e4 +#define DP_PHY_TX_LN1_DRV_LVL_NORD 0x00e8 +#define TXn_TX_BAND_NORD 0x0024 /* LANE_TXn registers */ #define TXn_CLKBUF_ENABLE 0x0000 @@ -86,6 +96,7 @@ struct phy_ver_ops { struct qcom_edp_phy_cfg { bool is_edp; + bool is_nord; const u8 *aux_cfg; const u8 *vco_div_cfg; const struct qcom_edp_swing_pre_emph_cfg *dp_swing_pre_emph_cfg; @@ -115,6 +126,7 @@ struct qcom_edp { struct regulator_bulk_data supplies[2]; bool is_edp; + bool is_nord; }; static const u8 dp_swing_hbr_rbr[4][4] = { @@ -306,9 +318,11 @@ static int qcom_edp_phy_init(struct phy *phy) memcpy(aux_cfg, edp->cfg->aux_cfg, sizeof(aux_cfg)); - ret = edp->cfg->ver_ops->com_clk_fwd_cfg(edp); - if (ret) - return ret; + if (!edp->is_nord) { + ret = edp->cfg->ver_ops->com_clk_fwd_cfg(edp); + if (ret) + return ret; + } writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, @@ -331,8 +345,11 @@ static int qcom_edp_phy_init(struct phy *phy) writel(0xfc, edp->edp + DP_PHY_MODE); - for (int i = 0; i < DP_AUX_CFG_SIZE; i++) + for (int i = 0; i < DP_AUX_CFG_SIZE; i++) { writel(aux_cfg[i], edp->edp + DP_PHY_AUX_CFG(i)); + if (edp->is_nord && i == 3) + writel(0x00, edp->edp + DP_PHY_AUX_CFG(i)); + } writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK | @@ -1121,7 +1138,13 @@ static int qcom_edp_phy_power_on(struct phy *phy) /* TX Lane configuration */ writel(0x05, edp->edp + DP_PHY_TX0_TX1_LANE_CTL); - writel(0x05, edp->edp + DP_PHY_TX2_TX3_LANE_CTL); + if (edp->is_nord) { + writel(0x05, edp->edp + DP_PHY_TX2_TX3_LANE_CTL_NORD); + writel(0x12, edp->edp + DP_PHY_TX_LN0_DRV_LVL_NORD); + writel(0x12, edp->edp + DP_PHY_TX_LN1_DRV_LVL_NORD); + } else { + writel(0x05, edp->edp + DP_PHY_TX2_TX3_LANE_CTL); + } /* TX-0 register configuration */ writel(0x03, edp->tx0 + TXn_TRANSCEIVER_BIAS_EN); @@ -1129,6 +1152,8 @@ static int qcom_edp_phy_power_on(struct phy *phy) writel(0x03, edp->tx0 + TXn_RESET_TSYNC_EN); writel(0x01, edp->tx0 + TXn_TRAN_DRVR_EMP_EN); writel(0x04, edp->tx0 + TXn_TX_BAND); + if (edp->is_nord) + writel(0x05, edp->tx0 + TXn_TX_BAND_NORD); /* TX-1 register configuration */ writel(0x03, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN); @@ -1136,6 +1161,8 @@ static int qcom_edp_phy_power_on(struct phy *phy) writel(0x03, edp->tx1 + TXn_RESET_TSYNC_EN); writel(0x01, edp->tx1 + TXn_TRAN_DRVR_EMP_EN); writel(0x04, edp->tx1 + TXn_TX_BAND); + if (edp->is_nord) + writel(0x05, edp->tx1 + TXn_TX_BAND_NORD); ret = qcom_edp_set_vco_div(edp, &pixel_freq); if (ret) @@ -1159,13 +1186,21 @@ static int qcom_edp_phy_power_on(struct phy *phy) writel(0x00, edp->tx1 + TXn_TX_POL_INV); writel(0x10, edp->tx0 + TXn_TX_DRV_LVL_OFFSET); writel(0x10, edp->tx1 + TXn_TX_DRV_LVL_OFFSET); - writel(0x11, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX0); - writel(0x11, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX1); - writel(0x11, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX0); - writel(0x11, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX1); - - writel(0x10, edp->tx0 + TXn_TX_EMP_POST1_LVL); - writel(0x10, edp->tx1 + TXn_TX_EMP_POST1_LVL); + if (edp->is_nord) { + writel(0x06, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX0); + writel(0x06, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX1); + writel(0x06, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX0); + writel(0x06, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX1); + writel(0x06, edp->tx0 + TXn_TX_EMP_POST1_LVL); + writel(0x06, edp->tx1 + TXn_TX_EMP_POST1_LVL); + } else { + writel(0x11, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX0); + writel(0x11, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX1); + writel(0x11, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX0); + writel(0x11, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX1); + writel(0x10, edp->tx0 + TXn_TX_EMP_POST1_LVL); + writel(0x10, edp->tx1 + TXn_TX_EMP_POST1_LVL); + } writel(0x1f, edp->tx0 + TXn_TX_DRV_LVL); writel(0x1f, edp->tx1 + TXn_TX_DRV_LVL); @@ -1177,7 +1212,7 @@ static int qcom_edp_phy_power_on(struct phy *phy) cfg1 = 0x1; } else if (edp->dp_opts.lanes == 2) { bias0_en = 0x03; - bias1_en = 0x00; + bias1_en = edp->is_nord ? 0x03 : 0x00; drvr0_en = 0x04; drvr1_en = 0x07; cfg1 = 0x3; @@ -1200,7 +1235,7 @@ static int qcom_edp_phy_power_on(struct phy *phy) writel(0x19, edp->edp + DP_PHY_CFG); - ret = readl_poll_timeout(edp->edp + DP_PHY_STATUS, + ret = readl_poll_timeout(edp->edp + (edp->is_nord ? DP_PHY_STATUS_NORD : DP_PHY_STATUS), val, val & BIT(1), 500, 10000); if (ret) return ret; @@ -1426,6 +1461,7 @@ static int qcom_edp_phy_probe(struct platform_device *pdev) edp->dev = dev; edp->cfg = of_device_get_match_data(&pdev->dev); edp->is_edp = edp->cfg->is_edp; + edp->is_nord = edp->cfg->is_nord; edp->edp = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(edp->edp)) @@ -1481,8 +1517,350 @@ static int qcom_edp_phy_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(phy_provider); } + + +/* + * nord AUX config (eDP mode). + * From HPG Table 2-1-a: edp_phy_aux_bist.csv + * Index: 0 1 2 3 4 5 6 7 8 9 10 11 12 + */ +static const u8 edp_phy_aux_cfg_nord[DP_AUX_CFG_SIZE] = { + 0x00, 0x13, 0xa4, 0x01, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03, 0x02, 0x02, 0x04, +}; + +/* + * nord VCO_DIV config for eDP mode. + * From HPG Table 2-1-b AUX Clock Settings (eDP mode) – Nominal/Turbo column. + * Indices: [0]=1620, [1]=2700, [2]=5400, [3]=8100 + */ +static const u8 edp_phy_vco_div_cfg_nord[4] = { + 0x00, 0x00, 0x02, 0x01, +}; + +/* + * nord eDP swing/pre-emphasis tables (eDP mode, low HBR: RBR/HBR). + * From HPG Table 2-2: LDO ON 550mV (0x51). + * Rates: 1.62/2.16/2.43/2.7 Gbps + */ +static const u8 nord_edp_swing_hbr_rbr[4][4] = { + { 0x07, 0x0f, 0x16, 0x1f }, + { 0x0d, 0x16, 0x1e, 0xff }, + { 0x11, 0x1b, 0xff, 0xff }, + { 0x16, 0xff, 0xff, 0xff }, +}; + +static const u8 nord_edp_pre_emp_hbr_rbr[4][4] = { + { 0x05, 0x11, 0x17, 0x1d }, + { 0x05, 0x11, 0x18, 0xff }, + { 0x06, 0x11, 0xff, 0xff }, + { 0x00, 0xff, 0xff, 0xff }, +}; + +/* + * nord eDP swing/pre-emphasis tables (eDP mode, high HBR: HBR2/HBR3). + * From HPG Table 2-4: LDO ON 660mV (0x91). + * Rates: 3.24/4.32/5.4/5.94/8.1 Gbps + */ +static const u8 nord_edp_swing_hbr2_hbr3[4][4] = { + { 0x0b, 0x11, 0x17, 0x1c }, + { 0x10, 0x19, 0x1f, 0xff }, + { 0x19, 0x1f, 0xff, 0xff }, + { 0x1f, 0xff, 0xff, 0xff }, +}; + +static const u8 nord_edp_pre_emp_hbr2_hbr3[4][4] = { + { 0x0c, 0x15, 0x19, 0x1e }, + { 0x0b, 0x15, 0x19, 0xff }, + { 0x0e, 0x14, 0xff, 0xff }, + { 0x0d, 0xff, 0xff, 0xff }, +}; + +static const struct qcom_edp_swing_pre_emph_cfg nord_edp_swing_pre_emph_cfg = { + .swing_hbr_rbr = &nord_edp_swing_hbr_rbr, + .swing_hbr3_hbr2 = &nord_edp_swing_hbr2_hbr3, + .pre_emphasis_hbr_rbr = &nord_edp_pre_emp_hbr_rbr, + .pre_emphasis_hbr3_hbr2 = &nord_edp_pre_emp_hbr2_hbr3, +}; + +/* + * nord DP swing/pre-emphasis tables (DP mode, COMBO_PHYS TypeC). + * From HPG Table 2-6-a (HBR3/HBR2) and Table 2-6-b (HBR/RBR). + */ +static const u8 nord_dp_swing_hbr2_hbr3[4][4] = { + { 0x02, 0x12, 0x16, 0x1a }, + { 0x09, 0x19, 0x1f, 0xff }, + { 0x10, 0x1f, 0xff, 0xff }, + { 0x1f, 0xff, 0xff, 0xff }, +}; + +static const u8 nord_dp_pre_emp_hbr2_hbr3[4][4] = { + { 0x00, 0x0c, 0x15, 0x1b }, + { 0x02, 0x0e, 0x16, 0xff }, + { 0x02, 0x11, 0xff, 0xff }, + { 0x04, 0xff, 0xff, 0xff }, +}; + +static const u8 nord_dp_swing_hbr_rbr[4][4] = { + { 0x07, 0x0f, 0x16, 0x1f }, + { 0x11, 0x1e, 0x1f, 0xff }, + { 0x16, 0x1f, 0xff, 0xff }, + { 0x1f, 0xff, 0xff, 0xff }, +}; + +static const u8 nord_dp_pre_emp_hbr_rbr[4][4] = { + { 0x00, 0x0e, 0x15, 0x1a }, + { 0x00, 0x0e, 0x15, 0xff }, + { 0x00, 0x0e, 0xff, 0xff }, + { 0x02, 0xff, 0xff, 0xff }, +}; + +static const struct qcom_edp_swing_pre_emph_cfg nord_dp_swing_pre_emph_cfg = { + .swing_hbr_rbr = &nord_dp_swing_hbr_rbr, + .swing_hbr3_hbr2 = &nord_dp_swing_hbr2_hbr3, + .pre_emphasis_hbr_rbr = &nord_dp_pre_emp_hbr_rbr, + .pre_emphasis_hbr3_hbr2 = &nord_dp_pre_emp_hbr2_hbr3, +}; + +static int qcom_edp_phy_power_on_nord(const struct qcom_edp *edp) +{ + u32 val; + + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | + DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | + DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, + edp->edp + DP_PHY_PD_CTL); + writel(0xfc, edp->edp + DP_PHY_MODE); + + return readl_poll_timeout(edp->pll + DP_QSERDES_V8_COM_CMN_STATUS_V2, + val, val & BIT(7), 5, 200); +} + +static int qcom_edp_phy_com_resetsm_cntrl_nord(const struct qcom_edp *edp) +{ + u32 val; + + writel(0x20, edp->pll + DP_QSERDES_V8_COM_RESETSM_CNTRL); + + return readl_poll_timeout(edp->pll + DP_QSERDES_V8_COM_C_READY_STATUS_V2, + val, val & BIT(0), 500, 10000); +} + +static int qcom_edp_com_bias_en_clkbuflr_nord(const struct qcom_edp *edp) +{ + /* + * From HPG Table 2-1-d: Enable bias PLL. + * QSERDES_COM_BIAS_EN_CLKBUFLR_EN = 0x1F + */ + writel(0x1f, edp->pll + DP_QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN); + + return 0; +} + +/* + * nord SSC settings. + * From HPG Table 2-9: SSC settings for all speed combinations. + * SSC_PER1 = 0x6B, SSC_PER2 = 0x02 for all rates. + * SSC_STEP_SIZE1/2 are rate-dependent. + */ +static int qcom_edp_com_configure_ssc_nord(const struct qcom_edp *edp) +{ + const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; + u32 step1; + u32 step2; + + switch (dp_opts->link_rate) { + case 1620: + step1 = 0x83; + step2 = 0x02; + break; + + case 2700: + case 5400: + step1 = 0x18; + step2 = 0x02; + break; + + case 8100: + step1 = 0x5b; + step2 = 0x02; + break; + + default: + return -EINVAL; + } + + writel(0x01, edp->pll + DP_QSERDES_V8_COM_SSC_EN_CENTER); + writel(0x00, edp->pll + DP_QSERDES_V8_COM_SSC_ADJ_PER1); + writel(0x6b, edp->pll + DP_QSERDES_V8_COM_SSC_PER1); + writel(0x02, edp->pll + DP_QSERDES_V8_COM_SSC_PER2); + writel(step1, edp->pll + DP_QSERDES_V8_COM_SSC_STEP_SIZE1_MODE0); + writel(step2, edp->pll + DP_QSERDES_V8_COM_SSC_STEP_SIZE2_MODE0); + + return 0; +} + +/* + * nord PLL configuration. + * From HPG Table 2-1-d: DP PLL Config section. + * CXO = 38.4 MHz. + */ +static int qcom_edp_com_configure_pll_nord(const struct qcom_edp *edp) +{ + const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; + u32 div_frac_start1_mode0; + u32 div_frac_start2_mode0; + u32 div_frac_start3_mode0; + u32 dec_start_mode0; + u32 lock_cmp1_mode0; + u32 lock_cmp2_mode0; + u32 lock_cmp_en; + u32 hsclk_sel; + u32 code1_mode0; + u32 code2_mode0; + u32 core_clk_div_mode0 = 0x14; + + /* + * PLL settings from HPG Table 2-1-d for each supported data rate. + * Supported: 1.62, 2.7, 5.4, 8.1 Gbps (RBR, HBR, HBR2, HBR3). + */ + switch (dp_opts->link_rate) { + case 1620: + hsclk_sel = 0x0c; + dec_start_mode0 = 0x54; + div_frac_start1_mode0 = 0x00; + div_frac_start2_mode0 = 0x00; + div_frac_start3_mode0 = 0x06; + lock_cmp1_mode0 = 0x37; + lock_cmp2_mode0 = 0x04; + lock_cmp_en = 0x04; + code1_mode0 = 0x8d; + code2_mode0 = 0x27; + break; + + case 2700: + hsclk_sel = 0x04; + dec_start_mode0 = 0x46; + div_frac_start1_mode0 = 0x00; + div_frac_start2_mode0 = 0x00; + div_frac_start3_mode0 = 0x05; + lock_cmp1_mode0 = 0x07; + lock_cmp2_mode0 = 0x07; + lock_cmp_en = 0x08; + code1_mode0 = 0xf6; + code2_mode0 = 0x20; + break; + + case 5400: + hsclk_sel = 0x01; + dec_start_mode0 = 0x46; + div_frac_start1_mode0 = 0x00; + div_frac_start2_mode0 = 0x00; + div_frac_start3_mode0 = 0x05; + lock_cmp1_mode0 = 0x0f; + lock_cmp2_mode0 = 0x0e; + lock_cmp_en = 0x08; + code1_mode0 = 0xf6; + code2_mode0 = 0x20; + break; + + case 8100: + hsclk_sel = 0x03; + dec_start_mode0 = 0x4f; + div_frac_start1_mode0 = 0x00; + div_frac_start2_mode0 = 0xa0; + div_frac_start3_mode0 = 0x01; + lock_cmp1_mode0 = 0x17; + lock_cmp2_mode0 = 0x15; + lock_cmp_en = 0x08; + code1_mode0 = 0x14; + code2_mode0 = 0x25; + core_clk_div_mode0 = 0x0A; + break; + + default: + return -EINVAL; + } + + /* Common PLL settings from HPG Table 2-1-d */ + writel(0x01, edp->pll + DP_QSERDES_V8_COM_SVS_MODE_CLK_SEL_V2); + writel(0x0b, edp->pll + DP_QSERDES_V8_COM_SYSCLK_EN_SEL); + writel(0x02, edp->pll + DP_QSERDES_V8_COM_SYS_CLK_CTRL); + writel(0x0c, edp->pll + DP_QSERDES_V8_COM_CLK_ENABLE1); + writel(0x06, edp->pll + DP_QSERDES_V8_COM_SYSCLK_BUF_ENABLE); + writel(0x30, edp->pll + DP_QSERDES_V8_COM_CLK_SELECT); + writel(hsclk_sel, edp->pll + DP_QSERDES_V8_COM_HSCLK_SEL_1); + writel(0x07, edp->pll + DP_QSERDES_V8_COM_PLL_IVCO); + writel(lock_cmp_en, edp->pll + DP_QSERDES_V8_COM_LOCK_CMP_EN); + writel(0x36, edp->pll + DP_QSERDES_V8_COM_PLL_CCTRL_MODE0); + writel(0x16, edp->pll + DP_QSERDES_V8_COM_PLL_RCTRL_MODE0); + writel(0x06, edp->pll + DP_QSERDES_V8_COM_CP_CTRL_MODE0); + writel(dec_start_mode0, edp->pll + DP_QSERDES_V8_COM_DEC_START_MODE0); + writel(div_frac_start1_mode0, edp->pll + DP_QSERDES_V8_COM_DIV_FRAC_START1_MODE0); + writel(div_frac_start2_mode0, edp->pll + DP_QSERDES_V8_COM_DIV_FRAC_START2_MODE0); + writel(div_frac_start3_mode0, edp->pll + DP_QSERDES_V8_COM_DIV_FRAC_START3_MODE0); + writel(0x12, edp->pll + DP_QSERDES_V8_COM_CMN_CONFIG_1); + writel(0x3f, edp->pll + DP_QSERDES_V8_COM_INTEGLOOP_GAIN0_MODE0); + writel(0x00, edp->pll + DP_QSERDES_V8_COM_INTEGLOOP_GAIN1_MODE0); + writel(0x00, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE_MAP); + writel(lock_cmp1_mode0, edp->pll + DP_QSERDES_V8_COM_LOCK_CMP1_MODE0); + writel(lock_cmp2_mode0, edp->pll + DP_QSERDES_V8_COM_LOCK_CMP2_MODE0); + + writel(0x0a, edp->pll + DP_QSERDES_V8_COM_BG_TIMER); + writel(core_clk_div_mode0, edp->pll + DP_QSERDES_V8_COM_CORECLK_DIV_MODE0); + writel(0x00, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE_CTRL); + writel(0x1D, edp->pll + DP_QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN); // May be 0x17 + writel(0x0f, edp->pll + DP_QSERDES_V8_COM_CORE_CLK_EN); + writel(code1_mode0, edp->pll + DP_QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE0); + writel(code2_mode0, edp->pll + DP_QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE0); + + return 0; +} + +/* + * nord LDO configuration. + * From HPG Table 2-1-d: LDO Configuration section. + * eDP mode: 0xD1 for rates <= 8.1 Gbps, 0x00 for UHBR (>8.1 Gbps). + * DP mode: always 0x00. + * Also programs EDP2_DP_PHY_LDO_CFG: 0x03 for eDP rates <= 8.1G, 0x00 otherwise. + */ +static int qcom_edp_ldo_config_nord(const struct qcom_edp *edp) +{ + const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; + u32 ldo_config; + u32 phy_ldo_cfg; + + ldo_config = 0xd0; + phy_ldo_cfg = 0x03; + + writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG); + writel(dp_opts->lanes > 2 ? ldo_config : 0x00, edp->tx1 + TXn_LDO_CONFIG); + writel(phy_ldo_cfg, edp->edp + DP_PHY_LDO_CFG); + + return 0; +} + +static const struct phy_ver_ops qcom_edp_phy_ops_nord = { + .com_power_on = qcom_edp_phy_power_on_nord, + .com_resetsm_cntrl = qcom_edp_phy_com_resetsm_cntrl_nord, + .com_bias_en_clkbuflr = qcom_edp_com_bias_en_clkbuflr_nord, + .com_configure_pll = qcom_edp_com_configure_pll_nord, + .com_configure_ssc = qcom_edp_com_configure_ssc_nord, + .com_ldo_config = qcom_edp_ldo_config_nord, +}; + +static const struct qcom_edp_phy_cfg nord_edp_phy_cfg = { + .is_edp = false, + .is_nord = true, + .aux_cfg = edp_phy_aux_cfg_nord, + .vco_div_cfg = edp_phy_vco_div_cfg_nord, + .dp_swing_pre_emph_cfg = &nord_dp_swing_pre_emph_cfg, + .edp_swing_pre_emph_cfg = &nord_edp_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_nord, +}; + static const struct of_device_id qcom_edp_phy_match_table[] = { { .compatible = "qcom,glymur-dp-phy", .data = &glymur_phy_cfg, }, + { .compatible = "qcom,nord-dp-phy", .data = &nord_edp_phy_cfg, }, { .compatible = "qcom,sa8775p-edp-phy", .data = &sa8775p_dp_phy_cfg, }, { .compatible = "qcom,sc7280-edp-phy", .data = &sc7280_dp_phy_cfg, }, { .compatible = "qcom,sc8180x-edp-phy", .data = &sc8180x_dp_phy_cfg, }, diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-dp-com-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-dp-com-v8.h index 93edabb830af7..09e3f47440fc8 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-dp-com-v8.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-dp-com-v8.h @@ -48,5 +48,8 @@ #define DP_QSERDES_V8_COM_CLK_FWD_CONFIG_1 0x2f4 #define DP_QSERDES_V8_COM_CMN_STATUS 0x314 #define DP_QSERDES_V8_COM_C_READY_STATUS 0x33c +#define DP_QSERDES_V8_COM_SVS_MODE_CLK_SEL_V2 0x17c +#define DP_QSERDES_V8_COM_CMN_STATUS_V2 0x1d0 +#define DP_QSERDES_V8_COM_C_READY_STATUS_V2 0x1f8 #endif