From 0cb9c31770c25e343baae3f61093f455f46c35aa Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Thu, 11 Sep 2025 19:24:01 +0800 Subject: [PATCH 01/67] FROMLIST: dt-bindings: display/msm: Document the DPU for QCS8300 Document the DPU for Qualcomm QCS8300 platform. It use the same DPU hardware with SA8775P and reuse it's driver. Link:https://lore.kernel.org/all/20250911-qcs8300_mdss-v12-1-5f7d076e2b81@oss.qualcomm.com/ Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yongxing Mou --- .../bindings/display/msm/qcom,sm8650-dpu.yaml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml index 0a46120dd8680..d9b980a897229 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml @@ -13,11 +13,16 @@ $ref: /schemas/display/msm/dpu-common.yaml# properties: compatible: - enum: - - qcom,sa8775p-dpu - - qcom,sm8650-dpu - - qcom,sm8750-dpu - - qcom,x1e80100-dpu + oneOf: + - enum: + - qcom,sa8775p-dpu + - qcom,sm8650-dpu + - qcom,sm8750-dpu + - qcom,x1e80100-dpu + - items: + - enum: + - qcom,qcs8300-dpu + - const: qcom,sa8775p-dpu reg: items: From 6bd697262553657a8b0d7b60423ac2a8550bdfb6 Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Thu, 11 Sep 2025 19:24:02 +0800 Subject: [PATCH 02/67] FROMLIST: dt-bindings: display/msm: dp-controller: document QCS8300 compatible Add compatible string for the DisplayPort controller found on the Qualcomm QCS8300 SoC. The Qualcomm QCS8300 platform comes with one DisplayPort controller that supports 4 MST streams, similar to the one found on the SA8775P. Link:https://lore.kernel.org/all/20250911-qcs8300_mdss-v12-2-5f7d076e2b81@oss.qualcomm.com/ Signed-off-by: Yongxing Mou --- .../devicetree/bindings/display/msm/dp-controller.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index aeb4e4f36044a..ea88e1903f26a 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -31,6 +31,11 @@ properties: - qcom,sm8650-dp - qcom,x1e80100-dp + - items: + - enum: + - qcom,qcs8300-dp + - const: qcom,sa8775p-dp + - items: - enum: - qcom,sm6350-dp From 10a224fb46ae82aba71359e3e1bffd94403a378b Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Thu, 11 Sep 2025 19:24:03 +0800 Subject: [PATCH 03/67] FROMLIST: dt-bindings: display/msm: Document MDSS on QCS8300 Document the MDSS hardware found on the Qualcomm QCS8300 platform. Link:https://lore.kernel.org/all/20250911-qcs8300_mdss-v12-3-5f7d076e2b81@oss.qualcomm.com/ Signed-off-by: Yongxing Mou --- .../display/msm/qcom,qcs8300-mdss.yaml | 286 ++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml new file mode 100644 index 0000000000000..e96baaae9ba9e --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml @@ -0,0 +1,286 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,qcs8300-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. QCS8300 Display MDSS + +maintainers: + - Yongxing Mou + +description: + QCS8300 MSM Mobile Display Subsystem(MDSS), which encapsulates sub-blocks like + DPU display controller, DP interfaces and EDP etc. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + const: qcom,qcs8300-mdss + + clocks: + items: + - description: Display AHB + - description: Display hf AXI + - description: Display core + + iommus: + maxItems: 1 + + interconnects: + maxItems: 3 + + interconnect-names: + maxItems: 3 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + contains: + const: qcom,qcs8300-dpu + + "^displayport-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + contains: + const: qcom,qcs8300-dp + + "^phy@[0-9a-f]+$": + type: object + additionalProperties: true + properties: + compatible: + contains: + const: qcom,qcs8300-edp-phy + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + #include + + mdss: display-subsystem@ae00000 { + compatible = "qcom,qcs8300-mdss"; + reg = <0x0ae00000 0x1000>; + reg-names = "mdss"; + + interconnects = <&mmss_noc MASTER_MDP0 QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&mmss_noc MASTER_MDP1 QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "mdp0-mem", + "mdp1-mem", + "cpu-cfg"; + + resets = <&dispcc_core_bcr>; + power-domains = <&dispcc_gdsc>; + + clocks = <&dispcc_ahb_clk>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc_mdp_clk>; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_smmu 0x1000 0x402>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,qcs8300-dpu", "qcom,sa8775p-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_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"; + + assigned-clocks = <&dispcc0 MDSS_DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <19200000>; + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + interrupt-parent = <&mdss>; + interrupts = <0>; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + + dpu_intf0_out: endpoint { + remote-endpoint = <&mdss_dp0_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-375000000 { + opp-hz = /bits/ 64 <375000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-575000000 { + opp-hz = /bits/ 64 <575000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + required-opps = <&rpmhpd_opp_turbo_l1>; + }; + }; + }; + + mdss_dp0_phy: phy@aec2a00 { + compatible = "qcom,qcs8300-edp-phy", "qcom,sa8775p-edp-phy"; + + reg = <0x0aec2a00 0x200>, + <0x0aec2200 0xd0>, + <0x0aec2600 0xd0>, + <0x0aec2000 0x1c8>; + + clocks = <&dispcc MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>; + clock-names = "aux", + "cfg_ahb"; + + #clock-cells = <1>; + #phy-cells = <0>; + + vdda-phy-supply = <&vreg_l1c>; + vdda-pll-supply = <&vreg_l4a>; + }; + + displayport-controller@af54000 { + compatible = "qcom,qcs8300-dp", "qcom,sa8775p-dp"; + + pinctrl-0 = <&dp_hot_plug_det>; + pinctrl-names = "default"; + + reg = <0xaf54000 0x104>, + <0xaf54200 0x0c0>, + <0xaf55000 0x770>, + <0xaf56000 0x09c>, + <0xaf57000 0x09c>, + <0xaf58000 0x09c>, + <0xaf59000 0x09c>, + <0xaf5a000 0x23c>, + <0xaf5b000 0x23c>; + + interrupt-parent = <&mdss>; + interrupts = <12>; + 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 = <&mdss_dp0_phy 0>, + <&mdss_dp0_phy 1>, + <&mdss_dp0_phy 1>, + <&mdss_dp0_phy 1>; + phys = <&mdss_dp0_phy>; + phy-names = "dp"; + operating-points-v2 = <&dp_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + #sound-dai-cells = <0>; + + 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_dp_out: endpoint { }; + }; + }; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-160000000 { + opp-hz = /bits/ 64 <160000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + required-opps = <&rpmhpd_opp_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>; + }; + }; + }; + }; +... From 6992b78fe24fe18a9bf6b96a413ef726ae636637 Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Thu, 11 Sep 2025 19:24:04 +0800 Subject: [PATCH 04/67] FROMLIST: soc: qcom: ubwc: Add QCS8300 UBWC cfg The QCS8300 supports UBWC 4.0 and 4 channels LP5 memory interface. Use the SC8280XP data structure for QCS8300 according to the specification. Link:https://lore.kernel.org/all/20250911-qcs8300_mdss-v12-4-5f7d076e2b81@oss.qualcomm.com/ Acked-by: Bjorn Andersson Reviewed-by: Dmitry Baryshkov Signed-off-by: Yongxing Mou --- drivers/soc/qcom/ubwc_config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c index 15d373bff231d..6de0e9d796c18 100644 --- a/drivers/soc/qcom/ubwc_config.c +++ b/drivers/soc/qcom/ubwc_config.c @@ -237,6 +237,7 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,msm8998", .data = &msm8998_data }, { .compatible = "qcom,qcm2290", .data = &qcm2290_data, }, { .compatible = "qcom,qcm6490", .data = &sc7280_data, }, + { .compatible = "qcom,qcs8300", .data = &sc8280xp_data, }, { .compatible = "qcom,sa8155p", .data = &sm8150_data, }, { .compatible = "qcom,sa8540p", .data = &sc8280xp_data, }, { .compatible = "qcom,sa8775p", .data = &sa8775p_data, }, From 69cdd9f639a7f057572091ab55774167f1f23826 Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Thu, 11 Sep 2025 19:24:05 +0800 Subject: [PATCH 05/67] FROMLIST: drm/msm: mdss: Add QCS8300 support Add Mobile Display Subsystem (MDSS) support for the QCS8300 platform. Link:https://lore.kernel.org/all/20250911-qcs8300_mdss-v12-5-5f7d076e2b81@oss.qualcomm.com/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Yongxing Mou --- drivers/gpu/drm/msm/msm_mdss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 2d0e3e784c044..db2f0064eb72e 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,mdss", .data = &data_153k6 }, { .compatible = "qcom,msm8998-mdss", .data = &data_76k8 }, { .compatible = "qcom,qcm2290-mdss", .data = &data_76k8 }, + { .compatible = "qcom,qcs8300-mdss", .data = &data_74k }, { .compatible = "qcom,sa8775p-mdss", .data = &data_74k }, { .compatible = "qcom,sar2130p-mdss", .data = &data_74k }, { .compatible = "qcom,sdm670-mdss", .data = &data_76k8 }, From e23caf7d9955d1ea1258ddacfae6e0da7623e7ad Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Tue, 2 Sep 2025 11:22:35 +0530 Subject: [PATCH 06/67] FROMLIST: ASoC: codecs: lpass-macro: Add support for channel map mixer control Introduce the channel map mixer control support for LPASS macro codec Digital Audio Interfaces (DAIs). The channel map mixer controls are required by APPS to configure usecase-specific audio routing and channel mapping. Link: https://lore.kernel.org/linux-sound/708dc6e4-1566-4c72-9f3a-a34f935ac247@oss.qualcomm.com/ Signed-off-by: Mohammad Rafi Shaik --- sound/soc/codecs/lpass-macro-common.c | 55 +++++++++++++++++++++++++++ sound/soc/codecs/lpass-macro-common.h | 2 + sound/soc/codecs/lpass-rx-macro.c | 12 ++++++ sound/soc/codecs/lpass-tx-macro.c | 9 +++++ sound/soc/codecs/lpass-va-macro.c | 9 +++++ sound/soc/codecs/lpass-wsa-macro.c | 12 ++++++ 6 files changed, 99 insertions(+) diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c index 6e3b8d0897dd6..777af4885245d 100644 --- a/sound/soc/codecs/lpass-macro-common.c +++ b/sound/soc/codecs/lpass-macro-common.c @@ -8,12 +8,67 @@ #include #include #include +#include +#include +#include #include "lpass-macro-common.h" static DEFINE_MUTEX(lpass_codec_mutex); static enum lpass_codec_version lpass_codec_version; +static int lpass_macro_chmap_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct snd_soc_dai *dai = info->private_data; + u32 *chmap_data = NULL; + u32 rx_ch_cnt = 0; + u32 tx_ch_cnt = 0; + u32 rx_ch, tx_ch; + + chmap_data = kzalloc(sizeof(u32) * 2, GFP_KERNEL); + if (!chmap_data) + return -ENOMEM; + + snd_soc_dai_get_channel_map(dai, &tx_ch_cnt, &tx_ch, &rx_ch_cnt, &rx_ch); + if (rx_ch_cnt) { + chmap_data[0] = rx_ch_cnt; + chmap_data[1] = rx_ch; + } else if (tx_ch_cnt) { + chmap_data[0] = tx_ch_cnt; + chmap_data[1] = tx_ch; + } + memcpy(ucontrol->value.bytes.data, chmap_data, sizeof(u32) * 2); + + kfree(chmap_data); + return 0; +} + +int lpass_macro_add_chmap_ctls(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai, int dir) +{ + struct snd_pcm_chmap *info; + int ret; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + ret = snd_pcm_add_chmap_ctls(rtd->pcm, dir, NULL, + 2 * sizeof(u32), 0, &info); + if (ret < 0) { + kfree(info); + return ret; + } + + /* override handlers */ + info->private_data = dai; + info->kctl->get = lpass_macro_chmap_ctl_get; + return 0; +} +EXPORT_SYMBOL_GPL(lpass_macro_add_chmap_ctls); + struct lpass_macro *lpass_macro_pds_init(struct device *dev) { struct lpass_macro *l_pds; diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h index 10ad682019fa7..afa8072ca7703 100644 --- a/sound/soc/codecs/lpass-macro-common.h +++ b/sound/soc/codecs/lpass-macro-common.h @@ -41,6 +41,8 @@ struct lpass_macro *lpass_macro_pds_init(struct device *dev); void lpass_macro_pds_exit(struct lpass_macro *pds); void lpass_macro_set_codec_version(enum lpass_codec_version version); enum lpass_codec_version lpass_macro_get_codec_version(void); +int lpass_macro_add_chmap_ctls(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai, int dir); static inline void lpass_macro_pds_exit_action(void *pds) { diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index a8fc842cc94ef..43c8f4116cb6d 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -1955,10 +1955,22 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) return 0; } +static int rx_macro_pcm_new(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai) +{ + int dir = SNDRV_PCM_STREAM_PLAYBACK; + + if (dai->id == RX_MACRO_AIF_ECHO) + dir = SNDRV_PCM_STREAM_CAPTURE; + + return lpass_macro_add_chmap_ctls(rtd, dai, dir); +} + static const struct snd_soc_dai_ops rx_macro_dai_ops = { .hw_params = rx_macro_hw_params, .get_channel_map = rx_macro_get_channel_map, .mute_stream = rx_macro_digital_mute, + .pcm_new = rx_macro_pcm_new, }; static struct snd_soc_dai_driver rx_macro_dai[] = { diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 1da34cb3505f3..934b814b7a016 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -1210,10 +1210,19 @@ static int tx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) return 0; } +static int tx_macro_pcm_new(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai) +{ + int dir = SNDRV_PCM_STREAM_CAPTURE; + + return lpass_macro_add_chmap_ctls(rtd, dai, dir); +} + static const struct snd_soc_dai_ops tx_macro_dai_ops = { .hw_params = tx_macro_hw_params, .get_channel_map = tx_macro_get_channel_map, .mute_stream = tx_macro_digital_mute, + .pcm_new = tx_macro_pcm_new, }; static struct snd_soc_dai_driver tx_macro_dai[] = { diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 2e1b77973a3e9..dc4177ce31206 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -938,10 +938,19 @@ static int va_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) return 0; } +static int va_macro_pcm_new(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai) +{ + int dir = SNDRV_PCM_STREAM_CAPTURE; + + return lpass_macro_add_chmap_ctls(rtd, dai, dir); +} + static const struct snd_soc_dai_ops va_macro_dai_ops = { .hw_params = va_macro_hw_params, .get_channel_map = va_macro_get_channel_map, .mute_stream = va_macro_digital_mute, + .pcm_new = va_macro_pcm_new, }; static struct snd_soc_dai_driver va_macro_dais[] = { diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 38faa9074ca3e..900d06b409f15 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -1356,9 +1356,21 @@ static int wsa_macro_get_channel_map(const struct snd_soc_dai *dai, return 0; } +static int wsa_macro_pcm_new(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai) +{ + int dir = SNDRV_PCM_STREAM_PLAYBACK; + + if (dai->id == WSA_MACRO_AIF_VI || dai->id == WSA_MACRO_AIF_ECHO) + dir = SNDRV_PCM_STREAM_CAPTURE; + + return lpass_macro_add_chmap_ctls(rtd, dai, dir); +} + static const struct snd_soc_dai_ops wsa_macro_dai_ops = { .hw_params = wsa_macro_hw_params, .get_channel_map = wsa_macro_get_channel_map, + .pcm_new = wsa_macro_pcm_new, }; static struct snd_soc_dai_driver wsa_macro_dai[] = { From 553419127a35c4d857a1d9a6fe68c2b4d23cac48 Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Tue, 7 Oct 2025 07:32:25 +0530 Subject: [PATCH 07/67] FROMLIST: ASoC: soc-pcm: Fix mute and unmute control for non-dynamic DAI links In setups where the same codec DAI is reused across multiple DAI links, mute controls via `snd_soc_dai_digital_mute()` is skipped for non-dynamic links. The trigger operations are not invoked when `dai_link->dynamic == 0`, and mute controls is currently conditioned only on `snd_soc_dai_mute_is_ctrled_at_trigger()`. This patch ensures that mute and unmute is applied explicitly for non-dynamic links. Link: https://lore.kernel.org/linux-sound/20251007023325.853640-1-mohammad.rafi.shaik@oss.qualcomm.com/ Fixes: f0220575e65a ("ASoC: soc-dai: add flag to mute and unmute stream during trigger") Cc: stable@vger.kernel.org Signed-off-by: Mohammad Rafi Shaik --- sound/soc/soc-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 2c21fd528afd0..4ed829b49bc2d 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -949,7 +949,7 @@ static int __soc_pcm_prepare(struct snd_soc_pcm_runtime *rtd, SND_SOC_DAPM_STREAM_START); for_each_rtd_dais(rtd, i, dai) { - if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai)) + if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai) || !rtd->dai_link->dynamic) snd_soc_dai_digital_mute(dai, 0, substream->stream); } @@ -1007,7 +1007,7 @@ static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd, soc_pcm_set_dai_params(dai, NULL); if (snd_soc_dai_stream_active(dai, substream->stream) == 1) { - if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai)) + if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai) || !rtd->dai_link->dynamic) snd_soc_dai_digital_mute(dai, 1, substream->stream); } } From a0b46735e58d0ed30d45211ca770c28ff682318a Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Sun, 21 Sep 2025 01:10:59 +0530 Subject: [PATCH 08/67] FROMLIST: dt-bindings: remoteproc: qcom,pas: Add iommus property Most Qualcomm platforms feature Gunyah hypervisor which handles IOMMU configuration for remote processor and when it is not present, the operating system must perform these configurations instead and for that firmware stream should be presented to the operating system. Hence, add iommus property as optional property for PAS supported devices. Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-1-d609ed766061@oss.qualcomm.com/ Acked-by: Rob Herring (Arm) Reviewed-by: Bryan O'Donoghue Signed-off-by: Mukesh Ojha --- .../devicetree/bindings/remoteproc/qcom,pas-common.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml index 63a82e7a8bf88..68c17bf18987c 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml @@ -44,6 +44,9 @@ properties: - const: stop-ack - const: shutdown-ack + iommus: + maxItems: 1 + power-domains: minItems: 1 maxItems: 3 From e2d84703fbb69f8a38b0ebe03f04880d0ddbdcdf Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Sun, 21 Sep 2025 01:11:00 +0530 Subject: [PATCH 09/67] FROMLIST: firmware: qcom_scm: Rename peripheral as pas_id Peripheral and pas_id refers to unique id for a subsystem and used only when peripheral authentication service from secure world is utilized. Lets rename peripheral to pas_id to reflect closer to its meaning. Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-2-d609ed766061@oss.qualcomm.com/ Reviewed-by: Bryan O'Donoghue Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 30 +++++++++++++------------- include/linux/firmware/qcom/qcom_scm.h | 10 ++++----- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index e777b7cb9b127..3379607eaf94f 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -562,7 +562,7 @@ static void qcom_scm_set_download_mode(u32 dload_mode) * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the * metadata - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * @metadata: pointer to memory containing ELF header, program header table * and optional blob of data used for authenticating the metadata * and the rest of the firmware @@ -575,7 +575,7 @@ static void qcom_scm_set_download_mode(u32 dload_mode) * track the metadata allocation, this needs to be released by invoking * qcom_scm_pas_metadata_release() by the caller. */ -int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, +int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx) { dma_addr_t mdata_phys; @@ -585,7 +585,7 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -658,20 +658,20 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); /** * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral * for firmware loading - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * @addr: start address of memory area to prepare * @size: size of the memory area to prepare * * Returns 0 on success. */ -int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) +int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP, .arginfo = QCOM_SCM_ARGS(3), - .args[0] = peripheral, + .args[0] = pas_id, .args[1] = addr, .args[2] = size, .owner = ARM_SMCCC_OWNER_SIP, @@ -699,18 +699,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); /** * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware * and reset the remote processor - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * * Return 0 on success. */ -int qcom_scm_pas_auth_and_reset(u32 peripheral) +int qcom_scm_pas_auth_and_reset(u32 pas_id) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -735,18 +735,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); /** * qcom_scm_pas_shutdown() - Shut down the remote processor - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * * Returns 0 on success. */ -int qcom_scm_pas_shutdown(u32 peripheral) +int qcom_scm_pas_shutdown(u32 pas_id) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; @@ -772,18 +772,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown); /** * qcom_scm_pas_supported() - Check if the peripheral authentication service is * available for the given peripherial - * @peripheral: peripheral id + * @pas_id: peripheral authentication service id * * Returns true if PAS is supported for this peripheral, otherwise false. */ -bool qcom_scm_pas_supported(u32 peripheral) +bool qcom_scm_pas_supported(u32 pas_id) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_PIL, .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED, .arginfo = QCOM_SCM_ARGS(1), - .args[0] = peripheral, + .args[0] = pas_id, .owner = ARM_SMCCC_OWNER_SIP, }; struct qcom_scm_res res; diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index a55ca771286bf..a13f703b16cd4 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -72,13 +72,13 @@ struct qcom_scm_pas_metadata { ssize_t size; }; -int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, +int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx); void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); -int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size); -int qcom_scm_pas_auth_and_reset(u32 peripheral); -int qcom_scm_pas_shutdown(u32 peripheral); -bool qcom_scm_pas_supported(u32 peripheral); +int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); +int qcom_scm_pas_auth_and_reset(u32 pas_id); +int qcom_scm_pas_shutdown(u32 pas_id); +bool qcom_scm_pas_supported(u32 pas_id); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); int qcom_scm_io_writel(phys_addr_t addr, unsigned int val); From 20bf8ef3f4eeb45a83a55c934227375471fc3639 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Sun, 21 Sep 2025 01:11:01 +0530 Subject: [PATCH 10/67] FROMLIST: firmware: qcom_scm: Introduce PAS context initialization helper function When the Peripheral Authentication Service (PAS) method runs on a SoC where Linux operates at EL2 (i.e., without the Gunyah hypervisor), the reset sequences are handled by TrustZone. In such cases, Linux must perform additional steps before invoking PAS SMC calls, such as creating a SHM bridge. Therefore, PAS SMC calls require awareness and handling of these additional steps when Linux runs at EL2. To support this, there is a need for a data structure that can be initialized prior to invoking any SMC or MDT functions. This structure allows those functions to determine whether they are operating in the presence or absence of the Gunyah hypervisor and behave accordingly. Currently, remoteproc and non-remoteproc subsystems use different variants of the MDT loader helper API, primarily due to differences in metadata context handling. Remoteproc subsystems retain the metadata context until authentication and reset are completed, while non-remoteproc subsystems (e.g., video, graphics, IPA, etc.) do not retain the metadata context and can free it within the qcom_scm_pas_init() call by passing a NULL context parameter and due to these differences, it is not possible to extend metadata context handling to support remoteproc and non remoteproc subsystem use PAS operations, when Linux operates at EL2. Add PAS context data structure and initialization helper function. Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-3-d609ed766061@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 33 ++++++++++++++++++++++++++ include/linux/firmware/qcom/qcom_scm.h | 10 ++++++++ 2 files changed, 43 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 3379607eaf94f..6d22b2ac78804 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -558,6 +558,39 @@ static void qcom_scm_set_download_mode(u32 dload_mode) dev_err(__scm->dev, "failed to set download mode: %d\n", ret); } +/** + * qcom_scm_pas_context_init() - Initialize peripheral authentication service + * context for a given peripheral + * + * @dev: PAS firmware device + * @pas_id: peripheral authentication service id + * @mem_phys: Subsystem reserve memory start address + * @mem_size: Subsystem reserve memory size + * + * Upon successful, returns the PAS context or ERR_PTR() of the error otherwise. + */ +void *qcom_scm_pas_context_init(struct device *dev, u32 pas_id, phys_addr_t mem_phys, + size_t mem_size) +{ + struct qcom_scm_pas_context *ctx; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + ctx->dev = dev; + ctx->pas_id = pas_id; + ctx->mem_phys = mem_phys; + ctx->mem_size = mem_size; + + ctx->metadata = devm_kzalloc(dev, sizeof(*ctx->metadata), GFP_KERNEL); + if (!ctx->metadata) + return ERR_PTR(-ENOMEM); + + return ctx; +} +EXPORT_SYMBOL_GPL(qcom_scm_pas_context_init); + /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index a13f703b16cd4..75dec515c5d2c 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -72,6 +72,16 @@ struct qcom_scm_pas_metadata { ssize_t size; }; +struct qcom_scm_pas_context { + struct device *dev; + u32 pas_id; + phys_addr_t mem_phys; + size_t mem_size; + struct qcom_scm_pas_metadata *metadata; +}; + +void *qcom_scm_pas_context_init(struct device *dev, u32 pas_id, phys_addr_t mem_phys, + size_t mem_size); int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx); void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); From 0c456ca7934f116d96ad3e7b83724eca2120ae54 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Sun, 21 Sep 2025 01:11:03 +0530 Subject: [PATCH 11/67] FROMLIST: remoteproc: pas: Replace metadata context with PAS context structure As a superset of the existing metadata context, the PAS context structure enables both remoteproc and non-remoteproc subsystems to better support scenarios where the SoC runs with or without the Gunyah hypervisor. To reflect this, relevant SCM and metadata functions are updated to incorporate PAS context awareness. Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-4-d609ed766061@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 32 ++++++++++++---------- drivers/remoteproc/qcom_q6v5_pas.c | 37 ++++++++++++++++++-------- drivers/soc/qcom/mdt_loader.c | 4 +-- include/linux/firmware/qcom/qcom_scm.h | 4 +-- include/linux/soc/qcom/mdt_loader.h | 6 ++--- 5 files changed, 51 insertions(+), 32 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 6d22b2ac78804..b11a21797d461 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -600,7 +600,7 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_context_init); * and optional blob of data used for authenticating the metadata * and the rest of the firmware * @size: size of the metadata - * @ctx: optional metadata context + * @ctx: optional pas context * * Return: 0 on success. * @@ -609,8 +609,9 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_context_init); * qcom_scm_pas_metadata_release() by the caller. */ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_metadata *ctx) + struct qcom_scm_pas_context *ctx) { + struct qcom_scm_pas_metadata *mdt_ctx; dma_addr_t mdata_phys; void *mdata_buf; int ret; @@ -661,10 +662,11 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, out: if (ret < 0 || !ctx) { dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); - } else if (ctx) { - ctx->ptr = mdata_buf; - ctx->phys = mdata_phys; - ctx->size = size; + } else if (ctx && ctx->metadata) { + mdt_ctx = ctx->metadata; + mdt_ctx->ptr = mdata_buf; + mdt_ctx->phys = mdata_phys; + mdt_ctx->size = size; } return ret ? : res.result[0]; @@ -673,18 +675,20 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image); /** * qcom_scm_pas_metadata_release() - release metadata context - * @ctx: metadata context + * @ctx: pas context */ -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx) +void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) { - if (!ctx->ptr) - return; + struct qcom_scm_pas_metadata *mdt_ctx; - dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); + mdt_ctx = ctx->metadata; + if (!mdt_ctx->ptr) + return; - ctx->ptr = NULL; - ctx->phys = 0; - ctx->size = 0; + dma_free_coherent(__scm->dev, mdt_ctx->size, mdt_ctx->ptr, mdt_ctx->phys); + mdt_ctx->ptr = NULL; + mdt_ctx->phys = 0; + mdt_ctx->size = 0; } EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 158bcd6cc85c5..e9dcab94ea0cd 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -117,8 +117,8 @@ struct qcom_pas { struct qcom_rproc_ssr ssr_subdev; struct qcom_sysmon *sysmon; - struct qcom_scm_pas_metadata pas_metadata; - struct qcom_scm_pas_metadata dtb_pas_metadata; + struct qcom_scm_pas_context *pas_ctx; + struct qcom_scm_pas_context *dtb_pas_ctx; }; static void qcom_pas_segment_dump(struct rproc *rproc, @@ -211,9 +211,9 @@ static int qcom_pas_unprepare(struct rproc *rproc) * auth_and_reset() was successful, but in other cases clean it up * here. */ - qcom_scm_pas_metadata_release(&pas->pas_metadata); + qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); return 0; } @@ -241,7 +241,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) ret = qcom_mdt_pas_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, pas->dtb_pas_id, pas->dtb_mem_phys, - &pas->dtb_pas_metadata); + pas->dtb_pas_ctx); if (ret) goto release_dtb_firmware; @@ -255,7 +255,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return 0; release_dtb_metadata: - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); release_dtb_firmware: release_firmware(pas->dtb_firmware); @@ -306,7 +306,7 @@ static int qcom_pas_start(struct rproc *rproc) } ret = qcom_mdt_pas_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id, - pas->mem_phys, &pas->pas_metadata); + pas->mem_phys, pas->pas_ctx); if (ret) goto disable_px_supply; @@ -332,9 +332,9 @@ static int qcom_pas_start(struct rproc *rproc) goto release_pas_metadata; } - qcom_scm_pas_metadata_release(&pas->pas_metadata); + qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); /* firmware is used to pass reference from qcom_pas_start(), drop it now */ pas->firmware = NULL; @@ -342,9 +342,9 @@ static int qcom_pas_start(struct rproc *rproc) return 0; release_pas_metadata: - qcom_scm_pas_metadata_release(&pas->pas_metadata); + qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); + qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); disable_px_supply: if (pas->px_supply) regulator_disable(pas->px_supply); @@ -779,6 +779,21 @@ static int qcom_pas_probe(struct platform_device *pdev) } qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name); + + pas->pas_ctx = qcom_scm_pas_context_init(pas->dev, pas->pas_id, pas->mem_phys, + pas->mem_size); + if (IS_ERR(pas->pas_ctx)) { + ret = PTR_ERR(pas->pas_ctx); + goto remove_ssr_sysmon; + } + + pas->dtb_pas_ctx = qcom_scm_pas_context_init(pas->dev, pas->dtb_pas_id, + pas->dtb_mem_phys, pas->dtb_mem_size); + if (IS_ERR(pas->dtb_pas_ctx)) { + ret = PTR_ERR(pas->dtb_pas_ctx); + goto remove_ssr_sysmon; + } + ret = rproc_add(rproc); if (ret) goto remove_ssr_sysmon; diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index a5c80d4fcc366..fe35038c5342e 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -234,13 +234,13 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); * @fw_name: name of the firmware, for construction of segment file names * @pas_id: PAS identifier * @mem_phys: physical address of allocated memory region - * @ctx: PAS metadata context, to be released by caller + * @ctx: PAS context, ctx->metadata to be released by caller * * Returns 0 on success, negative errno otherwise. */ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_metadata *ctx) + struct qcom_scm_pas_context *ctx) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 75dec515c5d2c..7c58d26ede240 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -83,8 +83,8 @@ struct qcom_scm_pas_context { void *qcom_scm_pas_context_init(struct device *dev, u32 pas_id, phys_addr_t mem_phys, size_t mem_size); int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_metadata *ctx); -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); + struct qcom_scm_pas_context *ctx); +void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx); int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 8ea8230579a20..07c2788418166 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -10,14 +10,14 @@ struct device; struct firmware; -struct qcom_scm_pas_metadata; +struct qcom_scm_pas_context; #if IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ssize_t qcom_mdt_get_size(const struct firmware *fw); int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_metadata *pas_metadata_ctx); + struct qcom_scm_pas_context *pas_ctx); int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -39,7 +39,7 @@ static inline ssize_t qcom_mdt_get_size(const struct firmware *fw) static inline int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_metadata *pas_metadata_ctx) + struct qcom_scm_pas_context *pas_ctx) { return -ENODEV; } From a173a8d6f01a3ad54102a3a3f8e184ccda02ffcd Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Sun, 21 Sep 2025 01:11:02 +0530 Subject: [PATCH 12/67] FROMLIST: soc: qcom: mdtloader: Add PAS context aware qcom_mdt_pas_load() function Introduce a new PAS context-aware function, qcom_mdt_pas_load(), for remote processor drivers. This function utilizes the PAS context pointer returned from qcom_scm_pas_ctx_init() to perform firmware metadata verification and memory setup via SMC calls. The qcom_mdt_pas_load() and qcom_mdt_load() functions are largely similar, but the former is designed for clients using the PAS context-based data structure. Over time, all users of qcom_mdt_load() can be migrated to use qcom_mdt_pas_load() for consistency and improved abstraction. As the remoteproc PAS driver (qcom_q6v5_pas) has already adopted the PAS context-based approach, update it to use qcom_mdt_pas_load(). Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-5-d609ed766061@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/remoteproc/qcom_q6v5_pas.c | 24 +++++----------------- drivers/soc/qcom/mdt_loader.c | 32 +++++++++++++++++++++++++++++ include/linux/soc/qcom/mdt_loader.h | 10 +++++++++ 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index e9dcab94ea0cd..ee0ea35803c6c 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -239,15 +239,9 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return ret; } - ret = qcom_mdt_pas_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, - pas->dtb_pas_id, pas->dtb_mem_phys, - pas->dtb_pas_ctx); - if (ret) - goto release_dtb_firmware; - - ret = qcom_mdt_load_no_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, - pas->dtb_mem_region, pas->dtb_mem_phys, - pas->dtb_mem_size, &pas->dtb_mem_reloc); + ret = qcom_mdt_pas_load(pas->dtb_pas_ctx, pas->dtb_firmware, + pas->dtb_firmware_name, pas->dtb_mem_region, + &pas->dtb_mem_reloc); if (ret) goto release_dtb_metadata; } @@ -256,8 +250,6 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) release_dtb_metadata: qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); - -release_dtb_firmware: release_firmware(pas->dtb_firmware); return ret; @@ -305,14 +297,8 @@ static int qcom_pas_start(struct rproc *rproc) } } - ret = qcom_mdt_pas_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id, - pas->mem_phys, pas->pas_ctx); - if (ret) - goto disable_px_supply; - - ret = qcom_mdt_load_no_init(pas->dev, pas->firmware, rproc->firmware, - pas->mem_region, pas->mem_phys, pas->mem_size, - &pas->mem_reloc); + ret = qcom_mdt_pas_load(pas->pas_ctx, pas->firmware, rproc->firmware, + pas->mem_region, &pas->mem_reloc); if (ret) goto release_pas_metadata; diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index fe35038c5342e..52de8adcc4f2d 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -486,5 +486,37 @@ int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, } EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init); +/** + * qcom_mdt_pas_load - Loads and authenticates the metadata of the firmware + * (typically contained in the .mdt file), followed by loading the actual + * firmware segments (e.g., .bXX files). Authentication of the segments done + * by a separate call. + * + * The PAS context must be initialized using qcom_scm_pas_context_init() + * prior to invoking this function. + * + * @ctx: Pointer to the PAS (Peripheral Authentication Service) context + * @fw: Firmware object representing the .mdt file + * @firmware: Name of the firmware used to construct segment file names + * @mem_region: Memory region allocated for loading the firmware + * @reloc_base: Physical address adjusted after relocation + * + * Return: 0 on success or a negative error code on failure. + */ +int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, + const char *firmware, void *mem_region, phys_addr_t *reloc_base) +{ + int ret; + + ret = qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, + ctx->metadata); + if (ret) + return ret; + + return __qcom_mdt_load(ctx->dev, fw, firmware, mem_region, ctx->mem_phys, + ctx->mem_size, reloc_base); +} +EXPORT_SYMBOL_GPL(qcom_mdt_pas_load); + MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 07c2788418166..7d57746fbbfa5 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -23,6 +23,9 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, phys_addr_t mem_phys, size_t mem_size, phys_addr_t *reloc_base); +int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, + const char *firmware, void *mem_region, phys_addr_t *reloc_base); + int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, const char *fw_name, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -52,6 +55,13 @@ static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw, return -ENODEV; } +static inline int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, + const struct firmware *fw, const char *firmware, + void *mem_region, phys_addr_t *reloc_base) +{ + return -ENODEV; +} + static inline int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, const char *fw_name, void *mem_region, From ec072a73efd2bd22e4581c41c23cace063c04c0a Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 13 Oct 2025 14:12:55 +0530 Subject: [PATCH 13/67] FROMLIST: soc: qcom: mdtloader: Remove qcom_mdt_pas_init() from exported symbols qcom_mdt_pas_init() was previously used only by the remoteproc driver (drivers/remoteproc/qcom_q6v5_pas.c). Since that driver has now transitioned to using PAS context-based qcom_mdt_pas_load() function, making qcom_mdt_pas_init() obsolete for external use. Removes qcom_mdt_pas_init() from the list of exported symbols and make it static to limit its scope to internal use within mdtloader. Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-6-d609ed766061@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/soc/qcom/mdt_loader.c | 12 +++++------- include/linux/soc/qcom/mdt_loader.h | 10 ---------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 52de8adcc4f2d..97e6d11b8926f 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -238,9 +238,9 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); * * Returns 0 on success, negative errno otherwise. */ -int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *ctx) +static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, + const char *fw_name, int pas_id, phys_addr_t mem_phys, + struct qcom_scm_pas_context *ctx) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; @@ -302,7 +302,6 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, out: return ret; } -EXPORT_SYMBOL_GPL(qcom_mdt_pas_init); static bool qcom_mdt_bins_are_split(const struct firmware *fw) { @@ -456,7 +455,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, { int ret; - ret = qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL); + ret = __qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL); if (ret) return ret; @@ -508,8 +507,7 @@ int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *f { int ret; - ret = qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, - ctx->metadata); + ret = __qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); if (ret) return ret; diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 7d57746fbbfa5..82372e0db0a18 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -15,9 +15,6 @@ struct qcom_scm_pas_context; #if IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ssize_t qcom_mdt_get_size(const struct firmware *fw); -int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *pas_ctx); int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -40,13 +37,6 @@ static inline ssize_t qcom_mdt_get_size(const struct firmware *fw) return -ENODEV; } -static inline int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *pas_ctx) -{ - return -ENODEV; -} - static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, From e6908c421ec29ab3ab54259124a67564da171db7 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Sun, 21 Sep 2025 01:11:04 +0530 Subject: [PATCH 14/67] FROMLIST: firmware: qcom_scm: Add a prep version of auth_and_reset function For memory passed to TrustZone (TZ), it must either be part of a pool registered with TZ or explicitly registered via SHMbridge SMC calls. When Gunyah hypervisor is present, PAS SMC calls from Linux running at EL1 are trapped by Gunyah running @ EL2, which handles SHMbridge creation for both metadata and remoteproc carveout memory before invoking the calls to TZ. On SoCs running with a non-Gunyah-based hypervisor, Linux must take responsibility for creating the SHM bridge before invoking PAS SMC calls. For the auth_and_reset() call, the remoteproc carveout memory must first be registered with TZ via a SHMbridge SMC call and once authentication and reset are complete, the SHMbridge memory can be deregistered. Introduce qcom_scm_pas_prepare_and_auth_reset(), which sets up the SHM bridge over the remoteproc carveout memory when Linux operates at EL2. This behavior is indicated by a new field added to the PAS context data structure. The function then invokes the auth_and_reset SMC call. Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-7-d609ed766061@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 48 ++++++++++++++++++++++++++ include/linux/firmware/qcom/qcom_scm.h | 2 ++ 2 files changed, 50 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index b11a21797d461..a66e782fdb68f 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -770,6 +770,54 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id) } EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); +/** + * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the + * remote processor + * + * @ctx: Context saved during call to qcom_scm_pas_context_init() + * + * This function performs the necessary steps to prepare a PAS subsystem, + * authenticate it using the provided metadata, and initiate a reset sequence. + * + * It should be used when Linux is in control setting up the IOMMU hardware + * for remote subsystem during secure firmware loading processes. The preparation + * step sets up a shmbridge over the firmware memory before TrustZone accesses the + * firmware memory region for authentication. The authentication step verifies + * the integrity and authenticity of the firmware or configuration using secure + * metadata. Finally, the reset step ensures the subsystem starts in a clean and + * sane state. + * + * Return: 0 on success, negative errno on failure. + */ +int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) +{ + u64 handle; + int ret; + + if (!ctx->has_iommu) + return qcom_scm_pas_auth_and_reset(ctx->pas_id); + + /* + * When Linux running @ EL1, Gunyah hypervisor running @ EL2 traps the + * auth_and_reset call and create an shmbridge on the remote subsystem + * memory region and then invokes a call to TrustZone to authenticate. + * When Linux runs @ EL2 Linux must create the shmbridge itself and then + * subsequently call TrustZone for authenticate and reset. + */ + ret = qcom_tzmem_shm_bridge_create(ctx->mem_phys, ctx->mem_size, &handle); + if (ret) { + dev_err(__scm->dev, "Failed to create shmbridge for PAS ID (%u): %d\n", + ctx->pas_id, ret); + return ret; + } + + ret = qcom_scm_pas_auth_and_reset(ctx->pas_id); + qcom_tzmem_shm_bridge_delete(handle); + + return ret; +} +EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset); + /** * qcom_scm_pas_shutdown() - Shut down the remote processor * @pas_id: peripheral authentication service id diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 7c58d26ede240..e1de3cf73451d 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -78,6 +78,7 @@ struct qcom_scm_pas_context { phys_addr_t mem_phys; size_t mem_size; struct qcom_scm_pas_metadata *metadata; + bool has_iommu; }; void *qcom_scm_pas_context_init(struct device *dev, u32 pas_id, phys_addr_t mem_phys, @@ -89,6 +90,7 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); bool qcom_scm_pas_supported(u32 pas_id); +int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); int qcom_scm_io_writel(phys_addr_t addr, unsigned int val); From 145244df6e53af1f0d75eca8e3769e87547d6fd7 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Sun, 21 Sep 2025 01:11:05 +0530 Subject: [PATCH 15/67] FROMLIST: firmware: qcom_scm: Simplify qcom_scm_pas_init_image() Simplify qcom_scm_pas_init_image() by making the memory allocation, copy and free operations done in a separate function than the actual SMC call. Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-8-d609ed766061@oss.qualcomm.com/ Reviewed-by: Bryan O'Donoghue Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 58 ++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index a66e782fdb68f..eb79fceda92b7 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -591,6 +591,37 @@ void *qcom_scm_pas_context_init(struct device *dev, u32 pas_id, phys_addr_t mem_ } EXPORT_SYMBOL_GPL(qcom_scm_pas_context_init); +static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, void *metadata, + size_t size, struct qcom_scm_res *res) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_PIL, + .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, + .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), + .args[0] = pas_id, + .owner = ARM_SMCCC_OWNER_SIP, + }; + int ret; + + ret = qcom_scm_clk_enable(); + if (ret) + return ret; + + ret = qcom_scm_bw_enable(); + if (ret) + goto disable_clk; + + desc.args[1] = mdata_phys; + + ret = qcom_scm_call(__scm->dev, &desc, res); + qcom_scm_bw_disable(); + +disable_clk: + qcom_scm_clk_disable(); + + return ret; +} + /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the @@ -612,17 +643,10 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, struct qcom_scm_pas_context *ctx) { struct qcom_scm_pas_metadata *mdt_ctx; + struct qcom_scm_res res; dma_addr_t mdata_phys; void *mdata_buf; int ret; - struct qcom_scm_desc desc = { - .svc = QCOM_SCM_SVC_PIL, - .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, - .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), - .args[0] = pas_id, - .owner = ARM_SMCCC_OWNER_SIP, - }; - struct qcom_scm_res res; /* * During the scm call memory protection will be enabled for the meta @@ -643,23 +667,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, memcpy(mdata_buf, metadata, size); - ret = qcom_scm_clk_enable(); - if (ret) - goto out; - - ret = qcom_scm_bw_enable(); - if (ret) - goto disable_clk; - - desc.args[1] = mdata_phys; - - ret = qcom_scm_call(__scm->dev, &desc, &res); - qcom_scm_bw_disable(); - -disable_clk: - qcom_scm_clk_disable(); - -out: + ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, mdata_buf, size, &res); if (ret < 0 || !ctx) { dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); } else if (ctx && ctx->metadata) { From d1eafa291a50ad72c8556951830dfccf8a204179 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Sun, 21 Sep 2025 01:11:06 +0530 Subject: [PATCH 16/67] FROMLIST: firmware: qcom_scm: Add SHM bridge handling for PAS when running without QHEE On SoCs running with a non-Gunyah-based hypervisor, Linux must take responsibility for creating the SHM bridge both for metadata (before calling qcom_scm_pas_init_image()) and for remoteproc memory (before calling qcom_scm_pas_auth_and_reset()). We have taken care the things required for qcom_scm_pas_auth_and_reset(). Lets put these awareness of above conditions into qcom_scm_pas_init_image() and qcom_scm_pas_metadata_release(). Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-9-d609ed766061@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 44 ++++++++++++++++++++++++-- include/linux/firmware/qcom/qcom_scm.h | 5 ++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index eb79fceda92b7..c545f7114237b 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -622,6 +622,35 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, void *me return ret; } +static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, + const void *metadata, size_t size) +{ + struct qcom_scm_pas_metadata *mdt_ctx; + struct qcom_scm_res res; + phys_addr_t mdata_phys; + void *mdata_buf; + int ret; + + mdt_ctx = ctx->metadata; + mdata_buf = qcom_tzmem_alloc(__scm->mempool, size, GFP_KERNEL); + if (!mdata_buf) + return -ENOMEM; + + memcpy(mdata_buf, metadata, size); + mdata_phys = qcom_tzmem_to_phys(mdata_buf); + + ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, mdata_buf, size, &res); + if (ret < 0 || !mdt_ctx) { + qcom_tzmem_free(mdata_buf); + } else if (mdt_ctx) { + mdt_ctx->ptr = mdata_buf; + mdt_ctx->addr.phys_addr = mdata_phys; + mdt_ctx->size = size; + } + + return ret ? : res.result[0]; +} + /** * qcom_scm_pas_init_image() - Initialize peripheral authentication service * state machine for a given peripheral, using the @@ -648,6 +677,9 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, void *mdata_buf; int ret; + if (ctx && ctx->has_iommu) + return qcom_scm_pas_prep_and_init_image(ctx, metadata, size); + /* * During the scm call memory protection will be enabled for the meta * data blob, so make sure it's physically contiguous, 4K aligned and @@ -673,7 +705,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, } else if (ctx && ctx->metadata) { mdt_ctx = ctx->metadata; mdt_ctx->ptr = mdata_buf; - mdt_ctx->phys = mdata_phys; + mdt_ctx->addr.dma_addr = mdata_phys; mdt_ctx->size = size; } @@ -693,9 +725,15 @@ void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) if (!mdt_ctx->ptr) return; - dma_free_coherent(__scm->dev, mdt_ctx->size, mdt_ctx->ptr, mdt_ctx->phys); + if (ctx->has_iommu) { + qcom_tzmem_free(mdt_ctx->ptr); + mdt_ctx->addr.phys_addr = 0; + } else { + dma_free_coherent(__scm->dev, mdt_ctx->size, mdt_ctx->ptr, + mdt_ctx->addr.dma_addr); + mdt_ctx->addr.dma_addr = 0; + } mdt_ctx->ptr = NULL; - mdt_ctx->phys = 0; mdt_ctx->size = 0; } EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index e1de3cf73451d..583490bcd38be 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -68,7 +68,10 @@ int qcom_scm_set_remote_state(u32 state, u32 id); struct qcom_scm_pas_metadata { void *ptr; - dma_addr_t phys; + union { + dma_addr_t dma_addr; + phys_addr_t phys_addr; + } addr; ssize_t size; }; From 9c576605668c9a871cc45695ad8579179ba23d69 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Sun, 21 Sep 2025 01:11:07 +0530 Subject: [PATCH 17/67] FROMLIST: firmware: qcom_scm: Add qcom_scm_pas_get_rsc_table() to get resource table Qualcomm remote processor may rely on Static and Dynamic resources for it to be functional. Static resources are fixed like for example, memory-mapped addresses required by the subsystem and dynamic resources, such as shared memory in DDR etc., are determined at runtime during the boot process. For most of the Qualcomm SoCs, when run with Gunyah or older QHEE hypervisor, all the resources whether it is static or dynamic, is managed by the hypervisor. Dynamic resources if it is present for a remote processor will always be coming from secure world via SMC call while static resources may be present in remote processor firmware binary or it may be coming qcom_scm_pas_get_rsc_table() SMC call along with dynamic resources. Some of the remote processor drivers, such as video, GPU, IPA, etc., do not check whether resources are present in their remote processor firmware binary. In such cases, the caller of this function should set input_rt and input_rt_size as NULL and zero respectively. Remoteproc framework has method to check whether firmware binary contain resources or not and they should be pass resource table pointer to input_rt and resource table size to input_rt_size and this will be forwarded to TrustZone for authentication. TrustZone will then append the dynamic resources and return the complete resource table in output_rt More about documentation on resource table format can be found in include/linux/remoteproc.h Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-10-d609ed766061@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom/qcom_scm.c | 157 +++++++++++++++++++++++++ drivers/firmware/qcom/qcom_scm.h | 1 + include/linux/firmware/qcom/qcom_scm.h | 4 + 3 files changed, 162 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index c545f7114237b..3c554f3e85365 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -111,6 +112,10 @@ enum qcom_scm_qseecom_tz_cmd_info { QSEECOM_TZ_CMD_INFO_VERSION = 3, }; +enum qcom_scm_rsctable_resp_type { + RSCTABLE_BUFFER_NOT_SUFFICIENT = 20, +}; + #define QSEECOM_MAX_APP_NAME_SIZE 64 #define SHMBRIDGE_RESULT_NOTSUPP 4 @@ -779,6 +784,158 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) } EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); +static int __qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt, size_t input_rt_size, + void **output_rt, size_t *output_rt_size) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_PIL, + .cmd = QCOM_SCM_PIL_PAS_GET_RSCTABLE, + .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RO, QCOM_SCM_VAL, + QCOM_SCM_RW, QCOM_SCM_VAL), + .args[0] = pas_id, + .owner = ARM_SMCCC_OWNER_SIP, + }; + void *input_rt_buf, *output_rt_buf; + struct resource_table *rsc; + struct qcom_scm_res res; + int ret; + + ret = qcom_scm_clk_enable(); + if (ret) + return ret; + + ret = qcom_scm_bw_enable(); + if (ret) + goto disable_clk; + + /* + * TrustZone can not accept buffer as NULL value as argument Hence, + * we need to pass a input buffer indicating that subsystem firmware + * does not have resource table by filling resource table structure. + */ + if (!input_rt) + input_rt_size = sizeof(*rsc); + + input_rt_buf = qcom_tzmem_alloc(__scm->mempool, input_rt_size, GFP_KERNEL); + if (!input_rt_buf) { + ret = -ENOMEM; + goto disable_scm_bw; + } + + if (!input_rt) { + rsc = input_rt_buf; + rsc->num = 0; + } else { + memcpy(input_rt_buf, input_rt, input_rt_size); + } + + output_rt_buf = qcom_tzmem_alloc(__scm->mempool, *output_rt_size, GFP_KERNEL); + if (!output_rt_buf) { + ret = -ENOMEM; + goto free_input_rt_buf; + } + + desc.args[1] = qcom_tzmem_to_phys(input_rt_buf); + desc.args[2] = input_rt_size; + desc.args[3] = qcom_tzmem_to_phys(output_rt_buf); + desc.args[4] = *output_rt_size; + + /* + * Whether SMC fail or pass, res.result[2] will hold actual resource table + * size. + * + * if passed 'output_rt_size' buffer size is not sufficient to hold the + * resource table TrustZone sends, response code in res.result[1] as + * RSCTABLE_BUFFER_NOT_SUFFICIENT so that caller can retry this SMC call with + * output_rt buffer with res.result[2] size. + */ + ret = qcom_scm_call(__scm->dev, &desc, &res); + *output_rt_size = res.result[2]; + if (!ret) + memcpy(*output_rt, output_rt_buf, *output_rt_size); + + if (ret && res.result[1] == RSCTABLE_BUFFER_NOT_SUFFICIENT) + ret = -EAGAIN; + + qcom_tzmem_free(output_rt_buf); + +free_input_rt_buf: + qcom_tzmem_free(input_rt_buf); + +disable_scm_bw: + qcom_scm_bw_disable(); + +disable_clk: + qcom_scm_clk_disable(); + + return ret ? : res.result[0]; +} + +/** + * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer + * for a given peripheral. + * + * Qualcomm remote processor may rely on both static and dynamic resources for + * its functionality. Static resources typically refer to memory-mapped addresses + * required by the subsystem and are often embedded within the firmware binary + * and dynamic resources, such as shared memory in DDR etc., are determined at + * runtime during the boot process. + * + * On Qualcomm Technologies devices, it's possible that static resources are not + * embedded in the firmware binary and instead are provided by TrustZone However, + * dynamic resources are always expected to come from TrustZone. This indicates + * that for Qualcomm devices, all resources (static and dynamic) will be provided + * by TrustZone via the SMC call. + * + * If the remote processor firmware binary does contain static resources, they + * should be passed in input_rt. These will be forwarded to TrustZone for + * authentication. TrustZone will then append the dynamic resources and return + * the complete resource table in output_rt. + * + * If the remote processor firmware binary does not include a resource table, + * the caller of this function should set input_rt as NULL and input_rt_size + * as zero respectively. + * + * More about documentation on resource table data structures can be found in + * include/linux/rsc_table.h + * + * @ctx: PAS context + * @pas_id: peripheral authentication service id + * @input_rt: resource table buffer which is present in firmware binary + * @input_rt_size: size of the resource table present in firmware binary + * @output_rt: buffer to which the both static and dynamic resources will + * be returned. + * @output_rt_size: TrustZone expects caller should pass worst case size for + * the output_rt. + * + * Return: 0 on success and nonzero on failure. + * + * Upon successful return, output_rt will have the resource table and output_rt_size + * will have actual resource table size, + */ +int qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, void *input_rt, + size_t input_rt_size, void **output_rt, + size_t *output_rt_size) +{ + int ret; + + do { + *output_rt = devm_kzalloc(ctx->dev, *output_rt_size, GFP_KERNEL); + if (!*output_rt) + return -ENOMEM; + + ret = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt, + input_rt_size, output_rt, + output_rt_size); + if (ret) + devm_kfree(ctx->dev, *output_rt); + + } while (ret == -EAGAIN); + + return ret; +} +EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table); + /** * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware * and reset the remote processor diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h index a56c8212cc0c4..50d87c628d78b 100644 --- a/drivers/firmware/qcom/qcom_scm.h +++ b/drivers/firmware/qcom/qcom_scm.h @@ -105,6 +105,7 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev); #define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06 #define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07 #define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a +#define QCOM_SCM_PIL_PAS_GET_RSCTABLE 0x21 #define QCOM_SCM_SVC_IO 0x05 #define QCOM_SCM_IO_READ 0x01 diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 583490bcd38be..5cd9b2553cad7 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -93,6 +93,10 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); int qcom_scm_pas_auth_and_reset(u32 pas_id); int qcom_scm_pas_shutdown(u32 pas_id); bool qcom_scm_pas_supported(u32 pas_id); +int qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, void *input_rt, + size_t input_rt_size, void **output_rt, + size_t *output_rt_size); + int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx); int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); From 6681abcbb89f13e4b80e0fdc922262fb1100f12a Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Sun, 21 Sep 2025 01:11:08 +0530 Subject: [PATCH 18/67] FROMLIST: remoteproc: pas: Extend parse_fw callback to fetch resources via SMC call Qualcomm remote processor may rely on static and dynamic resources for it to be functional. For most of the Qualcomm SoCs, when run with Gunyah or older QHEE hypervisor, all the resources whether it is static or dynamic, is managed by the hypervisor. Dynamic resources if it is present for a remote processor will always be coming from secure world via SMC call while static resources may be present in remote processor firmware binary or it may be coming from SMC call along with dynamic resources. Remoteproc already has method like rproc_elf_load_rsc_table() to check firmware binary has resources or not and if it is not having then we pass NULL and zero as input resource table and its size argument respectively to qcom_scm_pas_get_rsc_table() and while it has resource present then it should pass the present resources to Trustzone(TZ) so that it could authenticate the present resources and append dynamic resource to return in output_rt argument along with authenticated resources. Extend parse_fw callback to include SMC call to get resources from Trustzone and to leverage resource table parsing and mapping and unmapping code from the remoteproc framework. Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-11-d609ed766061@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/remoteproc/qcom_q6v5_pas.c | 60 +++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index ee0ea35803c6c..1944df49893f6 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -34,6 +34,7 @@ #define QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS 100 #define MAX_ASSIGN_COUNT 3 +#define MAX_RSCTABLE_SIZE SZ_16K struct qcom_pas_data { int crash_reason_smem; @@ -413,6 +414,61 @@ static void *qcom_pas_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is return pas->mem_region + offset; } +static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *fw) +{ + size_t output_rt_size = MAX_RSCTABLE_SIZE; + struct qcom_pas *pas = rproc->priv; + struct resource_table *table = NULL; + void *output_rt; + size_t table_sz; + int ret; + + ret = qcom_register_dump_segments(rproc, fw); + if (ret) { + dev_err(pas->dev, "Error in registering dump segments\n"); + return ret; + } + + if (!rproc->has_iommu) + return ret; + + ret = rproc_elf_load_rsc_table(rproc, fw); + if (ret) + dev_info(&rproc->dev, "Error in loading resource table from firmware\n"); + + table = rproc->table_ptr; + table_sz = rproc->table_sz; + + /* + * Qualcomm remote processor may rely on static and dynamic resources for + * it to be functional. For most of the Qualcomm SoCs, when run with Gunyah + * or older QHEE hypervisor, all the resources whether it is static or dynamic, + * is managed by present hypervisor. Dynamic resources if it is present for + * a remote processor will always be coming from secure world via SMC call + * while static resources may be present in remote processor firmware binary + * or it may be coming from SMC call along with dynamic resources. + * + * Here, we call rproc_elf_load_rsc_table() to check firmware binary has resources + * or not and if it is not having then we pass NULL and zero as input resource + * table pointer and size respectively to the argument of qcom_scm_pas_get_rsc_table() + * and this is even true for Qualcomm remote processor who does follow remoteproc + * framework. + */ + ret = qcom_scm_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt, + &output_rt_size); + if (ret) { + dev_err(pas->dev, "Error in getting resource table: %d\n", ret); + return ret; + } + + kfree(rproc->cached_table); + rproc->cached_table = output_rt; + rproc->table_ptr = rproc->cached_table; + rproc->table_sz = output_rt_size; + + return ret; +} + static unsigned long qcom_pas_panic(struct rproc *rproc) { struct qcom_pas *pas = rproc->priv; @@ -425,7 +481,7 @@ static const struct rproc_ops qcom_pas_ops = { .start = qcom_pas_start, .stop = qcom_pas_stop, .da_to_va = qcom_pas_da_to_va, - .parse_fw = qcom_register_dump_segments, + .parse_fw = qcom_pas_parse_firmware, .load = qcom_pas_load, .panic = qcom_pas_panic, }; @@ -435,7 +491,7 @@ static const struct rproc_ops qcom_pas_minidump_ops = { .start = qcom_pas_start, .stop = qcom_pas_stop, .da_to_va = qcom_pas_da_to_va, - .parse_fw = qcom_register_dump_segments, + .parse_fw = qcom_pas_parse_firmware, .load = qcom_pas_load, .panic = qcom_pas_panic, .coredump = qcom_pas_minidump, From 806913442c1fd5fc6195a904f574a334df280b80 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Sun, 21 Sep 2025 01:11:09 +0530 Subject: [PATCH 19/67] FROMLIST: remoteproc: qcom: pas: Enable Secure PAS support with IOMMU managed by Linux Most Qualcomm platforms feature Gunyah hypervisor, which typically handles IOMMU configuration. This includes mapping memory regions and device memory resources for remote processors by intercepting qcom_scm_pas_auth_and_reset() calls. These mappings are later removed during teardown. Additionally, SHM bridge setup is required to enable memory protection for both remoteproc metadata and its memory regions. When the aforementioned hypervisor is absent, the operating system must perform these configurations instead. When Linux runs as the hypervisor (@ EL2) on a SoC, it will have its own device tree overlay file that specifies the firmware stream ID now managed by Linux for a particular remote processor. If the iommus property is specified in the remoteproc device tree node, it indicates that IOMMU configuration must be handled by Linux. In this case, the has_iommu flag is set for the remote processor, which ensures that the resource table, carveouts, and SHM bridge are properly configured before memory is passed to TrustZone for authentication. Otherwise, the has_iommu flag remains unset, which indicates default behavior. Enables Secure PAS support for remote processors when IOMMU configuration is managed by Linux. Link: https://lore.kernel.org/lkml/20251013-kvm_rprocv5-v5-12-d609ed766061@oss.qualcomm.com/ Signed-off-by: Mukesh Ojha --- drivers/remoteproc/qcom_q6v5_pas.c | 48 ++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 1944df49893f6..8c44987733ca9 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -256,6 +257,22 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return ret; } +static void qcom_pas_unmap_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size) +{ + if (rproc->has_iommu) + iommu_unmap(rproc->domain, mem_phys, size); +} + +static int qcom_pas_map_carveout(struct rproc *rproc, phys_addr_t mem_phys, size_t size) +{ + int ret = 0; + + if (rproc->has_iommu) + ret = iommu_map(rproc->domain, mem_phys, mem_phys, size, + IOMMU_READ | IOMMU_WRITE, GFP_KERNEL); + return ret; +} + static int qcom_pas_start(struct rproc *rproc) { struct qcom_pas *pas = rproc->priv; @@ -290,11 +307,15 @@ static int qcom_pas_start(struct rproc *rproc) } if (pas->dtb_pas_id) { - ret = qcom_scm_pas_auth_and_reset(pas->dtb_pas_id); + ret = qcom_pas_map_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); + if (ret) + goto disable_px_supply; + + ret = qcom_scm_pas_prepare_and_auth_reset(pas->dtb_pas_ctx); if (ret) { dev_err(pas->dev, "failed to authenticate dtb image and release reset\n"); - goto disable_px_supply; + goto unmap_dtb_carveout; } } @@ -305,18 +326,22 @@ static int qcom_pas_start(struct rproc *rproc) qcom_pil_info_store(pas->info_name, pas->mem_phys, pas->mem_size); - ret = qcom_scm_pas_auth_and_reset(pas->pas_id); + ret = qcom_pas_map_carveout(rproc, pas->mem_phys, pas->mem_size); + if (ret) + goto release_pas_metadata; + + ret = qcom_scm_pas_prepare_and_auth_reset(pas->pas_ctx); if (ret) { dev_err(pas->dev, "failed to authenticate image and release reset\n"); - goto release_pas_metadata; + goto unmap_carveout; } ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000)); if (ret == -ETIMEDOUT) { dev_err(pas->dev, "start timed out\n"); qcom_scm_pas_shutdown(pas->pas_id); - goto release_pas_metadata; + goto unmap_carveout; } qcom_scm_pas_metadata_release(pas->pas_ctx); @@ -328,10 +353,16 @@ static int qcom_pas_start(struct rproc *rproc) return 0; +unmap_carveout: + qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size); release_pas_metadata: qcom_scm_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + +unmap_dtb_carveout: + if (pas->dtb_pas_id) + qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); disable_px_supply: if (pas->px_supply) regulator_disable(pas->px_supply); @@ -387,8 +418,12 @@ static int qcom_pas_stop(struct rproc *rproc) ret = qcom_scm_pas_shutdown(pas->dtb_pas_id); if (ret) dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret); + + qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); } + qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size); + handover = qcom_q6v5_unprepare(&pas->q6v5); if (handover) qcom_pas_handover(&pas->q6v5); @@ -758,6 +793,7 @@ static int qcom_pas_probe(struct platform_device *pdev) return -ENOMEM; } + rproc->has_iommu = of_property_present(pdev->dev.of_node, "iommus"); rproc->auto_boot = desc->auto_boot; rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); @@ -836,6 +872,8 @@ static int qcom_pas_probe(struct platform_device *pdev) goto remove_ssr_sysmon; } + pas->pas_ctx->has_iommu = rproc->has_iommu; + pas->dtb_pas_ctx->has_iommu = rproc->has_iommu; ret = rproc_add(rproc); if (ret) goto remove_ssr_sysmon; From 33aa29f82e625fa69f2b0d160c21d38939c9e95b Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 10 Oct 2025 16:28:28 +0530 Subject: [PATCH 20/67] FROMLIST: dt-bindings: phy: qcom-edp: Add missing clock for X Elite On X Elite platform, the eDP PHY uses one more clock called ref. The current X Elite devices supported upstream work fine without this clock, because the boot firmware leaves this clock enabled. But we should not rely on that. Also, even though this change breaks the ABI, it is needed in order to make the driver disables this clock along with the other ones, for a proper bring-down of the entire PHY. So attach the this ref clock to the PHY. Cc: stable@vger.kernel.org # v6.10 Fixes: 5d5607861350 ("dt-bindings: phy: qcom-edp: Add X1E80100 PHY compatibles") Link:https://lore.kernel.org/all/20250909-phy-qcom-edp-add-missing-refclk-v3-1-4ec55a0512ab@linaro.org/ Signed-off-by: Abel Vesa --- .../devicetree/bindings/phy/qcom,edp-phy.yaml | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index eb97181cbb957..bfc4d75f50ff9 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -37,12 +37,15 @@ properties: - description: PLL register block clocks: - maxItems: 2 + minItems: 2 + maxItems: 3 clock-names: + minItems: 2 items: - const: aux - const: cfg_ahb + - const: ref "#clock-cells": const: 1 @@ -64,6 +67,29 @@ required: - "#clock-cells" - "#phy-cells" +allOf: + - if: + properties: + compatible: + enum: + - qcom,x1e80100-dp-phy + then: + properties: + clocks: + minItems: 3 + maxItems: 3 + clock-names: + minItems: 3 + maxItems: 3 + else: + properties: + clocks: + minItems: 2 + maxItems: 2 + clock-names: + minItems: 2 + maxItems: 2 + additionalProperties: false examples: From 7bd7b6b50db096ccce47573e2eff6ccd0625dcb9 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 10 Oct 2025 16:30:30 +0530 Subject: [PATCH 21/67] FROMLIST: phy: qcom: edp: Make the number of clocks flexible On X Elite, the DP PHY needs another clock called ref, while all other platforms do not. The current X Elite devices supported upstream work fine without this clock, because the boot firmware leaves this clock enabled. But we should not rely on that. Also, even though this change breaks the ABI, it is needed in order to make the driver disables this clock along with the other ones, for a proper bring-down of the entire PHY. So in order to handle these clocks on different platforms, make the driver get all the clocks regardless of how many there are provided. Cc: stable@vger.kernel.org # v6.10 Fixes: db83c107dc29 ("phy: qcom: edp: Add v6 specific ops and X1E80100 platform support") Link:https://lore.kernel.org/all/20250909-phy-qcom-edp-add-missing-refclk-v3-2-4ec55a0512ab@linaro.org/ Signed-off-by: Abel Vesa --- drivers/phy/qualcomm/phy-qcom-edp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index f1b51018683d5..ca9bb9d70e29e 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -103,7 +103,9 @@ struct qcom_edp { struct phy_configure_opts_dp dp_opts; - struct clk_bulk_data clks[2]; + struct clk_bulk_data *clks; + int num_clks; + struct regulator_bulk_data supplies[2]; bool is_edp; @@ -218,7 +220,7 @@ static int qcom_edp_phy_init(struct phy *phy) if (ret) return ret; - ret = clk_bulk_prepare_enable(ARRAY_SIZE(edp->clks), edp->clks); + ret = clk_bulk_prepare_enable(edp->num_clks, edp->clks); if (ret) goto out_disable_supplies; @@ -885,7 +887,7 @@ static int qcom_edp_phy_exit(struct phy *phy) { struct qcom_edp *edp = phy_get_drvdata(phy); - clk_bulk_disable_unprepare(ARRAY_SIZE(edp->clks), edp->clks); + clk_bulk_disable_unprepare(edp->num_clks, edp->clks); regulator_bulk_disable(ARRAY_SIZE(edp->supplies), edp->supplies); return 0; @@ -1092,11 +1094,9 @@ static int qcom_edp_phy_probe(struct platform_device *pdev) if (IS_ERR(edp->pll)) return PTR_ERR(edp->pll); - edp->clks[0].id = "aux"; - edp->clks[1].id = "cfg_ahb"; - ret = devm_clk_bulk_get(dev, ARRAY_SIZE(edp->clks), edp->clks); - if (ret) - return ret; + edp->num_clks = devm_clk_bulk_get_all(dev, &edp->clks); + if (edp->num_clks < 0) + return dev_err_probe(dev, edp->num_clks, "failed to parse clocks\n"); edp->supplies[0].supply = "vdda-phy"; edp->supplies[1].supply = "vdda-pll"; From 1bf57b37a9bb879e370f9d89eb5fed44e66ab419 Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Fri, 10 Oct 2025 16:50:16 +0530 Subject: [PATCH 22/67] FROMLIST: dt-bindings: phy: qcom-edp: Add edp ref clk for sa8775p Add edp reference clock for sa8775p edp phy. Link:https://lore.kernel.org/all/20251013104806.6599-2-quic_riteshk@quicinc.com/ Signed-off-by: Ritesh Kumar --- Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index bfc4d75f50ff9..b0e4015596de6 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -73,6 +73,7 @@ allOf: compatible: enum: - qcom,x1e80100-dp-phy + - qcom,sa8775p-edp-phy then: properties: clocks: From 878843a076af2ce2343c4e321eeb0d4b60c339a3 Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Fri, 10 Oct 2025 16:56:30 +0530 Subject: [PATCH 23/67] FROMLIST: dt-bindings: display/msm: qcom,sa8775p-mdss: update edp phy example Update clock entry in edp phy example node to add support for edp reference clock. Link:https://lore.kernel.org/all/20251013104806.6599-3-quic_riteshk@quicinc.com/ Signed-off-by: Ritesh Kumar --- .../devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml index e2730a2f25cfb..6c827cf9692b9 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml @@ -200,9 +200,11 @@ examples: <0x0aec2000 0x1c8>; clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>, - <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>; + <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_EDP_REF_CLKREF_EN>; clock-names = "aux", - "cfg_ahb"; + "cfg_ahb", + "ref"; #clock-cells = <1>; #phy-cells = <0>; From 2efb8e5cf0df4955a8347808e791e7c5df6d436e Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Fri, 7 Nov 2025 02:20:07 +0530 Subject: [PATCH 24/67] FROMLIST: dt-bindings: display/msm: gpu: Document A612 GPU A612 GPU has a new IP called RGMU (Reduced Graphics Management Unit) which replaces GMU. But it doesn't do clock or voltage scaling. So we need the gpu core clock in the GPU node along with the power domain to do clock and voltage scaling from the kernel. Update the bindings to describe this GPU. Signed-off-by: Akhil P Oommen Link: https://lore.kernel.org/all/20251107-qcs615-spin-2-v2-2-a2d7c4fbf6e6@oss.qualcomm.com/ --- .../devicetree/bindings/display/msm/gpu.yaml | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/gpu.yaml b/Documentation/devicetree/bindings/display/msm/gpu.yaml index 3696b083e3530..8d1a579d47636 100644 --- a/Documentation/devicetree/bindings/display/msm/gpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/gpu.yaml @@ -45,11 +45,11 @@ properties: - const: amd,imageon clocks: - minItems: 2 + minItems: 1 maxItems: 7 clock-names: - minItems: 2 + minItems: 1 maxItems: 7 reg: @@ -388,6 +388,34 @@ allOf: required: - clocks - clock-names + + - if: + properties: + compatible: + contains: + const: qcom,adreno-612.0 + then: + properties: + clocks: + items: + - description: GPU Core clock + + clock-names: + items: + - const: core + + reg: + items: + - description: GPU Reg memory + + reg-names: + items: + - const: kgsl_3d0_reg_memory + + required: + - clocks + - clock-names + else: if: properties: From 229115a988e2a9ac5c6dcbf06e396be043b81592 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Fri, 7 Nov 2025 02:20:08 +0530 Subject: [PATCH 25/67] FROMLIST: dt-bindings: display/msm/rgmu: Document A612 RGMU RGMU a.k.a Reduced Graphics Management Unit is a small state machine with the sole purpose of providing IFPC (Inter Frame Power Collapse) support. Compared to GMU, it doesn't manage GPU clock, voltage scaling, bw voting or any other functionalities. All it does is detect an idle GPU and toggle the GDSC switch. As it doesn't access DDR space, it doesn't require iommu. So far, only Adreno 612 GPU has an RGMU core. Document RGMU in the GMU's schema. Signed-off-by: Jie Zhang Signed-off-by: Akhil P Oommen Link: https://lore.kernel.org/all/20251107-qcs615-spin-2-v2-3-a2d7c4fbf6e6@oss.qualcomm.com/ --- .../devicetree/bindings/display/msm/rgmu.yaml | 131 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 132 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/msm/rgmu.yaml diff --git a/Documentation/devicetree/bindings/display/msm/rgmu.yaml b/Documentation/devicetree/bindings/display/msm/rgmu.yaml new file mode 100644 index 0000000000000..7621556477d09 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/rgmu.yaml @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/display/msm/rgmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RGMU attached to certain Adreno GPUs + +maintainers: + - Rob Clark + +description: | + RGMU (Reduced Graphics Management Unit) IP is present in some GPUs that + belong to Adreno A6xx family. It is a small state machine that helps to + toggle the GX GDSC (connected to CX rail) to implement IFPC feature and save + power. + +properties: + compatible: + items: + - const: qcom,adreno-rgmu-612.0 + - const: qcom,adreno-rgmu + + reg: + items: + - description: Core RGMU registers + + reg-names: + items: + - const: gmu + + clocks: + items: + - description: GMU clock + - description: GPU CX clock + - description: GPU AXI clock + - description: GPU MEMNOC clock + - description: GPU SMMU vote clock + + clock-names: + items: + - const: gmu + - const: cxo + - const: axi + - const: memnoc + - const: smmu_vote + + power-domains: + items: + - description: CX GDSC power domain + - description: GX GDSC power domain + + power-domain-names: + items: + - const: cx + - const: gx + + interrupts: + items: + - description: GMU OOB interrupt + - description: GMU interrupt + + interrupt-names: + items: + - const: oob + - const: gmu + + operating-points-v2: true + opp-table: + type: object + +required: + - reg + - reg-names + - clocks + - clock-names + - power-domains + - power-domain-names + - interrupts + - interrupt-names + - operating-points-v2 + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + rgmu: rgmu@506a000 { + compatible = "qcom,adreno-rgmu-612.0", "qcom,adreno-rgmu"; + + reg = <0x05000000 0x90000>; + reg-names = "gmu"; + + clocks = <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + clock-names = "gmu", + "cxo", + "axi", + "memnoc", + "smmu_vote"; + + power-domains = <&gpucc CX_GDSC>, + <&gpucc GX_GDSC>; + power-domain-names = "cx", + "gx"; + + interrupts = , + ; + interrupt-names = "oob", + "gmu"; + + operating-points-v2 = <&rgmu_opp_table>; + + rgmu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index ddecf1ef3bed3..c7fa8487f9d51 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7882,6 +7882,7 @@ S: Maintained B: https://gitlab.freedesktop.org/drm/msm/-/issues T: git https://gitlab.freedesktop.org/drm/msm.git F: Documentation/devicetree/bindings/display/msm/gpu.yaml +F: Documentation/devicetree/bindings/display/msm/rgmu.yaml F: Documentation/devicetree/bindings/opp/opp-v2-qcom-adreno.yaml F: drivers/gpu/drm/msm/adreno/ F: drivers/gpu/drm/msm/msm_gpu.* From a69aa7a59ed897f5069853930009ea345bf93ef4 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:49 +0800 Subject: [PATCH 26/67] FROMLIST: drm/msm/dp: move link-specific parsing from dp_panel to dp_link Since max_dp_lanes and max_dp_link_rate are link-specific parameters, move their parsing from dp_panel to dp_link for better separation of concerns. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-13-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/gpu/drm/msm/dp/dp_link.c | 57 ++++++++++++++++++++++ drivers/gpu/drm/msm/dp/dp_link.h | 4 ++ drivers/gpu/drm/msm/dp/dp_panel.c | 78 ++++--------------------------- drivers/gpu/drm/msm/dp/dp_panel.h | 3 -- 4 files changed, 70 insertions(+), 72 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index 66e1bbd80db3a..2aeb3ecf76fab 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -6,12 +6,14 @@ #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ #include +#include #include #include "dp_reg.h" #include "dp_link.h" #include "dp_panel.h" +#define DP_LINK_RATE_HBR2 540000 /* kbytes */ #define DP_TEST_REQUEST_MASK 0x7F enum audio_sample_rate { @@ -1210,10 +1212,61 @@ u32 msm_dp_link_get_test_bits_depth(struct msm_dp_link *msm_dp_link, u32 bpp) return tbd; } +static u32 msm_dp_link_link_frequencies(struct device_node *of_node) +{ + struct device_node *endpoint; + u64 frequency = 0; + int cnt; + + endpoint = of_graph_get_endpoint_by_regs(of_node, 1, 0); /* port@1 */ + if (!endpoint) + return 0; + + cnt = of_property_count_u64_elems(endpoint, "link-frequencies"); + + if (cnt > 0) + of_property_read_u64_index(endpoint, "link-frequencies", + cnt - 1, &frequency); + of_node_put(endpoint); + + do_div(frequency, + 10 * /* from symbol rate to link rate */ + 1000); /* kbytes */ + + return frequency; +} + +static int msm_dp_link_parse_dt(struct device *dev, struct msm_dp_link *msm_dp_link) +{ + struct device_node *of_node = dev->of_node; + int cnt; + + /* + * data-lanes is the property of msm_dp_out endpoint + */ + cnt = drm_of_get_data_lanes_count_ep(of_node, 1, 0, 1, DP_MAX_NUM_DP_LANES); + if (cnt < 0) { + /* legacy code, data-lanes is the property of mdss_dp node */ + cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES); + } + + if (cnt > 0) + msm_dp_link->max_dp_lanes = cnt; + else + msm_dp_link->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */ + + msm_dp_link->max_dp_link_rate = msm_dp_link_link_frequencies(of_node); + if (!msm_dp_link->max_dp_link_rate) + msm_dp_link->max_dp_link_rate = DP_LINK_RATE_HBR2; + + return 0; +} + struct msm_dp_link *msm_dp_link_get(struct device *dev, struct drm_dp_aux *aux) { struct msm_dp_link_private *link; struct msm_dp_link *msm_dp_link; + int ret; if (!dev || !aux) { DRM_ERROR("invalid input\n"); @@ -1229,5 +1282,9 @@ struct msm_dp_link *msm_dp_link_get(struct device *dev, struct drm_dp_aux *aux) mutex_init(&link->psm_mutex); msm_dp_link = &link->msm_dp_link; + ret = msm_dp_link_parse_dt(dev, msm_dp_link); + if (ret) + return ERR_PTR(ret); + return msm_dp_link; } diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h index ba47c6d19fbfa..0684a962d4ec9 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.h +++ b/drivers/gpu/drm/msm/dp/dp_link.h @@ -12,6 +12,7 @@ #define DS_PORT_STATUS_CHANGED 0x200 #define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF #define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0) +#define DP_MAX_NUM_DP_LANES 4 struct msm_dp_link_info { unsigned char revision; @@ -72,6 +73,9 @@ struct msm_dp_link { struct msm_dp_link_test_audio test_audio; struct msm_dp_link_phy_params phy_params; struct msm_dp_link_info link_params; + + u32 max_dp_lanes; + u32 max_dp_link_rate; }; /** diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 15b7f6c7146e1..ad5d55bf009db 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -16,9 +16,6 @@ #define DP_INTF_CONFIG_DATABUS_WIDEN BIT(4) -#define DP_MAX_NUM_DP_LANES 4 -#define DP_LINK_RATE_HBR2 540000 /* kbytes */ - struct msm_dp_panel_private { struct device *dev; struct drm_device *drm_dev; @@ -91,6 +88,7 @@ static int msm_dp_panel_read_dpcd(struct msm_dp_panel *msm_dp_panel) int rc, max_lttpr_lanes, max_lttpr_rate; struct msm_dp_panel_private *panel; struct msm_dp_link_info *link_info; + struct msm_dp_link *link; u8 *dpcd, major, minor; panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); @@ -105,16 +103,20 @@ static int msm_dp_panel_read_dpcd(struct msm_dp_panel *msm_dp_panel) major = (link_info->revision >> 4) & 0x0f; minor = link_info->revision & 0x0f; + link = panel->link; + drm_dbg_dp(panel->drm_dev, "max_lanes=%d max_link_rate=%d\n", + link->max_dp_lanes, link->max_dp_link_rate); + link_info->rate = drm_dp_max_link_rate(dpcd); link_info->num_lanes = drm_dp_max_lane_count(dpcd); /* Limit data lanes from data-lanes of endpoint property of dtsi */ - if (link_info->num_lanes > msm_dp_panel->max_dp_lanes) - link_info->num_lanes = msm_dp_panel->max_dp_lanes; + if (link_info->num_lanes > link->max_dp_lanes) + link_info->num_lanes = link->max_dp_lanes; /* Limit link rate from link-frequencies of endpoint property of dtsi */ - if (link_info->rate > msm_dp_panel->max_dp_link_rate) - link_info->rate = msm_dp_panel->max_dp_link_rate; + if (link_info->rate > link->max_dp_link_rate) + link_info->rate = link->max_dp_link_rate; /* Limit data lanes from LTTPR capabilities, if any */ max_lttpr_lanes = drm_dp_lttpr_max_lane_count(panel->link->lttpr_common_caps); @@ -173,9 +175,6 @@ int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel, panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); - drm_dbg_dp(panel->drm_dev, "max_lanes=%d max_link_rate=%d\n", - msm_dp_panel->max_dp_lanes, msm_dp_panel->max_dp_link_rate); - rc = msm_dp_panel_read_dpcd(msm_dp_panel); if (rc) { DRM_ERROR("read dpcd failed %d\n", rc); @@ -648,60 +647,6 @@ int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel) return 0; } -static u32 msm_dp_panel_link_frequencies(struct device_node *of_node) -{ - struct device_node *endpoint; - u64 frequency = 0; - int cnt; - - endpoint = of_graph_get_endpoint_by_regs(of_node, 1, 0); /* port@1 */ - if (!endpoint) - return 0; - - cnt = of_property_count_u64_elems(endpoint, "link-frequencies"); - - if (cnt > 0) - of_property_read_u64_index(endpoint, "link-frequencies", - cnt - 1, &frequency); - of_node_put(endpoint); - - do_div(frequency, - 10 * /* from symbol rate to link rate */ - 1000); /* kbytes */ - - return frequency; -} - -static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel) -{ - struct msm_dp_panel_private *panel; - struct device_node *of_node; - int cnt; - - panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); - of_node = panel->dev->of_node; - - /* - * data-lanes is the property of msm_dp_out endpoint - */ - cnt = drm_of_get_data_lanes_count_ep(of_node, 1, 0, 1, DP_MAX_NUM_DP_LANES); - if (cnt < 0) { - /* legacy code, data-lanes is the property of mdss_dp node */ - cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES); - } - - if (cnt > 0) - msm_dp_panel->max_dp_lanes = cnt; - else - msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */ - - msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node); - if (!msm_dp_panel->max_dp_link_rate) - msm_dp_panel->max_dp_link_rate = DP_LINK_RATE_HBR2; - - return 0; -} - struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux, struct msm_dp_link *link, void __iomem *link_base, @@ -709,7 +654,6 @@ struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux { struct msm_dp_panel_private *panel; struct msm_dp_panel *msm_dp_panel; - int ret; if (!dev || !aux || !link) { DRM_ERROR("invalid input\n"); @@ -729,10 +673,6 @@ struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux msm_dp_panel = &panel->msm_dp_panel; msm_dp_panel->max_bw_code = DP_LINK_BW_8_1; - ret = msm_dp_panel_parse_dt(msm_dp_panel); - if (ret) - return ERR_PTR(ret); - return msm_dp_panel; } diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index d2cf401506dcb..921a296852d4d 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -41,9 +41,6 @@ struct msm_dp_panel { bool vsc_sdp_supported; u32 hw_revision; - u32 max_dp_lanes; - u32 max_dp_link_rate; - u32 max_bw_code; }; From 6ca12d0f05a2959e70be7c97133192fa0de15d75 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:50 +0800 Subject: [PATCH 27/67] FROMLIST: drm/msm/dp: Add support for lane mapping configuration QCS615 platform requires non-default logical-to-physical lane mapping due to its unique hardware routing. Unlike the standard mapping sequence <0 1 2 3>, QCS615 uses <3 2 0 1>, which necessitates explicit configuration via the data-lanes property in the device tree. This ensures correct signal routing between the DP controller and PHY. For partial definitions, fill remaining lanes with unused physical lanes in ascending order. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-14-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/gpu/drm/msm/dp/dp_ctrl.c | 10 +++--- drivers/gpu/drm/msm/dp/dp_link.c | 61 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/dp/dp_link.h | 1 + 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index c42fd2c17a328..cbcc7c2f0ffc4 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -423,13 +423,13 @@ static void msm_dp_ctrl_config_ctrl(struct msm_dp_ctrl_private *ctrl) static void msm_dp_ctrl_lane_mapping(struct msm_dp_ctrl_private *ctrl) { - u32 ln_0 = 0, ln_1 = 1, ln_2 = 2, ln_3 = 3; /* One-to-One mapping */ + u32 *lane_map = ctrl->link->lane_map; u32 ln_mapping; - ln_mapping = ln_0 << LANE0_MAPPING_SHIFT; - ln_mapping |= ln_1 << LANE1_MAPPING_SHIFT; - ln_mapping |= ln_2 << LANE2_MAPPING_SHIFT; - ln_mapping |= ln_3 << LANE3_MAPPING_SHIFT; + ln_mapping = lane_map[0] << LANE0_MAPPING_SHIFT; + ln_mapping |= lane_map[1] << LANE1_MAPPING_SHIFT; + ln_mapping |= lane_map[2] << LANE2_MAPPING_SHIFT; + ln_mapping |= lane_map[3] << LANE3_MAPPING_SHIFT; msm_dp_write_link(ctrl, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING, ln_mapping); diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index 2aeb3ecf76fab..2ae78d33fffd7 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -1236,6 +1236,62 @@ static u32 msm_dp_link_link_frequencies(struct device_node *of_node) return frequency; } +/* + * Always populate msm_dp_link->lane_map with 4 lanes. + * - Use DTS "data-lanes" if present; otherwise fall back to default mapping. + * - For partial definitions, fill remaining entries with unused lanes in + * ascending order. + */ +static int msm_dp_link_lane_map(struct device *dev, struct msm_dp_link *msm_dp_link) +{ + struct device_node *of_node = dev->of_node; + struct device_node *endpoint; + int cnt = msm_dp_link->max_dp_lanes; + u32 tmp[DP_MAX_NUM_DP_LANES]; + u32 map[DP_MAX_NUM_DP_LANES] = {0, 1, 2, 3}; /* default 1:1 mapping */ + bool used[DP_MAX_NUM_DP_LANES] = {false}; + int i, ret = -EINVAL; + + endpoint = of_graph_get_endpoint_by_regs(of_node, 1, -1); + if (endpoint) { + ret = of_property_read_u32_array(endpoint, "data-lanes", tmp, cnt); + if (ret) + dev_dbg(dev, "endpoint data-lanes read failed (ret=%d)\n", ret); + } + + if (ret) { + ret = of_property_read_u32_array(of_node, "data-lanes", tmp, cnt); + if (ret) { + dev_info(dev, "data-lanes not defined, set to default\n"); + goto out; + } + } + + for (i = 0; i < cnt; i++) { + if (tmp[i] >= DP_MAX_NUM_DP_LANES) { + dev_err(dev, "data-lanes[%d]=%u out of range\n", i, tmp[i]); + return -EINVAL; + } + used[tmp[i]] = true; + map[i] = tmp[i]; + } + + /* Fill the remaining entries with unused physical lanes (ascending) */ + i = cnt; + for (int j = 0; i < DP_MAX_NUM_DP_LANES && j < DP_MAX_NUM_DP_LANES; j++) { + if (!used[j]) + map[i++] = j; + } + +out: + if (endpoint) + of_node_put(endpoint); + + dev_dbg(dev, "data-lanes count %d <%d %d %d %d>\n", cnt, map[0], map[1], map[2], map[3]); + memcpy(msm_dp_link->lane_map, map, sizeof(map)); + return 0; +} + static int msm_dp_link_parse_dt(struct device *dev, struct msm_dp_link *msm_dp_link) { struct device_node *of_node = dev->of_node; @@ -1255,6 +1311,11 @@ static int msm_dp_link_parse_dt(struct device *dev, struct msm_dp_link *msm_dp_l else msm_dp_link->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */ + if (msm_dp_link_lane_map(dev, msm_dp_link)) { + dev_err(dev, "failed to parse data-lanes\n"); + return -EINVAL; + } + msm_dp_link->max_dp_link_rate = msm_dp_link_link_frequencies(of_node); if (!msm_dp_link->max_dp_link_rate) msm_dp_link->max_dp_link_rate = DP_LINK_RATE_HBR2; diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h index 0684a962d4ec9..b1eb2de6d2a76 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.h +++ b/drivers/gpu/drm/msm/dp/dp_link.h @@ -74,6 +74,7 @@ struct msm_dp_link { struct msm_dp_link_phy_params phy_params; struct msm_dp_link_info link_params; + u32 lane_map[DP_MAX_NUM_DP_LANES]; u32 max_dp_lanes; u32 max_dp_link_rate; }; From 3a23b5e6587da99f1fe609a4a1013575145b5a9b Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Tue, 16 Sep 2025 20:11:03 +0800 Subject: [PATCH 28/67] FROMLIST: dt-bindings: display/msm: dp-controller: Add SM6150 Add DisplayPort controller binding for Qualcomm SM6150 SoC. SM6150 uses the same controller IP as SM8150. Declare 'qcom,sm6150-dp' as a fallback compatible to 'qcom,sm8150-dp' and 'qcom,sm8350-dp' for consistency with existing bindings and to ensure correct matching and future clarity. Signed-off-by: Xiangxu Yin Acked-by: Rob Herring (Arm) Signed-off-by: Yongxing Mou Link: https://lore.kernel.org/all/20250916-add-dp-controller-support-for-sm6150-v3-1-dd60ebbd101e@oss.qualcomm.com/ --- .../devicetree/bindings/display/msm/dp-controller.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index ea88e1903f26a..d26e51db7b6bb 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -58,6 +58,12 @@ properties: - qcom,sm8550-dp - const: qcom,sm8350-dp + - items: + - enum: + - qcom,sm6150-dp + - const: qcom,sm8150-dp + - const: qcom,sm8350-dp + - items: - enum: - qcom,sm8750-dp From b844ff0be8b5fecb6dbc1e90418ffd97237fbcc0 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Tue, 4 Nov 2025 09:33:23 +0800 Subject: [PATCH 29/67] FROMLIST: dt-bindings: display: msm: sm6150-mdss: Add DisplayPort controller SM6150 uses the same DisplayPort controller as SM8150, which is compatible with SM8350. Add SM6150-specific compatible string for the DisplayPort controller. Signed-off-by: Xiangxu Yin Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/all/20251104-add-displayport-support-to-qcs615-devicetree-v7-1-e51669170a6f@oss.qualcomm.com/ --- .../devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml index 9ac24f99d3ada..98949deed9ae0 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml @@ -51,6 +51,14 @@ patternProperties: compatible: const: qcom,sm6150-dpu + "^displayport-controller@[0-9a-f]+$": + type: object + additionalProperties: true + properties: + compatible: + contains: + const: qcom,sm6150-dp + "^dsi@[0-9a-f]+$": type: object additionalProperties: true From 5cd96d76c3db5a4f4dd0173f857e935a9848e523 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Tue, 4 Nov 2025 09:33:24 +0800 Subject: [PATCH 30/67] FROMLIST: dt-bindings: display: msm: sm6150-mdss: Fix example indentation and OPP values Improve the binding example by fixing indentation and adding missing blank lines for better readability. Also correct the OPP clock values to match the actual SM6150 DTS configuration. Reviewed-by: Rob Herring (Arm) Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20251104-add-displayport-support-to-qcs615-devicetree-v7-2-e51669170a6f@oss.qualcomm.com/ --- .../display/msm/qcom,sm6150-mdss.yaml | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml index 98949deed9ae0..46e9335f849fe 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6150-mdss.yaml @@ -138,35 +138,37 @@ examples: #size-cells = <0>; port@0 { - reg = <0>; - dpu_intf0_out: endpoint { - }; + reg = <0>; + + dpu_intf0_out: endpoint { + }; }; port@1 { - reg = <1>; - dpu_intf1_out: endpoint { - remote-endpoint = <&mdss_dsi0_in>; - }; + reg = <1>; + + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; }; }; mdp_opp_table: opp-table { compatible = "operating-points-v2"; - opp-19200000 { - opp-hz = /bits/ 64 <19200000>; - required-opps = <&rpmhpd_opp_low_svs>; + opp-192000000 { + opp-hz = /bits/ 64 <192000000>; + required-opps = <&rpmhpd_opp_low_svs>; }; - opp-25600000 { - opp-hz = /bits/ 64 <25600000>; - required-opps = <&rpmhpd_opp_svs>; + opp-256000000 { + opp-hz = /bits/ 64 <256000000>; + required-opps = <&rpmhpd_opp_svs>; }; opp-307200000 { - opp-hz = /bits/ 64 <307200000>; - required-opps = <&rpmhpd_opp_nom>; + opp-hz = /bits/ 64 <307200000>; + required-opps = <&rpmhpd_opp_nom>; }; }; }; From 583091636e1ceb37c55f98c36daf7c5258e0c5cf Mon Sep 17 00:00:00 2001 From: Xin Ji Date: Tue, 18 Nov 2025 15:49:51 +0530 Subject: [PATCH 31/67] FROMLIST: drm/bridge: anx7625: Fix EDID block size at drm_edid_alloc() calling Since DRM validates the all of EDID blocks, allocates drm_edid data structure based on the actually block count returned by the sink monitor at drm_edid_alloc() calling. Fixes: 7c585f9a71aa ("drm/bridge: anx7625: use struct drm_edid more") Signed-off-by: Xin Ji Link: https://lore.kernel.org/all/20250808064613.2623732-1-xji@analogixsemi.com/ Signed-off-by: Arpit Saini --- drivers/gpu/drm/bridge/analogix/anx7625.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 6f3fdcb6afdb9..0bb8be08a77cc 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1801,7 +1801,7 @@ static const struct drm_edid *anx7625_edid_read(struct anx7625_data *ctx) return NULL; } - ctx->cached_drm_edid = drm_edid_alloc(edid_buf, FOUR_BLOCK_SIZE); + ctx->cached_drm_edid = drm_edid_alloc(edid_buf, edid_num * EDID_LENGTH); kfree(edid_buf); out: From db4ef25967c15c811a3e87d69b4bee80feab1efa Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:37 +0800 Subject: [PATCH 32/67] FROMLIST: dt-bindings: phy: Add QMP USB3+DP PHY for QCS615 Add device tree binding documentation for the Qualcomm QMP USB3+DP PHY on QCS615 Platform. This PHY supports both USB3 and DP functionality over USB-C, with PHY mode switching capability. It does not support combo mode. Reviewed-by: Rob Herring (Arm) Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-1-dc5edaac6c2b@oss.qualcomm.com/ --- .../phy/qcom,qcs615-qmp-usb3dp-phy.yaml | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml new file mode 100644 index 0000000000000..efb465c71c1b5 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml @@ -0,0 +1,111 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/qcom,qcs615-qmp-usb3dp-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QMP USB3-DP PHY controller (DP, QCS615) + +maintainers: + - Xiangxu Yin + +description: + The QMP PHY controller supports physical layer functionality for both USB3 + and DisplayPort over USB-C. While it enables mode switching between USB3 and + DisplayPort, but does not support combo mode. + +properties: + compatible: + enum: + - qcom,qcs615-qmp-usb3-dp-phy + + reg: + maxItems: 1 + + clocks: + maxItems: 4 + + clock-names: + items: + - const: aux + - const: ref + - const: cfg_ahb + - const: pipe + + resets: + maxItems: 2 + + reset-names: + items: + - const: phy_phy + - const: dp_phy + + vdda-phy-supply: true + + vdda-pll-supply: true + + "#clock-cells": + const: 1 + description: + See include/dt-bindings/phy/phy-qcom-qmp.h + + "#phy-cells": + const: 1 + description: + See include/dt-bindings/phy/phy-qcom-qmp.h + + qcom,tcsr-reg: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to TCSR hardware block + - description: offset of the VLS CLAMP register + - description: offset of the PHY mode register + description: Clamp and PHY mode register present in the TCSR + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - reset-names + - vdda-phy-supply + - vdda-pll-supply + - "#clock-cells" + - "#phy-cells" + - qcom,tcsr-reg + +additionalProperties: false + +examples: + - | + #include + #include + + phy@88e8000 { + compatible = "qcom,qcs615-qmp-usb3-dp-phy"; + reg = <0x88e8000 0x2000>; + + clocks = <&gcc GCC_USB2_SEC_PHY_AUX_CLK>, + <&gcc GCC_USB3_SEC_CLKREF_CLK>, + <&gcc GCC_AHB2PHY_WEST_CLK>, + <&gcc GCC_USB2_SEC_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + + resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, + <&gcc GCC_USB3_DP_PHY_SEC_BCR>; + reset-names = "phy_phy", + "dp_phy"; + + vdda-phy-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l12a>; + + #clock-cells = <1>; + #phy-cells = <1>; + + qcom,tcsr-reg = <&tcsr 0xbff0 0xb24c>; + }; From be1aa2097f25b20a7d66617dcbe7331206c48056 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Thu, 13 Nov 2025 16:00:16 +0800 Subject: [PATCH 33/67] FROMLIST: phy: qcom: qmp-usbc: Rename USB-specific ops to prepare for DP support To support following DisplayPort (DP) mode over the Type-C PHY, rename USB-specific functions and ops to clearly separate them from common or DP-related logic. This is a preparatory cleanup to enable USB + DP dual mode. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-2-dc5edaac6c2b@oss.qualcomm.com/ Signed-off-by: Yongxing Mou --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 55 ++++++++++++------------ 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 5e7fcb26744a4..62920dd2aed39 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -342,11 +342,10 @@ struct qmp_usbc { struct mutex phy_mutex; + struct phy *usb_phy; enum phy_mode mode; unsigned int usb_init_count; - struct phy *phy; - struct clk_fixed_rate pipe_clk_fixed; struct typec_switch_dev *sw; @@ -454,7 +453,7 @@ static const struct qmp_phy_cfg sdm660_usb3phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; -static int qmp_usbc_init(struct phy *phy) +static int qmp_usbc_com_init(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -504,7 +503,7 @@ static int qmp_usbc_init(struct phy *phy) return ret; } -static int qmp_usbc_exit(struct phy *phy) +static int qmp_usbc_com_exit(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -518,7 +517,7 @@ static int qmp_usbc_exit(struct phy *phy) return 0; } -static int qmp_usbc_power_on(struct phy *phy) +static int qmp_usbc_usb_power_on(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -566,7 +565,7 @@ static int qmp_usbc_power_on(struct phy *phy) return ret; } -static int qmp_usbc_power_off(struct phy *phy) +static int qmp_usbc_usb_power_off(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -587,20 +586,20 @@ static int qmp_usbc_power_off(struct phy *phy) return 0; } -static int qmp_usbc_enable(struct phy *phy) +static int qmp_usbc_usb_enable(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); int ret; mutex_lock(&qmp->phy_mutex); - ret = qmp_usbc_init(phy); + ret = qmp_usbc_com_init(phy); if (ret) goto out_unlock; - ret = qmp_usbc_power_on(phy); + ret = qmp_usbc_usb_power_on(phy); if (ret) { - qmp_usbc_exit(phy); + qmp_usbc_com_exit(phy); goto out_unlock; } @@ -611,19 +610,19 @@ static int qmp_usbc_enable(struct phy *phy) return ret; } -static int qmp_usbc_disable(struct phy *phy) +static int qmp_usbc_usb_disable(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); int ret; qmp->usb_init_count--; - ret = qmp_usbc_power_off(phy); + ret = qmp_usbc_usb_power_off(phy); if (ret) return ret; - return qmp_usbc_exit(phy); + return qmp_usbc_com_exit(phy); } -static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode) +static int qmp_usbc_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct qmp_usbc *qmp = phy_get_drvdata(phy); @@ -632,10 +631,10 @@ static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode) return 0; } -static const struct phy_ops qmp_usbc_phy_ops = { - .init = qmp_usbc_enable, - .exit = qmp_usbc_disable, - .set_mode = qmp_usbc_set_mode, +static const struct phy_ops qmp_usbc_usb_phy_ops = { + .init = qmp_usbc_usb_enable, + .exit = qmp_usbc_usb_disable, + .set_mode = qmp_usbc_usb_set_mode, .owner = THIS_MODULE, }; @@ -690,7 +689,7 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev) dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); - if (!qmp->phy->init_count) { + if (!qmp->usb_init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; } @@ -710,7 +709,7 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev) dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); - if (!qmp->phy->init_count) { + if (!qmp->usb_init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; } @@ -865,11 +864,11 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw, qmp->orientation = orientation; if (qmp->usb_init_count) { - qmp_usbc_power_off(qmp->phy); - qmp_usbc_exit(qmp->phy); + qmp_usbc_usb_power_off(qmp->usb_phy); + qmp_usbc_com_exit(qmp->usb_phy); - qmp_usbc_init(qmp->phy); - qmp_usbc_power_on(qmp->phy); + qmp_usbc_com_init(qmp->usb_phy); + qmp_usbc_usb_power_on(qmp->usb_phy); } mutex_unlock(&qmp->phy_mutex); @@ -1097,14 +1096,14 @@ static int qmp_usbc_probe(struct platform_device *pdev) if (ret) goto err_node_put; - qmp->phy = devm_phy_create(dev, np, &qmp_usbc_phy_ops); - if (IS_ERR(qmp->phy)) { - ret = PTR_ERR(qmp->phy); + qmp->usb_phy = devm_phy_create(dev, np, &qmp_usbc_usb_phy_ops); + if (IS_ERR(qmp->usb_phy)) { + ret = PTR_ERR(qmp->usb_phy); dev_err(dev, "failed to create PHY: %d\n", ret); goto err_node_put; } - phy_set_drvdata(qmp->phy, qmp); + phy_set_drvdata(qmp->usb_phy, qmp); of_node_put(np); From 8ba9951395f2219093e2b36e13de87d21268bf4e Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:39 +0800 Subject: [PATCH 34/67] FROMLIST: phy: qcom: qmp-usbc: Add DP-related fields for USB/DP switchable PHY Extend qmp_usbc_offsets and qmp_phy_cfg with DP-specific fields, including register offsets, init tables, and callback hooks. Also update qmp_usbc struct to track DP-related resources and state. This enables support for USB/DP switchable Type-C PHYs that operate in either mode. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-3-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 54 ++++++++++++++++++++---- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 62920dd2aed39..de28c3464a40e 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -293,13 +293,18 @@ struct qmp_usbc_offsets { /* for PHYs with >= 2 lanes */ u16 tx2; u16 rx2; + + u16 dp_serdes; + u16 dp_txa; + u16 dp_txb; + u16 dp_dp_phy; }; -/* struct qmp_phy_cfg - per-PHY initialization config */ +struct qmp_usbc; struct qmp_phy_cfg { const struct qmp_usbc_offsets *offsets; - /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ + /* Init sequence for USB PHY blocks - serdes, tx, rx, pcs */ const struct qmp_phy_init_tbl *serdes_tbl; int serdes_tbl_num; const struct qmp_phy_init_tbl *tx_tbl; @@ -309,6 +314,27 @@ struct qmp_phy_cfg { const struct qmp_phy_init_tbl *pcs_tbl; int pcs_tbl_num; + /* Init sequence for DP PHY blocks - serdes, tx, rbr, hbr, hbr2 */ + const struct qmp_phy_init_tbl *dp_serdes_tbl; + int dp_serdes_tbl_num; + const struct qmp_phy_init_tbl *dp_tx_tbl; + int dp_tx_tbl_num; + const struct qmp_phy_init_tbl *serdes_tbl_rbr; + int serdes_tbl_rbr_num; + const struct qmp_phy_init_tbl *serdes_tbl_hbr; + int serdes_tbl_hbr_num; + const struct qmp_phy_init_tbl *serdes_tbl_hbr2; + int serdes_tbl_hbr2_num; + + const u8 (*swing_tbl)[4][4]; + const u8 (*pre_emphasis_tbl)[4][4]; + + /* DP PHY callbacks */ + void (*dp_aux_init)(struct qmp_usbc *qmp); + void (*configure_dp_tx)(struct qmp_usbc *qmp); + int (*configure_dp_phy)(struct qmp_usbc *qmp); + int (*calibrate_dp_phy)(struct qmp_usbc *qmp); + /* regulators to be requested */ const char * const *vreg_list; int num_vregs; @@ -329,24 +355,36 @@ struct qmp_usbc { void __iomem *rx; void __iomem *tx2; void __iomem *rx2; - - struct regmap *tcsr_map; - u32 vls_clamp_reg; + void __iomem *dp_dp_phy; + void __iomem *dp_tx; + void __iomem *dp_tx2; + void __iomem *dp_serdes; struct clk *pipe_clk; + struct clk_fixed_rate pipe_clk_fixed; + + struct clk_hw dp_link_hw; + struct clk_hw dp_pixel_hw; struct clk_bulk_data *clks; int num_clks; int num_resets; struct reset_control_bulk_data *resets; struct regulator_bulk_data *vregs; + struct regmap *tcsr_map; + u32 vls_clamp_reg; + u32 dp_phy_mode_reg; + struct mutex phy_mutex; struct phy *usb_phy; enum phy_mode mode; unsigned int usb_init_count; - struct clk_fixed_rate pipe_clk_fixed; + struct phy *dp_phy; + unsigned int dp_aux_cfg; + struct phy_configure_opts_dp dp_opts; + unsigned int dp_init_count; struct typec_switch_dev *sw; enum typec_orientation orientation; @@ -689,7 +727,7 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev) dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); - if (!qmp->usb_init_count) { + if (!qmp->usb_init_count && !qmp->dp_init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; } @@ -709,7 +747,7 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev) dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); - if (!qmp->usb_init_count) { + if (!qmp->usb_init_count && !qmp->dp_init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; } From e7dc039e96b95f2c955951aae0dfb99de4d9761c Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:40 +0800 Subject: [PATCH 35/67] FROMLIST: phy: qcom: qmp-usbc: Add regulator init_load support QMP USBC PHY drivers previously did not set init_load_uA for regulators, which could result in incorrect vote levels. This patch introduces regulator definitions with proper init_load_uA values based on each chip's power grid design. QCS615 USB3 PHY was previously reusing qcm2290_usb3phy_cfg, but its regulator requirements differ. A new qcs615_usb3phy_cfg is added to reflect the correct settings. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-4-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 68 ++++++++++++++---------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index de28c3464a40e..3b48c69f9c3cb 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -336,7 +336,7 @@ struct qmp_phy_cfg { int (*calibrate_dp_phy)(struct qmp_usbc *qmp); /* regulators to be requested */ - const char * const *vreg_list; + const struct regulator_bulk_data *vreg_list; int num_vregs; /* array of registers with different offsets */ @@ -428,9 +428,19 @@ static const char * const usb3phy_reset_l[] = { "phy_phy", "phy", }; -/* list of regulators */ -static const char * const qmp_phy_vreg_l[] = { - "vdda-phy", "vdda-pll", +static const struct regulator_bulk_data qmp_phy_msm8998_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 68600 }, + { .supply = "vdda-pll", .init_load_uA = 14200 }, +}; + +static const struct regulator_bulk_data qmp_phy_sm2290_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 66100 }, + { .supply = "vdda-pll", .init_load_uA = 13300 }, +}; + +static const struct regulator_bulk_data qmp_phy_qcs615_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 50000 }, + { .supply = "vdda-pll", .init_load_uA = 20000 }, }; static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = { @@ -454,8 +464,8 @@ static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl), .pcs_tbl = msm8998_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = qmp_phy_msm8998_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l), .regs = qmp_v3_usb3phy_regs_layout, }; @@ -470,8 +480,8 @@ static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), .pcs_tbl = qcm2290_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = qmp_phy_sm2290_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_sm2290_vreg_l), .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; @@ -486,8 +496,24 @@ static const struct qmp_phy_cfg sdm660_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(sdm660_usb3_rx_tbl), .pcs_tbl = qcm2290_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = qmp_phy_msm8998_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout_qcm2290, +}; + +static const struct qmp_phy_cfg qcs615_usb3phy_cfg = { + .offsets = &qmp_usbc_offsets_v3_qcm2290, + + .serdes_tbl = qcm2290_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), + .tx_tbl = qcm2290_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), + .rx_tbl = qcm2290_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), + .pcs_tbl = qcm2290_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .vreg_list = qmp_phy_qcs615_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l), .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; @@ -773,23 +799,6 @@ static const struct dev_pm_ops qmp_usbc_pm_ops = { qmp_usbc_runtime_resume, NULL) }; -static int qmp_usbc_vreg_init(struct qmp_usbc *qmp) -{ - const struct qmp_phy_cfg *cfg = qmp->cfg; - struct device *dev = qmp->dev; - int num = cfg->num_vregs; - int i; - - qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); - if (!qmp->vregs) - return -ENOMEM; - - for (i = 0; i < num; i++) - qmp->vregs[i].supply = cfg->vreg_list[i]; - - return devm_regulator_bulk_get(dev, num, qmp->vregs); -} - static int qmp_usbc_reset_init(struct qmp_usbc *qmp, const char *const *reset_list, int num_resets) @@ -1097,7 +1106,8 @@ static int qmp_usbc_probe(struct platform_device *pdev) mutex_init(&qmp->phy_mutex); - ret = qmp_usbc_vreg_init(qmp); + ret = devm_regulator_bulk_get_const(qmp->dev, qmp->cfg->num_vregs, + qmp->cfg->vreg_list, &qmp->vregs); if (ret) return ret; @@ -1163,7 +1173,7 @@ static const struct of_device_id qmp_usbc_of_match_table[] = { .data = &qcm2290_usb3phy_cfg, }, { .compatible = "qcom,qcs615-qmp-usb3-phy", - .data = &qcm2290_usb3phy_cfg, + .data = &qcs615_usb3phy_cfg, }, { .compatible = "qcom,sdm660-qmp-usb3-phy", .data = &sdm660_usb3phy_cfg, From 3bd29bda845bf499118c2f4133080d964a1a733c Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:41 +0800 Subject: [PATCH 36/67] FROMLIST: phy: qcom: qmp-usbc: Move reset config into PHY cfg The original reset list only works for USB-only PHYs. USB3DP PHYs require different reset names such as "dp_phy", so they need a separate list. Moving reset configuration into qmp_phy_cfg allows per-PHY customization without adding special-case logic in DT parsing. The legacy DT path keeps using the old hardcoded list, while non-legacy paths use cfg->reset_list. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-5-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 3b48c69f9c3cb..f9e20f43435c0 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -335,7 +335,8 @@ struct qmp_phy_cfg { int (*configure_dp_phy)(struct qmp_usbc *qmp); int (*calibrate_dp_phy)(struct qmp_usbc *qmp); - /* regulators to be requested */ + const char * const *reset_list; + int num_resets; const struct regulator_bulk_data *vreg_list; int num_vregs; @@ -464,6 +465,8 @@ static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl), .pcs_tbl = msm8998_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl), + .reset_list = usb3phy_reset_l, + .num_resets = ARRAY_SIZE(usb3phy_reset_l), .vreg_list = qmp_phy_msm8998_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l), .regs = qmp_v3_usb3phy_regs_layout, @@ -480,6 +483,8 @@ static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), .pcs_tbl = qcm2290_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .reset_list = usb3phy_reset_l, + .num_resets = ARRAY_SIZE(usb3phy_reset_l), .vreg_list = qmp_phy_sm2290_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_sm2290_vreg_l), .regs = qmp_v3_usb3phy_regs_layout_qcm2290, @@ -496,6 +501,8 @@ static const struct qmp_phy_cfg sdm660_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(sdm660_usb3_rx_tbl), .pcs_tbl = qcm2290_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .reset_list = usb3phy_reset_l, + .num_resets = ARRAY_SIZE(usb3phy_reset_l), .vreg_list = qmp_phy_msm8998_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l), .regs = qmp_v3_usb3phy_regs_layout_qcm2290, @@ -512,6 +519,8 @@ static const struct qmp_phy_cfg qcs615_usb3phy_cfg = { .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), .pcs_tbl = qcm2290_usb3_pcs_tbl, .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .reset_list = usb3phy_reset_l, + .num_resets = ARRAY_SIZE(usb3phy_reset_l), .vreg_list = qmp_phy_qcs615_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l), .regs = qmp_v3_usb3phy_regs_layout_qcm2290, @@ -1051,8 +1060,7 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) "failed to get pipe clock\n"); } - ret = qmp_usbc_reset_init(qmp, usb3phy_reset_l, - ARRAY_SIZE(usb3phy_reset_l)); + ret = qmp_usbc_reset_init(qmp, cfg->reset_list, cfg->num_resets); if (ret) return ret; From e59ab936a65e515dde2c23ffea1b2cb1bcc15550 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:42 +0800 Subject: [PATCH 37/67] FROMLIST: phy: qcom: qmp-usbc: add DP link and vco_div clocks for DP PHY USB3DP PHY requires link and vco_div clocks when operating in DP mode. Extend qmp_usbc_register_clocks and the clock provider logic to register these clocks along with the existing pipe clock, to support both USB and DP configurations. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-6-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 210 ++++++++++++++++++++++- 1 file changed, 204 insertions(+), 6 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index f9e20f43435c0..7139f4dab82fd 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "phy-qcom-qmp-common.h" @@ -851,9 +852,23 @@ static int qmp_usbc_clk_init(struct qmp_usbc *qmp) return devm_clk_bulk_get_optional(dev, num, qmp->clks); } -static void phy_clk_release_provider(void *res) +static struct clk_hw *qmp_usbc_clks_hw_get(struct of_phandle_args *clkspec, void *data) { - of_clk_del_provider(res); + struct qmp_usbc *qmp = data; + + if (clkspec->args_count == 0) + return &qmp->pipe_clk_fixed.hw; + + switch (clkspec->args[0]) { + case QMP_USB43DP_USB3_PIPE_CLK: + return &qmp->pipe_clk_fixed.hw; + case QMP_USB43DP_DP_LINK_CLK: + return &qmp->dp_link_hw; + case QMP_USB43DP_DP_VCO_DIV_CLK: + return &qmp->dp_pixel_hw; + } + + return ERR_PTR(-EINVAL); } /* @@ -878,12 +893,14 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np) { struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed; struct clk_init_data init = { }; + char name[64]; int ret; ret = of_property_read_string(np, "clock-output-names", &init.name); if (ret) { - dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); - return ret; + /* Clock name is not mandatory. */ + snprintf(name, sizeof(name), "%s::pipe_clk", dev_name(qmp->dev)); + init.name = name; } init.ops = &clk_fixed_rate_ops; @@ -892,10 +909,184 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np) fixed->fixed_rate = 125000000; fixed->hw.init = &init; - ret = devm_clk_hw_register(qmp->dev, &fixed->hw); + return devm_clk_hw_register(qmp->dev, &fixed->hw); +} + + +/* + * Display Port PLL driver block diagram for branch clocks + * + * +------------------------------+ + * | DP_VCO_CLK | + * | | + * | +-------------------+ | + * | | (DP PLL/VCO) | | + * | +---------+---------+ | + * | v | + * | +----------+-----------+ | + * | | hsclk_divsel_clk_src | | + * | +----------+-----------+ | + * +------------------------------+ + * | + * +---------<---------v------------>----------+ + * | | + * +--------v----------------+ | + * | dp_phy_pll_link_clk | | + * | link_clk | | + * +--------+----------------+ | + * | | + * | | + * v v + * Input to DISPCC block | + * for link clk, crypto clk | + * and interface clock | + * | + * | + * +--------<------------+-----------------+---<---+ + * | | | + * +----v---------+ +--------v-----+ +--------v------+ + * | vco_divided | | vco_divided | | vco_divided | + * | _clk_src | | _clk_src | | _clk_src | + * | | | | | | + * |divsel_six | | divsel_two | | divsel_four | + * +-------+------+ +-----+--------+ +--------+------+ + * | | | + * v---->----------v-------------<------v + * | + * +----------+-----------------+ + * | dp_phy_pll_vco_div_clk | + * +---------+------------------+ + * | + * v + * Input to DISPCC block + * for DP pixel clock + * + */ +static int qmp_dp_pixel_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + switch (req->rate) { + case 1620000000UL / 2: + case 2700000000UL / 2: + /* 5.4 is same link rate as 2.7GHz, i.e. div 4 */ + return 0; + default: + return -EINVAL; + } +} + +static unsigned long qmp_dp_pixel_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + const struct qmp_usbc *qmp; + const struct phy_configure_opts_dp *dp_opts; + + qmp = container_of(hw, struct qmp_usbc, dp_pixel_hw); + + dp_opts = &qmp->dp_opts; + + switch (dp_opts->link_rate) { + case 1620: + return 1620000000UL / 2; + case 2700: + return 2700000000UL / 2; + case 5400: + return 5400000000UL / 4; + default: + return 0; + } +} + +static const struct clk_ops qmp_dp_pixel_clk_ops = { + .determine_rate = qmp_dp_pixel_clk_determine_rate, + .recalc_rate = qmp_dp_pixel_clk_recalc_rate, +}; + +static int qmp_dp_link_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + switch (req->rate) { + case 162000000: + case 270000000: + case 540000000: + return 0; + default: + return -EINVAL; + } +} + +static unsigned long qmp_dp_link_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + const struct qmp_usbc *qmp; + const struct phy_configure_opts_dp *dp_opts; + + qmp = container_of(hw, struct qmp_usbc, dp_link_hw); + dp_opts = &qmp->dp_opts; + + switch (dp_opts->link_rate) { + case 1620: + case 2700: + case 5400: + return dp_opts->link_rate * 100000; + default: + return 0; + } +} + +static const struct clk_ops qmp_dp_link_clk_ops = { + .determine_rate = qmp_dp_link_clk_determine_rate, + .recalc_rate = qmp_dp_link_clk_recalc_rate, +}; + +static int phy_dp_clks_register(struct qmp_usbc *qmp, struct device_node *np) +{ + struct clk_init_data init = { }; + char name[64]; + int ret; + + snprintf(name, sizeof(name), "%s::link_clk", dev_name(qmp->dev)); + init.ops = &qmp_dp_link_clk_ops; + init.name = name; + qmp->dp_link_hw.init = &init; + ret = devm_clk_hw_register(qmp->dev, &qmp->dp_link_hw); + if (ret < 0) { + dev_err(qmp->dev, "link clk reg fail ret=%d\n", ret); + return ret; + } + + snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(qmp->dev)); + init.ops = &qmp_dp_pixel_clk_ops; + init.name = name; + qmp->dp_pixel_hw.init = &init; + ret = devm_clk_hw_register(qmp->dev, &qmp->dp_pixel_hw); + if (ret) { + dev_err(qmp->dev, "pxl clk reg fail ret=%d\n", ret); + return ret; + } + + return 0; +} + +static void phy_clk_release_provider(void *res) +{ + of_clk_del_provider(res); +} + +static int qmp_usbc_register_clocks(struct qmp_usbc *qmp, struct device_node *np) +{ + struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed; + int ret; + + ret = phy_pipe_clk_register(qmp, np); if (ret) return ret; + if (qmp->dp_serdes != 0) { + ret = phy_dp_clks_register(qmp, np); + if (ret) + return ret; + } + + if (np == qmp->dev->of_node) + return devm_of_clk_add_hw_provider(qmp->dev, qmp_usbc_clks_hw_get, qmp); + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw); if (ret) return ret; @@ -1040,6 +1231,13 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) if (IS_ERR(base)) return PTR_ERR(base); + if (offs->dp_serdes != 0) { + qmp->dp_serdes = base + offs->dp_serdes; + qmp->dp_tx = base + offs->dp_txa; + qmp->dp_tx2 = base + offs->dp_txb; + qmp->dp_dp_phy = base + offs->dp_dp_phy; + } + qmp->serdes = base + offs->serdes; qmp->pcs = base + offs->pcs; if (offs->pcs_misc) @@ -1148,7 +1346,7 @@ static int qmp_usbc_probe(struct platform_device *pdev) */ pm_runtime_forbid(dev); - ret = phy_pipe_clk_register(qmp, np); + ret = qmp_usbc_register_clocks(qmp, np); if (ret) goto err_node_put; From 32b9bd91af80df76f75909b44c60607e13597a64 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:43 +0800 Subject: [PATCH 38/67] FROMLIST: phy: qcom: qmp-usbc: Move USB-only init to usb_power_on The current implementation programs USB-specific registers in qmp_usbc_com_init(), which is shared by both USB and DP modes. This causes unnecessary configuration when the PHY is used for DP. Move USB-only register setup from com_init to qmp_usbc_usb_power_on, so it runs only for USB mode. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-7-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 7139f4dab82fd..a971bdc3e7677 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -30,6 +30,8 @@ #include "phy-qcom-qmp-pcs-misc-v3.h" #define PHY_INIT_COMPLETE_TIMEOUT 10000 +#define SW_PORTSELECT_VAL BIT(0) +#define SW_PORTSELECT_MUX BIT(1) /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { @@ -531,8 +533,6 @@ static int qmp_usbc_com_init(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; - void __iomem *pcs = qmp->pcs; - u32 val = 0; int ret; ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); @@ -557,16 +557,6 @@ static int qmp_usbc_com_init(struct phy *phy) if (ret) goto err_assert_reset; - qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); - -#define SW_PORTSELECT_VAL BIT(0) -#define SW_PORTSELECT_MUX BIT(1) - /* Use software based port select and switch on typec orientation */ - val = SW_PORTSELECT_MUX; - if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) - val |= SW_PORTSELECT_VAL; - writel(val, qmp->pcs_misc); - return 0; err_assert_reset: @@ -599,6 +589,14 @@ static int qmp_usbc_usb_power_on(struct phy *phy) unsigned int val; int ret; + qphy_setbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); + + /* Use software based port select and switch on typec orientation */ + val = SW_PORTSELECT_MUX; + if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) + val |= SW_PORTSELECT_VAL; + writel(val, qmp->pcs_misc); + qmp_configure(qmp->dev, qmp->serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); From 7452b82d5279ff894ea0bbabcbe4281232b004a3 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:44 +0800 Subject: [PATCH 39/67] FROMLIST: phy: qcom: qmp-usbc: Add TCSR parsing and PHY mode setting Extend TCSR parsing to read optional dp_phy_mode_reg and add qmp_usbc_set_phy_mode() to switch between USB and DP modes when supported. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-8-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 25 ++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index a971bdc3e7677..fab6ccc4a5f12 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -529,6 +529,12 @@ static const struct qmp_phy_cfg qcs615_usb3phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; +static void qmp_usbc_set_phy_mode(struct qmp_usbc *qmp, bool is_dp) +{ + if (qmp->tcsr_map && qmp->dp_phy_mode_reg) + regmap_write(qmp->tcsr_map, qmp->dp_phy_mode_reg, is_dp); +} + static int qmp_usbc_com_init(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); @@ -669,6 +675,8 @@ static int qmp_usbc_usb_enable(struct phy *phy) if (ret) goto out_unlock; + qmp_usbc_set_phy_mode(qmp, false); + ret = qmp_usbc_usb_power_on(phy); if (ret) { qmp_usbc_com_exit(phy); @@ -1113,6 +1121,7 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw, qmp_usbc_com_exit(qmp->usb_phy); qmp_usbc_com_init(qmp->usb_phy); + qmp_usbc_set_phy_mode(qmp, false); qmp_usbc_usb_power_on(qmp->usb_phy); } @@ -1263,15 +1272,16 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) return 0; } -static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp) +static int qmp_usbc_parse_tcsr(struct qmp_usbc *qmp) { struct of_phandle_args tcsr_args; struct device *dev = qmp->dev; - int ret; + int ret, args_count; - /* for backwards compatibility ignore if there is no property */ - ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg", 1, 0, - &tcsr_args); + args_count = of_property_count_u32_elems(dev->of_node, "qcom,tcsr-reg"); + args_count = args_count - 1; + ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg", + args_count, 0, &tcsr_args); if (ret == -ENOENT) return 0; else if (ret < 0) @@ -1284,6 +1294,9 @@ static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp) qmp->vls_clamp_reg = tcsr_args.args[0]; + if (args_count > 1) + qmp->dp_phy_mode_reg = tcsr_args.args[1]; + return 0; } @@ -1319,7 +1332,7 @@ static int qmp_usbc_probe(struct platform_device *pdev) if (ret) return ret; - ret = qmp_usbc_parse_vls_clamp(qmp); + ret = qmp_usbc_parse_tcsr(qmp); if (ret) return ret; From 49d7e4e72e979725e58b8e4e39c013b80ff20126 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:45 +0800 Subject: [PATCH 40/67] FROMLIST: phy: qcom: qmp-usbc: Add DP PHY ops for USB/DP switchable Type-C PHYs Define qmp_usbc_dp_phy_ops struct to support DP mode on USB/DP switchable PHYs. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-9-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 194 ++++++++++++++++++++++- 1 file changed, 193 insertions(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index fab6ccc4a5f12..3580c19fd62e0 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -29,6 +29,8 @@ #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" +#include "phy-qcom-qmp-dp-phy.h" + #define PHY_INIT_COMPLETE_TIMEOUT 10000 #define SW_PORTSELECT_VAL BIT(0) #define SW_PORTSELECT_MUX BIT(1) @@ -711,6 +713,159 @@ static int qmp_usbc_usb_set_mode(struct phy *phy, enum phy_mode mode, int submod return 0; } +static int qmp_usbc_dp_enable(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + int ret; + + if (qmp->dp_init_count) { + dev_err(qmp->dev, "DP already inited\n"); + return 0; + } + + mutex_lock(&qmp->phy_mutex); + + ret = qmp_usbc_com_init(phy); + if (ret) + goto dp_init_unlock; + + qmp_usbc_set_phy_mode(qmp, true); + + cfg->dp_aux_init(qmp); + + qmp->dp_init_count++; + +dp_init_unlock: + mutex_unlock(&qmp->phy_mutex); + return ret; +} + +static int qmp_usbc_dp_disable(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + + mutex_lock(&qmp->phy_mutex); + + qmp_usbc_com_exit(phy); + + qmp->dp_init_count--; + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + +static int qmp_usbc_dp_configure(struct phy *phy, union phy_configure_opts *opts) +{ + const struct phy_configure_opts_dp *dp_opts = &opts->dp; + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + mutex_lock(&qmp->phy_mutex); + + memcpy(&qmp->dp_opts, dp_opts, sizeof(*dp_opts)); + if (qmp->dp_opts.set_voltages) { + cfg->configure_dp_tx(qmp); + qmp->dp_opts.set_voltages = 0; + } + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + +static int qmp_usbc_dp_calibrate(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + int ret = 0; + + mutex_lock(&qmp->phy_mutex); + + if (cfg->calibrate_dp_phy) { + ret = cfg->calibrate_dp_phy(qmp); + if (ret) { + dev_err(qmp->dev, "dp calibrate err(%d)\n", ret); + mutex_unlock(&qmp->phy_mutex); + return ret; + } + } + + mutex_unlock(&qmp->phy_mutex); + return 0; +} + +static int qmp_usbc_dp_serdes_init(struct qmp_usbc *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *serdes = qmp->dp_serdes; + const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; + + qmp_configure(qmp->dev, serdes, cfg->dp_serdes_tbl, + cfg->dp_serdes_tbl_num); + + switch (dp_opts->link_rate) { + case 1620: + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_rbr, + cfg->serdes_tbl_rbr_num); + break; + case 2700: + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr, + cfg->serdes_tbl_hbr_num); + break; + case 5400: + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr2, + cfg->serdes_tbl_hbr2_num); + break; + default: + /* Other link rates aren't supported */ + return -EINVAL; + } + + return 0; +} + +static int qmp_usbc_dp_power_on(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + void __iomem *tx = qmp->dp_tx; + void __iomem *tx2 = qmp->dp_tx2; + + mutex_lock(&qmp->phy_mutex); + + qmp_usbc_dp_serdes_init(qmp); + + qmp_configure_lane(qmp->dev, tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1); + qmp_configure_lane(qmp->dev, tx2, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 2); + + /* Configure special DP tx tunings */ + cfg->configure_dp_tx(qmp); + + /* Configure link rate, swing, etc. */ + cfg->configure_dp_phy(qmp); + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + +static int qmp_usbc_dp_power_off(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + + mutex_lock(&qmp->phy_mutex); + + /* Assert DP PHY power down */ + writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + static const struct phy_ops qmp_usbc_usb_phy_ops = { .init = qmp_usbc_usb_enable, .exit = qmp_usbc_usb_disable, @@ -718,6 +873,16 @@ static const struct phy_ops qmp_usbc_usb_phy_ops = { .owner = THIS_MODULE, }; +static const struct phy_ops qmp_usbc_dp_phy_ops = { + .init = qmp_usbc_dp_enable, + .exit = qmp_usbc_dp_disable, + .configure = qmp_usbc_dp_configure, + .calibrate = qmp_usbc_dp_calibrate, + .power_on = qmp_usbc_dp_power_on, + .power_off = qmp_usbc_dp_power_off, + .owner = THIS_MODULE, +}; + static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -1300,6 +1465,23 @@ static int qmp_usbc_parse_tcsr(struct qmp_usbc *qmp) return 0; } +static struct phy *qmp_usbc_phy_xlate(struct device *dev, const struct of_phandle_args *args) +{ + struct qmp_usbc *qmp = dev_get_drvdata(dev); + + if (args->args_count == 0) + return qmp->usb_phy; + + switch (args->args[0]) { + case QMP_USB43DP_USB3_PHY: + return qmp->usb_phy; + case QMP_USB43DP_DP_PHY: + return qmp->dp_phy ?: ERR_PTR(-ENODEV); + } + + return ERR_PTR(-EINVAL); +} + static int qmp_usbc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1370,9 +1552,19 @@ static int qmp_usbc_probe(struct platform_device *pdev) phy_set_drvdata(qmp->usb_phy, qmp); + if (qmp->dp_serdes != 0) { + qmp->dp_phy = devm_phy_create(dev, np, &qmp_usbc_dp_phy_ops); + if (IS_ERR(qmp->dp_phy)) { + ret = PTR_ERR(qmp->dp_phy); + dev_err(dev, "failed to create PHY: %d\n", ret); + goto err_node_put; + } + phy_set_drvdata(qmp->dp_phy, qmp); + } + of_node_put(np); - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + phy_provider = devm_of_phy_provider_register(dev, qmp_usbc_phy_xlate); return PTR_ERR_OR_ZERO(phy_provider); From d07074cbfd8ad8e0d80df325c9071b72efd20ba3 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:46 +0800 Subject: [PATCH 41/67] FROMLIST: phy: qcom: qmp-usbc: Add USB/DP exclude handling When both USB and DP PHY modes are enabled simultaneously on the same QMP USBC PHY, it can lead to hardware misconfiguration and undefined behavior. This happens because the PHY resources are not designed to operate in both modes at the same time. To prevent this, introduce a mutual exclusion check between USB and DP PHY modes. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-10-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 3580c19fd62e0..d84bf68940043 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -666,6 +666,19 @@ static int qmp_usbc_usb_power_off(struct phy *phy) return 0; } +static int qmp_usbc_check_phy_status(struct qmp_usbc *qmp, bool is_dp) +{ + if ((is_dp && qmp->usb_init_count) || + (!is_dp && qmp->dp_init_count)) { + dev_err(qmp->dev, + "PHY is configured for %s, can not enable %s\n", + is_dp ? "USB" : "DP", is_dp ? "DP" : "USB"); + return -EBUSY; + } + + return 0; +} + static int qmp_usbc_usb_enable(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); @@ -673,6 +686,10 @@ static int qmp_usbc_usb_enable(struct phy *phy) mutex_lock(&qmp->phy_mutex); + ret = qmp_usbc_check_phy_status(qmp, false); + if (ret) + goto out_unlock; + ret = qmp_usbc_com_init(phy); if (ret) goto out_unlock; @@ -726,6 +743,10 @@ static int qmp_usbc_dp_enable(struct phy *phy) mutex_lock(&qmp->phy_mutex); + ret = qmp_usbc_check_phy_status(qmp, true); + if (ret) + goto dp_init_unlock; + ret = qmp_usbc_com_init(phy); if (ret) goto dp_init_unlock; From fd6dde969f57310cdade97b4759ef5af55ae43db Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:47 +0800 Subject: [PATCH 42/67] FROMLIST: phy: qcom: qmp: Add DP v2 PHY register definitions Add dedicated headers for DP v2 PHY, including QSERDES COM and TX/RX register definitions. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-11-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h | 21 ++++ .../qualcomm/phy-qcom-qmp-qserdes-com-v2.h | 106 ++++++++++++++++++ .../qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h | 68 +++++++++++ drivers/phy/qualcomm/phy-qcom-qmp.h | 3 + 4 files changed, 198 insertions(+) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h new file mode 100644 index 0000000000000..8b9572d3cdebb --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_V2_H_ +#define QCOM_PHY_QMP_DP_PHY_V2_H_ + +// /* Only for QMP V2 PHY - DP PHY registers */ +#define QSERDES_V2_DP_PHY_AUX_INTERRUPT_MASK 0x048 +#define QSERDES_V2_DP_PHY_AUX_INTERRUPT_CLEAR 0x04c +#define QSERDES_V2_DP_PHY_AUX_BIST_CFG 0x050 + +#define QSERDES_V2_DP_PHY_VCO_DIV 0x068 +#define QSERDES_V2_DP_PHY_TX0_TX1_LANE_CTL 0x06c +#define QSERDES_V2_DP_PHY_TX2_TX3_LANE_CTL 0x088 + +#define QSERDES_V2_DP_PHY_SPARE0 0x0ac +#define QSERDES_V2_DP_PHY_STATUS 0x0c0 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h new file mode 100644 index 0000000000000..3ea1884f35dd5 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_COM_V2_H_ +#define QCOM_PHY_QMP_QSERDES_COM_V2_H_ + +/* Only for QMP V2 PHY - QSERDES COM registers */ +#define QSERDES_V2_COM_ATB_SEL1 0x000 +#define QSERDES_V2_COM_ATB_SEL2 0x004 +#define QSERDES_V2_COM_FREQ_UPDATE 0x008 +#define QSERDES_V2_COM_BG_TIMER 0x00c +#define QSERDES_V2_COM_SSC_EN_CENTER 0x010 +#define QSERDES_V2_COM_SSC_ADJ_PER1 0x014 +#define QSERDES_V2_COM_SSC_ADJ_PER2 0x018 +#define QSERDES_V2_COM_SSC_PER1 0x01c +#define QSERDES_V2_COM_SSC_PER2 0x020 +#define QSERDES_V2_COM_SSC_STEP_SIZE1 0x024 +#define QSERDES_V2_COM_SSC_STEP_SIZE2 0x028 +#define QSERDES_V2_COM_POST_DIV 0x02c +#define QSERDES_V2_COM_POST_DIV_MUX 0x030 +#define QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN 0x034 +#define QSERDES_V2_COM_CLK_ENABLE1 0x038 +#define QSERDES_V2_COM_SYS_CLK_CTRL 0x03c +#define QSERDES_V2_COM_SYSCLK_BUF_ENABLE 0x040 +#define QSERDES_V2_COM_PLL_EN 0x044 +#define QSERDES_V2_COM_PLL_IVCO 0x048 +#define QSERDES_V2_COM_LOCK_CMP1_MODE0 0x04c +#define QSERDES_V2_COM_LOCK_CMP2_MODE0 0x050 +#define QSERDES_V2_COM_LOCK_CMP3_MODE0 0x054 +#define QSERDES_V2_COM_LOCK_CMP1_MODE1 0x058 +#define QSERDES_V2_COM_LOCK_CMP2_MODE1 0x05c +#define QSERDES_V2_COM_LOCK_CMP3_MODE1 0x060 +#define QSERDES_V2_COM_EP_CLOCK_DETECT_CTR 0x068 +#define QSERDES_V2_COM_SYSCLK_DET_COMP_STATUS 0x06c +#define QSERDES_V2_COM_CLK_EP_DIV 0x074 +#define QSERDES_V2_COM_CP_CTRL_MODE0 0x078 +#define QSERDES_V2_COM_CP_CTRL_MODE1 0x07c +#define QSERDES_V2_COM_PLL_RCTRL_MODE0 0x084 +#define QSERDES_V2_COM_PLL_RCTRL_MODE1 0x088 +#define QSERDES_V2_COM_PLL_CCTRL_MODE0 0x090 +#define QSERDES_V2_COM_PLL_CCTRL_MODE1 0x094 +#define QSERDES_V2_COM_PLL_CNTRL 0x09c +#define QSERDES_V2_COM_BIAS_EN_CTRL_BY_PSM 0x0a8 +#define QSERDES_V2_COM_SYSCLK_EN_SEL 0x0ac +#define QSERDES_V2_COM_CML_SYSCLK_SEL 0x0b0 +#define QSERDES_V2_COM_RESETSM_CNTRL 0x0b4 +#define QSERDES_V2_COM_RESETSM_CNTRL2 0x0b8 +#define QSERDES_V2_COM_LOCK_CMP_EN 0x0c8 +#define QSERDES_V2_COM_LOCK_CMP_CFG 0x0cc +#define QSERDES_V2_COM_DEC_START_MODE0 0x0d0 +#define QSERDES_V2_COM_DEC_START_MODE1 0x0d4 +#define QSERDES_V2_COM_VCOCAL_DEADMAN_CTRL 0x0d8 +#define QSERDES_V2_COM_DIV_FRAC_START1_MODE0 0x0dc +#define QSERDES_V2_COM_DIV_FRAC_START2_MODE0 0x0e0 +#define QSERDES_V2_COM_DIV_FRAC_START3_MODE0 0x0e4 +#define QSERDES_V2_COM_DIV_FRAC_START1_MODE1 0x0e8 +#define QSERDES_V2_COM_DIV_FRAC_START2_MODE1 0x0ec +#define QSERDES_V2_COM_DIV_FRAC_START3_MODE1 0x0f0 +#define QSERDES_V2_COM_VCO_TUNE_MINVAL1 0x0f4 +#define QSERDES_V2_COM_VCO_TUNE_MINVAL2 0x0f8 +#define QSERDES_V2_COM_INTEGLOOP_INITVAL 0x100 +#define QSERDES_V2_COM_INTEGLOOP_EN 0x104 +#define QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0 0x108 +#define QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE0 0x10c +#define QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE1 0x110 +#define QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE1 0x114 +#define QSERDES_V2_COM_VCO_TUNE_MAXVAL1 0x118 +#define QSERDES_V2_COM_VCO_TUNE_MAXVAL2 0x11c +#define QSERDES_V2_COM_VCO_TUNE_CTRL 0x124 +#define QSERDES_V2_COM_VCO_TUNE_MAP 0x128 +#define QSERDES_V2_COM_VCO_TUNE1_MODE0 0x12c +#define QSERDES_V2_COM_VCO_TUNE2_MODE0 0x130 +#define QSERDES_V2_COM_VCO_TUNE1_MODE1 0x134 +#define QSERDES_V2_COM_VCO_TUNE2_MODE1 0x138 +#define QSERDES_V2_COM_VCO_TUNE_INITVAL1 0x13c +#define QSERDES_V2_COM_VCO_TUNE_INITVAL2 0x140 +#define QSERDES_V2_COM_VCO_TUNE_TIMER1 0x144 +#define QSERDES_V2_COM_VCO_TUNE_TIMER2 0x148 +#define QSERDES_V2_COM_CMN_STATUS 0x15c +#define QSERDES_V2_COM_RESET_SM_STATUS 0x160 +#define QSERDES_V2_COM_RESTRIM_CODE_STATUS 0x164 +#define QSERDES_V2_COM_PLLCAL_CODE1_STATUS 0x168 +#define QSERDES_V2_COM_PLLCAL_CODE2_STATUS 0x16c +#define QSERDES_V2_COM_CLK_SELECT 0x174 +#define QSERDES_V2_COM_HSCLK_SEL 0x178 +#define QSERDES_V2_COM_INTEGLOOP_BINCODE_STATUS 0x17c +#define QSERDES_V2_COM_PLL_ANALOG 0x180 +#define QSERDES_V2_COM_CORECLK_DIV 0x184 +#define QSERDES_V2_COM_SW_RESET 0x188 +#define QSERDES_V2_COM_CORE_CLK_EN 0x18c +#define QSERDES_V2_COM_C_READY_STATUS 0x190 +#define QSERDES_V2_COM_CMN_CONFIG 0x194 +#define QSERDES_V2_COM_CMN_RATE_OVERRIDE 0x198 +#define QSERDES_V2_COM_SVS_MODE_CLK_SEL 0x19c +#define QSERDES_V2_COM_DEBUG_BUS0 0x1a0 +#define QSERDES_V2_COM_DEBUG_BUS1 0x1a4 +#define QSERDES_V2_COM_DEBUG_BUS2 0x1a8 +#define QSERDES_V2_COM_DEBUG_BUS3 0x1ac +#define QSERDES_V2_COM_DEBUG_BUS_SEL 0x1b0 +#define QSERDES_V2_COM_CMN_MISC1 0x1b4 +#define QSERDES_V2_COM_CMN_MISC2 0x1b8 +#define QSERDES_V2_COM_CORECLK_DIV_MODE1 0x1bc + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h new file mode 100644 index 0000000000000..34919720b7bc4 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_TXRX_V2_H_ +#define QCOM_PHY_QMP_QSERDES_TXRX_V2_H_ + +/* Only for QMP V2 PHY - TX registers */ +#define QSERDES_V2_TX_BIST_MODE_LANENO 0x000 +#define QSERDES_V2_TX_CLKBUF_ENABLE 0x008 +#define QSERDES_V2_TX_TX_EMP_POST1_LVL 0x00c +#define QSERDES_V2_TX_TX_DRV_LVL 0x01c +#define QSERDES_V2_TX_RESET_TSYNC_EN 0x024 +#define QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN 0x028 +#define QSERDES_V2_TX_TX_BAND 0x02c +#define QSERDES_V2_TX_SLEW_CNTL 0x030 +#define QSERDES_V2_TX_INTERFACE_SELECT 0x034 +#define QSERDES_V2_TX_RES_CODE_LANE_TX 0x03c +#define QSERDES_V2_TX_RES_CODE_LANE_RX 0x040 +#define QSERDES_V2_TX_RES_CODE_LANE_OFFSET_TX 0x044 +#define QSERDES_V2_TX_RES_CODE_LANE_OFFSET_RX 0x048 +#define QSERDES_V2_TX_DEBUG_BUS_SEL 0x058 +#define QSERDES_V2_TX_TRANSCEIVER_BIAS_EN 0x05c +#define QSERDES_V2_TX_HIGHZ_DRVR_EN 0x060 +#define QSERDES_V2_TX_TX_POL_INV 0x064 +#define QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN 0x068 +#define QSERDES_V2_TX_LANE_MODE_1 0x08c +#define QSERDES_V2_TX_LANE_MODE_2 0x090 +#define QSERDES_V2_TX_LANE_MODE_3 0x094 +#define QSERDES_V2_TX_RCV_DETECT_LVL_2 0x0a4 +#define QSERDES_V2_TX_TRAN_DRVR_EMP_EN 0x0c0 +#define QSERDES_V2_TX_TX_INTERFACE_MODE 0x0c4 +#define QSERDES_V2_TX_VMODE_CTRL1 0x0f0 + +/* Only for QMP V2 PHY - RX registers */ +#define QSERDES_V2_RX_UCDR_FO_GAIN 0x008 +#define QSERDES_V2_RX_UCDR_SO_GAIN_HALF 0x00c +#define QSERDES_V2_RX_UCDR_SO_GAIN 0x014 +#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_HALF 0x024 +#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028 +#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN 0x02c +#define QSERDES_V2_RX_UCDR_FASTLOCK_FO_GAIN 0x030 +#define QSERDES_V2_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034 +#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c +#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040 +#define QSERDES_V2_RX_UCDR_PI_CONTROLS 0x044 +#define QSERDES_V2_RX_RX_TERM_BW 0x07c +#define QSERDES_V2_RX_VGA_CAL_CNTRL1 0x0bc +#define QSERDES_V2_RX_VGA_CAL_CNTRL2 0x0c0 +#define QSERDES_V2_RX_RX_EQ_GAIN2_LSB 0x0c8 +#define QSERDES_V2_RX_RX_EQ_GAIN2_MSB 0x0cc +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL1 0x0d0 +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d4 +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3 0x0d8 +#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4 0x0dc +#define QSERDES_V2_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x0f8 +#define QSERDES_V2_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x0fc +#define QSERDES_V2_RX_SIGDET_ENABLES 0x100 +#define QSERDES_V2_RX_SIGDET_CNTRL 0x104 +#define QSERDES_V2_RX_SIGDET_LVL 0x108 +#define QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL 0x10c +#define QSERDES_V2_RX_RX_BAND 0x110 +#define QSERDES_V2_RX_RX_INTERFACE_MODE 0x11c +#define QSERDES_V2_RX_RX_MODE_00 0x164 +#define QSERDES_V2_RX_RX_MODE_01 0x168 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index f58c82b2dd23e..1a9e4cc5aa11d 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -9,6 +9,9 @@ #include "phy-qcom-qmp-qserdes-com.h" #include "phy-qcom-qmp-qserdes-txrx.h" +#include "phy-qcom-qmp-qserdes-com-v2.h" +#include "phy-qcom-qmp-qserdes-txrx-v2.h" + #include "phy-qcom-qmp-qserdes-com-v3.h" #include "phy-qcom-qmp-qserdes-txrx-v3.h" From 23b7645da336e8abf546c3c16c7c02095bd86194 Mon Sep 17 00:00:00 2001 From: Xiangxu Yin Date: Fri, 26 Sep 2025 15:25:48 +0800 Subject: [PATCH 43/67] FROMLIST: phy: qcom: qmp-usbc: Add QCS615 USB/DP PHY config and DP mode support Add QCS615-specific configuration for USB/DP PHY, including DP init routines, voltage swing tables, and platform data. Add compatible "qcs615-qmp-usb3-dp-phy". Note: SW_PORTSELECT handling for orientation flip is not implemented due to QCS615 fixed-orientation design and non-standard lane mapping. Signed-off-by: Xiangxu Yin Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/all/20250926-add-displayport-support-for-qcs615-platform-v7-12-dc5edaac6c2b@oss.qualcomm.com/ --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 413 +++++++++++++++++++++++ 1 file changed, 413 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index d84bf68940043..105cc0f4b8ddd 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -30,6 +30,7 @@ #include "phy-qcom-qmp-pcs-misc-v3.h" #include "phy-qcom-qmp-dp-phy.h" +#include "phy-qcom-qmp-dp-phy-v2.h" #define PHY_INIT_COMPLETE_TIMEOUT 10000 #define SW_PORTSELECT_VAL BIT(0) @@ -289,6 +290,83 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88), }; +static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x37), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_CTRL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x40), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x08), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x05), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x02), +}; + +static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_rbr[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x2c), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xbf), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x21), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), +}; + +static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x38), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), +}; + +static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr2[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x8c), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x70), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), +}; + +static const struct qmp_phy_init_tbl qmp_v2_dp_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRANSCEIVER_BIAS_EN, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_VMODE_CTRL1, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_INTERFACE_SELECT, 0x3d), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_CLKBUF_ENABLE, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RESET_TSYNC_EN, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRAN_DRVR_EMP_EN, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_INTERFACE_MODE, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_EMP_POST1_LVL, 0x2b), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_DRV_LVL, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_BAND, 0x4), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_TX, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_RX, 0x12), +}; + struct qmp_usbc_offsets { u16 serdes; u16 pcs; @@ -434,6 +512,10 @@ static const char * const usb3phy_reset_l[] = { "phy_phy", "phy", }; +static const char * const usb3dpphy_reset_l[] = { + "phy_phy", "dp_phy", +}; + static const struct regulator_bulk_data qmp_phy_msm8998_vreg_l[] = { { .supply = "vdda-phy", .init_load_uA = 68600 }, { .supply = "vdda-pll", .init_load_uA = 14200 }, @@ -459,6 +541,34 @@ static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = { .rx2 = 0x800, }; +static const struct qmp_usbc_offsets qmp_usbc_usb3dp_offsets_qcs615 = { + .serdes = 0x0, + .pcs = 0xc00, + .pcs_misc = 0xa00, + .tx = 0x200, + .rx = 0x400, + .tx2 = 0x600, + .rx2 = 0x800, + .dp_serdes = 0x1c00, + .dp_txa = 0x1400, + .dp_txb = 0x1800, + .dp_dp_phy = 0x1000, +}; + +static const u8 qmp_v2_dp_pre_emphasis_hbr2_rbr[4][4] = { + {0x00, 0x0b, 0x12, 0xff}, + {0x00, 0x0a, 0x12, 0xff}, + {0x00, 0x0c, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff} +}; + +static const u8 qmp_v2_dp_voltage_swing_hbr2_rbr[4][4] = { + {0x07, 0x0f, 0x14, 0xff}, + {0x11, 0x1d, 0x1f, 0xff}, + {0x18, 0x1f, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff} +}; + static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { .offsets = &qmp_usbc_offsets_v3_qcm2290, @@ -531,6 +641,51 @@ static const struct qmp_phy_cfg qcs615_usb3phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; +static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp); +static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp); +static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp); +static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp); + +static const struct qmp_phy_cfg qcs615_usb3dp_phy_cfg = { + .offsets = &qmp_usbc_usb3dp_offsets_qcs615, + + .serdes_tbl = qcm2290_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), + .tx_tbl = qcm2290_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), + .rx_tbl = qcm2290_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), + .pcs_tbl = qcm2290_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + + .regs = qmp_v3_usb3phy_regs_layout_qcm2290, + + .dp_serdes_tbl = qmp_v2_dp_serdes_tbl, + .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl), + .dp_tx_tbl = qmp_v2_dp_tx_tbl, + .dp_tx_tbl_num = ARRAY_SIZE(qmp_v2_dp_tx_tbl), + + .serdes_tbl_rbr = qmp_v2_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qmp_v2_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qmp_v2_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr2), + + .swing_tbl = &qmp_v2_dp_voltage_swing_hbr2_rbr, + .pre_emphasis_tbl = &qmp_v2_dp_pre_emphasis_hbr2_rbr, + + .dp_aux_init = qmp_v2_dp_aux_init, + .configure_dp_tx = qmp_v2_configure_dp_tx, + .configure_dp_phy = qmp_v2_configure_dp_phy, + .calibrate_dp_phy = qmp_v2_calibrate_dp_phy, + + .reset_list = usb3dpphy_reset_l, + .num_resets = ARRAY_SIZE(usb3dpphy_reset_l), + .vreg_list = qmp_phy_qcs615_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l), +}; + static void qmp_usbc_set_phy_mode(struct qmp_usbc *qmp, bool is_dp) { if (qmp->tcsr_map && qmp->dp_phy_mode_reg) @@ -589,6 +744,253 @@ static int qmp_usbc_com_exit(struct phy *phy) return 0; } +static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp) +{ + writel(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, + qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + + 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, + qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + + writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0); + writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); + writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2); + writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG3); + writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG4); + writel(0x26, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG5); + writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG6); + writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7); + writel(0xbb, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8); + writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9); + qmp->dp_aux_cfg = 0; + + writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | + PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK | + PHY_AUX_REQ_ERR_MASK, + qmp->dp_dp_phy + QSERDES_V2_DP_PHY_AUX_INTERRUPT_MASK); +} + +static int qmp_v2_configure_dp_swing(struct qmp_usbc *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; + void __iomem *tx = qmp->dp_tx; + void __iomem *tx2 = qmp->dp_tx2; + unsigned int v_level = 0, p_level = 0; + u8 voltage_swing_cfg, pre_emphasis_cfg; + int i; + + if (dp_opts->lanes > 4) { + dev_err(qmp->dev, "Invalid lane_num(%d)\n", dp_opts->lanes); + return -EINVAL; + } + + for (i = 0; i < dp_opts->lanes; i++) { + v_level = max(v_level, dp_opts->voltage[i]); + p_level = max(p_level, dp_opts->pre[i]); + } + + if (v_level > 4 || p_level > 4) { + dev_err(qmp->dev, "Invalid v(%d) | p(%d) level)\n", + v_level, p_level); + return -EINVAL; + } + + voltage_swing_cfg = (*cfg->swing_tbl)[v_level][p_level]; + pre_emphasis_cfg = (*cfg->pre_emphasis_tbl)[v_level][p_level]; + + voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN; + pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN; + + if (voltage_swing_cfg == 0xff && pre_emphasis_cfg == 0xff) + return -EINVAL; + + writel(voltage_swing_cfg, tx + QSERDES_V2_TX_TX_DRV_LVL); + writel(pre_emphasis_cfg, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL); + writel(voltage_swing_cfg, tx2 + QSERDES_V2_TX_TX_DRV_LVL); + writel(pre_emphasis_cfg, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL); + + return 0; +} + +static void qmp_usbc_configure_dp_mode(struct qmp_usbc *qmp) +{ + bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE); + u32 val; + + val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | + DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN; + + writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + + if (reverse) + writel(0xc9, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE); + else + writel(0xd9, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE); +} + +static int qmp_usbc_configure_dp_clocks(struct qmp_usbc *qmp) +{ + const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; + u32 phy_vco_div; + unsigned long pixel_freq; + + switch (dp_opts->link_rate) { + case 1620: + phy_vco_div = 0x1; + pixel_freq = 1620000000UL / 2; + break; + case 2700: + phy_vco_div = 0x1; + pixel_freq = 2700000000UL / 2; + break; + case 5400: + phy_vco_div = 0x2; + pixel_freq = 5400000000UL / 4; + break; + default: + dev_err(qmp->dev, "link rate:%d not supported\n", dp_opts->link_rate); + return -EINVAL; + } + writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_VCO_DIV); + + clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000); + clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq); + + return 0; +} + +static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp) +{ + const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; + void __iomem *tx = qmp->dp_tx; + void __iomem *tx2 = qmp->dp_tx2; + + /* program default setting first */ + writel(0x2a, tx + QSERDES_V2_TX_TX_DRV_LVL); + writel(0x20, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL); + writel(0x2a, tx2 + QSERDES_V2_TX_TX_DRV_LVL); + writel(0x20, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL); + + if (dp_opts->link_rate >= 2700) { + writel(0xc4, tx + QSERDES_V2_TX_LANE_MODE_1); + writel(0xc4, tx2 + QSERDES_V2_TX_LANE_MODE_1); + } else { + writel(0xc6, tx + QSERDES_V2_TX_LANE_MODE_1); + writel(0xc6, tx2 + QSERDES_V2_TX_LANE_MODE_1); + } + + qmp_v2_configure_dp_swing(qmp); +} + +static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp) +{ + u32 status; + int ret; + + qmp_usbc_configure_dp_mode(qmp); + + writel(0x05, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_TX0_TX1_LANE_CTL); + writel(0x05, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_TX2_TX3_LANE_CTL); + + ret = qmp_usbc_configure_dp_clocks(qmp); + if (ret) + return ret; + + writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + writel(0x05, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + + writel(0x20, qmp->dp_serdes + QSERDES_COM_RESETSM_CNTRL); + + if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_C_READY_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)) { + dev_err(qmp->dev, "C_READY not ready\n"); + return -ETIMEDOUT; + } + + if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)){ + dev_err(qmp->dev, "FREQ_DONE not ready\n"); + return -ETIMEDOUT; + } + + if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)){ + dev_err(qmp->dev, "PLL_LOCKED not ready\n"); + return -ETIMEDOUT; + } + + writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + + if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)){ + dev_err(qmp->dev, "TSYNC_DONE not ready\n"); + return -ETIMEDOUT; + } + + if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)){ + dev_err(qmp->dev, "PHY_READY not ready\n"); + return -ETIMEDOUT; + } + + writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); + writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN); + writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV); + writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); + writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN); + writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV); + + writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); + + if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)){ + dev_err(qmp->dev, "PHY_READY not ready\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp) +{ + static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d}; + u8 val; + + qmp->dp_aux_cfg++; + qmp->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings); + val = cfg1_settings[qmp->dp_aux_cfg]; + + writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); + + return 0; +} + static int qmp_usbc_usb_power_on(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); @@ -855,6 +1257,14 @@ static int qmp_usbc_dp_power_on(struct phy *phy) void __iomem *tx = qmp->dp_tx; void __iomem *tx2 = qmp->dp_tx2; + /* + * FIXME: SW_PORTSELECT handling for DP orientation flip is not implemented. + * Expected: + * - For standard lane mapping: configure SW_PORTSELECT in QSERDES_DP_PHY_CFG_1. + * - For non-standard mapping: pass orientation to dp_ctrl and handle flip + * via logical2physical lane remapping. + */ + mutex_lock(&qmp->phy_mutex); qmp_usbc_dp_serdes_init(qmp); @@ -1601,6 +2011,9 @@ static const struct of_device_id qmp_usbc_of_match_table[] = { }, { .compatible = "qcom,qcm2290-qmp-usb3-phy", .data = &qcm2290_usb3phy_cfg, + }, { + .compatible = "qcom,qcs615-qmp-usb3-dp-phy", + .data = &qcs615_usb3dp_phy_cfg, }, { .compatible = "qcom,qcs615-qmp-usb3-phy", .data = &qcs615_usb3phy_cfg, From 4c17d093654f5137d3d2aec2822d103147ac7e2c Mon Sep 17 00:00:00 2001 From: Mani Chandana Ballary Kuntumalla Date: Tue, 23 Sep 2025 17:34:02 +0530 Subject: [PATCH 44/67] FROMLIST: drm/msm/dp: Update msm_dp_controller IDs for sa8775p The Qualcomm SA8775P platform comes with 2 DisplayPort controllers for each mdss. Update controller id for DPTX0 and DPTX1 of mdss1. Fixes: dcb380d19e58 ("drm/msm/dp: Add DisplayPort controller for SA8775P") Signed-off-by: Mani Chandana Ballary Kuntumalla Link: https://lore.kernel.org/all/20251125105622.1755651-2-quic_mkuntuma@quicinc.com/ --- drivers/gpu/drm/msm/dp/dp_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index d87d47cc7ec3e..f247aad553975 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -133,8 +133,8 @@ struct msm_dp_desc { 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 }, - { .io_start = 0x22154000, .id = MSM_DP_CONTROLLER_2, .wide_bus_supported = true }, - { .io_start = 0x2215c000, .id = MSM_DP_CONTROLLER_3, .wide_bus_supported = true }, + { .io_start = 0x22154000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, + { .io_start = 0x2215c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, {} }; From 7bdce3649fb43cd318c7ed46b75b97ecf681752d Mon Sep 17 00:00:00 2001 From: Yuanjie Yang Date: Thu, 23 Oct 2025 16:06:04 +0800 Subject: [PATCH 45/67] FROMLIST: drm/panel: Set sufficient voltage for panel nt37801 The NT37801 Sepc V1.0 chapter "5.7.1 Power On Sequence" states VDDI=1.65V~1.95V, so set sufficient voltage for panel nt37801. Signed-off-by: Yongxing Mou Signed-off-by: Yuanjie Yang Link: https://lore.kernel.org/all/20251023080609.1212-2-yuanjie.yang@oss.qualcomm.com/#r Signed-off-by: Yash Gupta --- drivers/gpu/drm/panel/panel-novatek-nt37801.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37801.c b/drivers/gpu/drm/panel/panel-novatek-nt37801.c index d6a37d7e0cc63..7eda16e0c1f94 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt37801.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt37801.c @@ -267,6 +267,11 @@ static int novatek_nt37801_probe(struct mipi_dsi_device *dsi) if (ret < 0) return ret; + ret = regulator_set_voltage(ctx->supplies[0].consumer, + 1650000, 1950000); + if (ret < 0) + return ret; + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), From 7d5c2fff943dca5780f15086eacff70356b723d8 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Fri, 24 Oct 2025 15:03:21 +0530 Subject: [PATCH 46/67] FROMLIST: dt-bindings: spmi: split out common QCOM SPMI PMIC arbiter properties Split out the common SPMI PMIC arbiter properties for QCOM devices into a separate file so that it can be included as a reference for devices using them. This will be needed for the upcoming PMIC v8 arbiter support patch, as the v8 arbiter also uses these common properties. Signed-off-by: Jishnu Prakash Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20251024-pmic_arb_v8-v3-1-cad8d6a2cbc0@oss.qualcomm.com Signed-off-by: Rakesh Kota --- .../spmi/qcom,spmi-pmic-arb-common.yaml | 35 +++++++++++++++++++ .../bindings/spmi/qcom,spmi-pmic-arb.yaml | 17 +-------- .../spmi/qcom,x1e80100-spmi-pmic-arb.yaml | 21 +++-------- 3 files changed, 40 insertions(+), 33 deletions(-) create mode 100644 Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-common.yaml diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-common.yaml b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-common.yaml new file mode 100644 index 0000000000000..8c38ed145e745 --- /dev/null +++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-common.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spmi/qcom,spmi-pmic-arb-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. SPMI Controller (common) + +maintainers: + - David Collins + +description: | + This defines some common properties used to define Qualcomm SPMI controllers + for PMIC arbiter. + +properties: + qcom,ee: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 5 + description: + indicates the active Execution Environment identifier + + qcom,channel: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 5 + description: + which of the PMIC Arb provided channels to use for accesses + +required: + - qcom,ee + - qcom,channel + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml index 51daf1b847a9b..d0c683dd52841 100644 --- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml +++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml @@ -19,6 +19,7 @@ description: | allOf: - $ref: spmi.yaml + - $ref: qcom,spmi-pmic-arb-common.yaml properties: compatible: @@ -71,20 +72,6 @@ properties: '#size-cells': true - qcom,ee: - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0 - maximum: 5 - description: > - indicates the active Execution Environment identifier - - qcom,channel: - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0 - maximum: 5 - description: > - which of the PMIC Arb provided channels to use for accesses - qcom,bus-id: $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 @@ -97,8 +84,6 @@ properties: required: - compatible - reg-names - - qcom,ee - - qcom,channel unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml b/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml index 7c3cc20a80d6c..08369fdd21612 100644 --- a/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml +++ b/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml @@ -17,6 +17,9 @@ description: | The PMIC Arbiter can also act as an interrupt controller, providing interrupts to slave devices. +allOf: + - $ref: qcom,spmi-pmic-arb-common.yaml + properties: compatible: oneOf: @@ -45,20 +48,6 @@ properties: '#size-cells': const: 2 - qcom,ee: - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0 - maximum: 5 - description: > - indicates the active Execution Environment identifier - - qcom,channel: - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0 - maximum: 5 - description: > - which of the PMIC Arb provided channels to use for accesses - patternProperties: "^spmi@[a-f0-9]+$": type: object @@ -96,10 +85,8 @@ patternProperties: required: - compatible - reg-names - - qcom,ee - - qcom,channel -additionalProperties: false +unevaluatedProperties: false examples: - | From d80f687e825421ba5c60d347524356ef95601be1 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Fri, 24 Oct 2025 15:03:22 +0530 Subject: [PATCH 47/67] FROMLIST: dt-bindings: spmi: add support for glymur-spmi-pmic-arb (arbiter v8) SPMI PMIC Arbiter version 8 builds upon version 7 with support for up to four SPMI buses. To achieve this, the register map was slightly rearranged. Add a new binding file and compatible string for version 8 using the name 'glymur' as the Qualcomm Technologies, Inc. Glymur SoC is the first one to use PMIC arbiter version 8. This specifies the new register ranges needed only for version 8. Also document SPMI PMIC Arbiter for Qualcomm Kaanapali SoC, by adding fallback to Glymur compatible string, as it too has version 8 functionality. Signed-off-by: David Collins Signed-off-by: Pankaj Patil Signed-off-by: Kamal Wadhwa Signed-off-by: Jingyi Wang Signed-off-by: Jishnu Prakash Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20251024-pmic_arb_v8-v3-2-cad8d6a2cbc0@oss.qualcomm.com Signed-off-by: Rakesh Kota --- .../spmi/qcom,glymur-spmi-pmic-arb.yaml | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml diff --git a/Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml b/Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml new file mode 100644 index 0000000000000..3b5005b96c6d5 --- /dev/null +++ b/Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml @@ -0,0 +1,150 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spmi/qcom,glymur-spmi-pmic-arb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. Glymur SPMI Controller (PMIC Arbiter v8) + +maintainers: + - David Collins + +description: | + The Glymur SPMI PMIC Arbiter implements HW version 8 and it's an SPMI + controller with wrapping arbitration logic to allow for multiple on-chip + devices to control up to 4 SPMI separate buses. + + The PMIC Arbiter can also act as an interrupt controller, providing interrupts + to slave devices. + +allOf: + - $ref: /schemas/spmi/qcom,spmi-pmic-arb-common.yaml + +properties: + compatible: + oneOf: + - items: + - enum: + - qcom,kaanapali-spmi-pmic-arb + - const: qcom,glymur-spmi-pmic-arb + - enum: + - qcom,glymur-spmi-pmic-arb + + reg: + items: + - description: core registers + - description: tx-channel per virtual slave registers + - description: rx-channel (called observer) per virtual slave registers + - description: channel to PMIC peripheral mapping registers + + reg-names: + items: + - const: core + - const: chnls + - const: obsrvr + - const: chnl_map + + ranges: true + + '#address-cells': + const: 2 + + '#size-cells': + const: 2 + +patternProperties: + "^spmi@[a-f0-9]+$": + type: object + $ref: /schemas/spmi/spmi.yaml + unevaluatedProperties: false + + properties: + reg: + items: + - description: configuration registers + - description: interrupt controller registers + - description: channel owner EE mapping registers + + reg-names: + items: + - const: cnfg + - const: intr + - const: chnl_owner + + interrupts: + maxItems: 1 + + interrupt-names: + const: periph_irq + + interrupt-controller: true + + '#interrupt-cells': + const: 4 + description: | + cell 1: slave ID for the requested interrupt (0-15) + cell 2: peripheral ID for requested interrupt (0-255) + cell 3: the requested peripheral interrupt (0-7) + cell 4: interrupt flags indicating level-sense information, + as defined in dt-bindings/interrupt-controller/irq.h + +required: + - compatible + - reg-names + +unevaluatedProperties: false + +examples: + - | + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + arbiter@c400000 { + compatible = "qcom,glymur-spmi-pmic-arb"; + reg = <0x0 0xc400000 0x0 0x3000>, + <0x0 0xc900000 0x0 0x400000>, + <0x0 0xc4c0000 0x0 0x400000>, + <0x0 0xc403000 0x0 0x8000>; + reg-names = "core", "chnls", "obsrvr", "chnl_map"; + + qcom,ee = <0>; + qcom,channel = <0>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + spmi@c426000 { + reg = <0x0 0xc426000 0x0 0x4000>, + <0x0 0xc8c0000 0x0 0x10000>, + <0x0 0xc42a000 0x0 0x8000>; + reg-names = "cnfg", "intr", "chnl_owner"; + + interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "periph_irq"; + interrupt-controller; + #interrupt-cells = <4>; + + #address-cells = <2>; + #size-cells = <0>; + }; + + spmi@c437000 { + reg = <0x0 0xc437000 0x0 0x4000>, + <0x0 0xc8d0000 0x0 0x10000>, + <0x0 0xc43b000 0x0 0x8000>; + reg-names = "cnfg", "intr", "chnl_owner"; + + interrupts-extended = <&pdc 3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "periph_irq"; + interrupt-controller; + #interrupt-cells = <4>; + + #address-cells = <2>; + #size-cells = <0>; + }; + }; + }; From 3a8993f9228948bc43a4794bd3df95a271bd59a5 Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 24 Oct 2025 15:03:23 +0530 Subject: [PATCH 48/67] FROMLIST: spmi: spmi-pmic-arb: add support for PMIC arbiter v8 PMIC arbiter v8 supports up to 4 SPMI buses and up to 8192 PMIC peripherals. Its register map differs from v7 as several fields increased in size. Add support for PMIC arbiter version 8. Signed-off-by: David Collins Signed-off-by: Kamal Wadhwa Signed-off-by: Jishnu Prakash Link: https://lore.kernel.org/r/20251024-pmic_arb_v8-v3-3-cad8d6a2cbc0@oss.qualcomm.com Signed-off-by: Rakesh Kota --- drivers/spmi/spmi-pmic-arb.c | 324 +++++++++++++++++++++++++++++++---- 1 file changed, 294 insertions(+), 30 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 91581974ef84e..612736973e4b0 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -3,6 +3,7 @@ * Copyright (c) 2012-2015, 2017, 2021, The Linux Foundation. All rights reserved. */ #include +#include #include #include #include @@ -25,10 +26,12 @@ #define PMIC_ARB_VERSION_V3_MIN 0x30000000 #define PMIC_ARB_VERSION_V5_MIN 0x50000000 #define PMIC_ARB_VERSION_V7_MIN 0x70000000 +#define PMIC_ARB_VERSION_V8_MIN 0x80000000 #define PMIC_ARB_INT_EN 0x0004 #define PMIC_ARB_FEATURES 0x0004 #define PMIC_ARB_FEATURES_PERIPH_MASK GENMASK(10, 0) +#define PMIC_ARB_FEATURES_V8_PERIPH_MASK GENMASK(12, 0) #define PMIC_ARB_FEATURES1 0x0008 @@ -50,9 +53,10 @@ #define SPMI_MAPPING_BIT_IS_1_RESULT(X) (((X) >> 0) & 0xFF) #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ -#define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ +#define PMIC_ARB_MAX_PPID BIT(13) #define PMIC_ARB_APID_VALID BIT(15) #define PMIC_ARB_CHAN_IS_IRQ_OWNER(reg) ((reg) & BIT(24)) +#define PMIC_ARB_V8_CHAN_IS_IRQ_OWNER(reg) ((reg) & BIT(31)) #define INVALID_EE 0xFF /* Ownership Table */ @@ -96,30 +100,33 @@ enum pmic_arb_channel { PMIC_ARB_CHANNEL_OBS, }; -#define PMIC_ARB_MAX_BUSES 2 +#define PMIC_ARB_MAX_BUSES 4 +#define PMIC_ARB_MAX_BUSES_V8 4 /* Maximum number of support PMIC peripherals */ #define PMIC_ARB_MAX_PERIPHS 512 #define PMIC_ARB_MAX_PERIPHS_V7 1024 +#define PMIC_ARB_MAX_PERIPHS_V8 8192 #define PMIC_ARB_TIMEOUT_US 1000 #define PMIC_ARB_MAX_TRANS_BYTES (8) #define PMIC_ARB_APID_MASK 0xFF #define PMIC_ARB_PPID_MASK 0xFFF +#define PMIC_ARB_V8_PPID_MASK 0x1FFF /* interrupt enable bit */ #define SPMI_PIC_ACC_ENABLE_BIT BIT(0) #define spec_to_hwirq(slave_id, periph_id, irq_id, apid) \ - ((((slave_id) & 0xF) << 28) | \ - (((periph_id) & 0xFF) << 20) | \ - (((irq_id) & 0x7) << 16) | \ - (((apid) & 0x3FF) << 0)) + (FIELD_PREP(GENMASK(28, 24), (slave_id)) | \ + FIELD_PREP(GENMASK(23, 16), (periph_id)) | \ + FIELD_PREP(GENMASK(15, 13), (irq_id)) | \ + FIELD_PREP(GENMASK(12, 0), (apid))) -#define hwirq_to_sid(hwirq) (((hwirq) >> 28) & 0xF) -#define hwirq_to_per(hwirq) (((hwirq) >> 20) & 0xFF) -#define hwirq_to_irq(hwirq) (((hwirq) >> 16) & 0x7) -#define hwirq_to_apid(hwirq) (((hwirq) >> 0) & 0x3FF) +#define hwirq_to_sid(hwirq) FIELD_GET(GENMASK(28, 24), (hwirq)) +#define hwirq_to_per(hwirq) FIELD_GET(GENMASK(23, 16), (hwirq)) +#define hwirq_to_irq(hwirq) FIELD_GET(GENMASK(15, 13), (hwirq)) +#define hwirq_to_apid(hwirq) FIELD_GET(GENMASK(12, 0), (hwirq)) struct pmic_arb_ver_ops; @@ -138,11 +145,12 @@ struct spmi_pmic_arb; * @domain: irq domain object for PMIC IRQ domain * @intr: address of the SPMI interrupt control registers. * @cnfg: address of the PMIC Arbiter configuration registers. + * @apid_owner: on v8: address of APID owner mapping table registers * @spmic: spmi controller registered for this bus * @lock: lock to synchronize accesses. - * @base_apid: on v7: minimum APID associated with the particular SPMI - * bus instance - * @apid_count: on v5 and v7: number of APIDs associated with the + * @base_apid: on v7 and v8: minimum APID associated with the + * particular SPMI bus instance + * @apid_count: on v5, v7 and v8: number of APIDs associated with the * particular SPMI bus instance * @mapping_table: in-memory copy of PPID -> APID mapping table. * @mapping_table_valid:bitmap containing valid-only periphs @@ -159,6 +167,7 @@ struct spmi_pmic_arb_bus { struct irq_domain *domain; void __iomem *intr; void __iomem *cnfg; + void __iomem *apid_owner; struct spmi_controller *spmic; raw_spinlock_t lock; u16 base_apid; @@ -181,6 +190,7 @@ struct spmi_pmic_arb_bus { * @wr_base: on v1 "core", on v2 "chnls" register base off DT. * @core: core register base for v2 and above only (see above) * @core_size: core register base size + * @apid_map: on v8, APID mapping table register base * @channel: execution environment channel to use for accesses. * @ee: the current Execution Environment * @ver_ops: version dependent operations. @@ -193,6 +203,7 @@ struct spmi_pmic_arb { void __iomem *wr_base; void __iomem *core; resource_size_t core_size; + void __iomem *apid_map; u8 channel; u8 ee; const struct pmic_arb_ver_ops *ver_ops; @@ -206,6 +217,7 @@ struct spmi_pmic_arb { * * @ver_str: version string. * @get_core_resources: initializes the core, observer and channels + * @get_bus_resources: requests per-SPMI bus register resources * @init_apid: finds the apid base and count * @ppid_to_apid: finds the apid for a given ppid. * @non_data_cmd: on v1 issues an spmi non-data command. @@ -227,6 +239,9 @@ struct spmi_pmic_arb { struct pmic_arb_ver_ops { const char *ver_str; int (*get_core_resources)(struct platform_device *pdev, void __iomem *core); + int (*get_bus_resources)(struct platform_device *pdev, + struct device_node *node, + struct spmi_pmic_arb_bus *bus); int (*init_apid)(struct spmi_pmic_arb_bus *bus, int index); int (*ppid_to_apid)(struct spmi_pmic_arb_bus *bus, u16 ppid); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ @@ -656,7 +671,7 @@ static int periph_interrupt(struct spmi_pmic_arb_bus *bus, u16 apid) unsigned int irq; u32 status, id; int handled = 0; - u8 sid = (bus->apid_data[apid].ppid >> 8) & 0xF; + u8 sid = (bus->apid_data[apid].ppid >> 8) & 0x1F; u8 per = bus->apid_data[apid].ppid & 0xFF; status = readl_relaxed(pmic_arb->ver_ops->irq_status(bus, apid)); @@ -686,7 +701,7 @@ static void pmic_arb_chained_irq(struct irq_desc *desc) int last = bus->max_apid; /* * acc_offset will be non-zero for the secondary SPMI bus instance on - * v7 controllers. + * v7 and v8 controllers. */ int acc_offset = bus->base_apid >> 5; u8 ee = pmic_arb->ee; @@ -913,7 +928,7 @@ static int qpnpint_irq_domain_translate(struct irq_domain *d, return -EINVAL; if (fwspec->param_count != 4) return -EINVAL; - if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7) + if (intspec[0] > 0x1F || intspec[1] > 0xFF || intspec[2] > 0x7) return -EINVAL; ppid = intspec[0] << 8 | intspec[1]; @@ -1160,6 +1175,24 @@ static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb_bus *bus, u16 ppid) return apid_valid & ~PMIC_ARB_APID_VALID; } +static void pmic_arb_dump_apid_map(struct spmi_pmic_arb_bus *bus) +{ + struct apid_data *apidd; + u16 apid, ppid; + + /* Dump the mapping table for debug purposes. */ + dev_dbg(&bus->spmic->dev, "PPID APID Write-EE IRQ-EE\n"); + for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) { + apid = bus->ppid_to_apid[ppid]; + if (apid & PMIC_ARB_APID_VALID) { + apid &= ~PMIC_ARB_APID_VALID; + apidd = &bus->apid_data[apid]; + dev_dbg(&bus->spmic->dev, "%#03X %3u %2u %2u\n", + ppid, apid, apidd->write_ee, apidd->irq_ee); + } + } +} + static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb_bus *bus) { struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; @@ -1222,17 +1255,7 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb_bus *bus) bus->last_apid = i; } - /* Dump the mapping table for debug purposes. */ - dev_dbg(&bus->spmic->dev, "PPID APID Write-EE IRQ-EE\n"); - for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) { - apid = bus->ppid_to_apid[ppid]; - if (apid & PMIC_ARB_APID_VALID) { - apid &= ~PMIC_ARB_APID_VALID; - apidd = &bus->apid_data[apid]; - dev_dbg(&bus->spmic->dev, "%#03X %3u %2u %2u\n", - ppid, apid, apidd->write_ee, apidd->irq_ee); - } - } + pmic_arb_dump_apid_map(bus); return 0; } @@ -1346,7 +1369,7 @@ static int pmic_arb_get_core_resources_v7(struct platform_device *pdev, } /* - * Only v7 supports 2 buses. Each bus will get a different apid count, read + * Arbiter v7 supports 2 buses. Each bus will get a different apid count, read * from different registers. */ static int pmic_arb_init_apid_v7(struct spmi_pmic_arb_bus *bus, int index) @@ -1424,6 +1447,185 @@ static int pmic_arb_offset_v7(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr, return offset; } +static int pmic_arb_get_core_resources_v8(struct platform_device *pdev, + void __iomem *core) +{ + struct spmi_pmic_arb *pmic_arb = platform_get_drvdata(pdev); + + pmic_arb->apid_map = devm_platform_ioremap_resource_byname(pdev, + "chnl_map"); + if (IS_ERR(pmic_arb->apid_map)) + return PTR_ERR(pmic_arb->apid_map); + + pmic_arb->core = core; + + pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS_V8; + + return pmic_arb_get_obsrvr_chnls_v2(pdev); +} + +static int pmic_arb_get_bus_resources_v8(struct platform_device *pdev, + struct device_node *node, + struct spmi_pmic_arb_bus *bus) +{ + int index; + + index = of_property_match_string(node, "reg-names", "chnl_owner"); + if (index < 0) { + dev_err(&pdev->dev, "chnl_owner reg region missing\n"); + return -EINVAL; + } + + bus->apid_owner = devm_of_iomap(&pdev->dev, node, index, NULL); + + return PTR_ERR_OR_ZERO(bus->apid_owner); +} + +static int pmic_arb_read_apid_map_v8(struct spmi_pmic_arb_bus *bus) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + struct apid_data *apidd; + struct apid_data *prev_apidd; + u16 i, apid, ppid, apid_max; + bool valid, is_irq_ee; + u32 regval, offset; + + /* + * In order to allow multiple EEs to write to a single PPID in arbiter + * version 8, there can be more than one APID mapped to each PPID. The + * owner field for each of these mappings specifies the EE which is + * allowed to write to the APID. The owner of the last (highest) APID + * which has the IRQ owner bit set for a given PPID will receive + * interrupts from the PPID. + * + * In arbiter version 8, the APID numbering space is divided between + * the SPMI buses according to this mapping: + * APID = 0 to N-1 --> bus 0 + * APID = N to N+M-1 --> bus 1 + * APID = N+M to N+M+P-1 --> bus 2 + * APID = N+M+P to N+M+P+Q-1 --> bus 3 + * where N = number of APIDs supported by bus 0 + * M = number of APIDs supported by bus 1 + * P = number of APIDs supported by bus 2 + * Q = number of APIDs supported by bus 3 + */ + apidd = &bus->apid_data[bus->base_apid]; + apid_max = bus->base_apid + bus->apid_count; + for (i = bus->base_apid; i < apid_max; i++, apidd++) { + offset = pmic_arb->ver_ops->apid_map_offset(i); + regval = readl_relaxed(pmic_arb->apid_map + offset); + if (!regval) + continue; + ppid = regval & PMIC_ARB_V8_PPID_MASK; + is_irq_ee = PMIC_ARB_V8_CHAN_IS_IRQ_OWNER(regval); + + regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(bus, i)); + apidd->write_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval); + + apidd->irq_ee = is_irq_ee ? apidd->write_ee : INVALID_EE; + + valid = bus->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID; + apid = bus->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID; + prev_apidd = &bus->apid_data[apid]; + + if (!valid || apidd->write_ee == pmic_arb->ee) { + /* First PPID mapping or one for this EE */ + bus->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID; + } else if (valid && is_irq_ee && + prev_apidd->write_ee == pmic_arb->ee) { + /* + * Duplicate PPID mapping after the one for this EE; + * override the irq owner + */ + prev_apidd->irq_ee = apidd->irq_ee; + } + + apidd->ppid = ppid; + bus->last_apid = i; + } + + pmic_arb_dump_apid_map(bus); + + return 0; +} + +static int pmic_arb_init_apid_v8(struct spmi_pmic_arb_bus *bus, int index) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + int ret, i; + + if (index < 0 || index >= PMIC_ARB_MAX_BUSES_V8) { + dev_err(&bus->spmic->dev, "Unsupported bus index %d detected\n", + index); + return -EINVAL; + } + + bus->base_apid = 0; + bus->apid_count = 0; + for (i = 0; i <= index; i++) { + bus->base_apid += bus->apid_count; + bus->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES + i * 4) & + PMIC_ARB_FEATURES_V8_PERIPH_MASK; + } + + if (bus->apid_count == 0) { + dev_err(&bus->spmic->dev, "Bus %d not implemented\n", index); + return -EINVAL; + } else if (bus->base_apid + bus->apid_count > pmic_arb->max_periphs) { + dev_err(&bus->spmic->dev, "Unsupported max APID %d detected\n", + bus->base_apid + bus->apid_count); + return -EINVAL; + } + + ret = pmic_arb_init_apid_min_max(bus); + if (ret) + return ret; + + ret = pmic_arb_read_apid_map_v8(bus); + if (ret) { + dev_err(&bus->spmic->dev, "could not read APID->PPID mapping table, rc= %d\n", + ret); + return ret; + } + + return 0; +} + +/* + * v8 offset per ee and per apid for observer channels and per apid for + * read/write channels. + */ +static int pmic_arb_offset_v8(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr, + enum pmic_arb_channel ch_type) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + u16 apid; + int rc; + u32 offset = 0; + u16 ppid = (sid << 8) | (addr >> 8); + + rc = pmic_arb->ver_ops->ppid_to_apid(bus, ppid); + if (rc < 0) + return rc; + + apid = rc; + switch (ch_type) { + case PMIC_ARB_CHANNEL_OBS: + offset = 0x40000 * pmic_arb->ee + 0x20 * apid; + break; + case PMIC_ARB_CHANNEL_RW: + if (bus->apid_data[apid].write_ee != pmic_arb->ee) { + dev_err(&bus->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n", + sid, addr); + return -EPERM; + } + offset = 0x200 * apid; + break; + } + + return offset; +} + static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc) { return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7); @@ -1490,6 +1692,14 @@ pmic_arb_acc_enable_v7(struct spmi_pmic_arb_bus *bus, u16 n) return pmic_arb->wr_base + 0x100 + 0x1000 * n; } +static void __iomem * +pmic_arb_acc_enable_v8(struct spmi_pmic_arb_bus *bus, u16 n) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + + return pmic_arb->wr_base + 0x100 + 0x200 * n; +} + static void __iomem * pmic_arb_irq_status_v1(struct spmi_pmic_arb_bus *bus, u16 n) { @@ -1516,6 +1726,14 @@ pmic_arb_irq_status_v7(struct spmi_pmic_arb_bus *bus, u16 n) return pmic_arb->wr_base + 0x104 + 0x1000 * n; } +static void __iomem * +pmic_arb_irq_status_v8(struct spmi_pmic_arb_bus *bus, u16 n) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + + return pmic_arb->wr_base + 0x104 + 0x200 * n; +} + static void __iomem * pmic_arb_irq_clear_v1(struct spmi_pmic_arb_bus *bus, u16 n) { @@ -1542,6 +1760,14 @@ pmic_arb_irq_clear_v7(struct spmi_pmic_arb_bus *bus, u16 n) return pmic_arb->wr_base + 0x108 + 0x1000 * n; } +static void __iomem * +pmic_arb_irq_clear_v8(struct spmi_pmic_arb_bus *bus, u16 n) +{ + struct spmi_pmic_arb *pmic_arb = bus->pmic_arb; + + return pmic_arb->wr_base + 0x108 + 0x200 * n; +} + static u32 pmic_arb_apid_map_offset_v2(u16 n) { return 0x800 + 0x4 * n; @@ -1557,6 +1783,12 @@ static u32 pmic_arb_apid_map_offset_v7(u16 n) return 0x2000 + 0x4 * n; } +static u32 pmic_arb_apid_map_offset_v8(u16 n) +{ + /* For v8, offset is from "chnl_map" base register, not "core". */ + return 0x4 * n; +} + static void __iomem * pmic_arb_apid_owner_v2(struct spmi_pmic_arb_bus *bus, u16 n) { @@ -1564,7 +1796,7 @@ pmic_arb_apid_owner_v2(struct spmi_pmic_arb_bus *bus, u16 n) } /* - * For arbiter version 7, APID ownership table registers have independent + * For arbiter version 7 and 8, APID ownership table registers have independent * numbering space for each SPMI bus instance, so each is indexed starting from * 0. */ @@ -1574,6 +1806,12 @@ pmic_arb_apid_owner_v7(struct spmi_pmic_arb_bus *bus, u16 n) return bus->cnfg + 0x4 * (n - bus->base_apid); } +static void __iomem * +pmic_arb_apid_owner_v8(struct spmi_pmic_arb_bus *bus, u16 n) +{ + return bus->apid_owner + 0x4 * (n - bus->base_apid); +} + static const struct pmic_arb_ver_ops pmic_arb_v1 = { .ver_str = "v1", .get_core_resources = pmic_arb_get_core_resources_v1, @@ -1654,6 +1892,23 @@ static const struct pmic_arb_ver_ops pmic_arb_v7 = { .apid_owner = pmic_arb_apid_owner_v7, }; +static const struct pmic_arb_ver_ops pmic_arb_v8 = { + .ver_str = "v8", + .get_core_resources = pmic_arb_get_core_resources_v8, + .get_bus_resources = pmic_arb_get_bus_resources_v8, + .init_apid = pmic_arb_init_apid_v8, + .ppid_to_apid = pmic_arb_ppid_to_apid_v5, + .non_data_cmd = pmic_arb_non_data_cmd_v2, + .offset = pmic_arb_offset_v8, + .fmt_cmd = pmic_arb_fmt_cmd_v2, + .owner_acc_status = pmic_arb_owner_acc_status_v7, + .acc_enable = pmic_arb_acc_enable_v8, + .irq_status = pmic_arb_irq_status_v8, + .irq_clear = pmic_arb_irq_clear_v8, + .apid_map_offset = pmic_arb_apid_map_offset_v8, + .apid_owner = pmic_arb_apid_owner_v8, +}; + static const struct irq_domain_ops pmic_arb_irq_domain_ops = { .activate = qpnpint_irq_domain_activate, .alloc = qpnpint_irq_domain_alloc, @@ -1731,6 +1986,12 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev, bus->spmic = ctrl; bus->id = bus_index; + if (pmic_arb->ver_ops->get_bus_resources) { + ret = pmic_arb->ver_ops->get_bus_resources(pdev, node, bus); + if (ret) + return ret; + } + ret = pmic_arb->ver_ops->init_apid(bus, bus_index); if (ret) return ret; @@ -1825,8 +2086,10 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) pmic_arb->ver_ops = &pmic_arb_v3; else if (hw_ver < PMIC_ARB_VERSION_V7_MIN) pmic_arb->ver_ops = &pmic_arb_v5; - else + else if (hw_ver < PMIC_ARB_VERSION_V8_MIN) pmic_arb->ver_ops = &pmic_arb_v7; + else + pmic_arb->ver_ops = &pmic_arb_v8; err = pmic_arb->ver_ops->get_core_resources(pdev, core); if (err) @@ -1875,6 +2138,7 @@ static void spmi_pmic_arb_remove(struct platform_device *pdev) static const struct of_device_id spmi_pmic_arb_match_table[] = { { .compatible = "qcom,spmi-pmic-arb", }, { .compatible = "qcom,x1e80100-spmi-pmic-arb", }, + { .compatible = "qcom,glymur-spmi-pmic-arb", }, {}, }; MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table); From 7dbd4e5e840579346c901e297d8030b7ae559976 Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Mon, 27 Oct 2025 14:22:49 -0700 Subject: [PATCH 49/67] FROMLIST: dt-bindings: soc: qcom: qcom,pmic-glink: Add Kaanapali and Glymur compatibles Document the Kaanapali and Glymur compatibles used to describe the PMIC glink on each platform. Kaanapali will have the same battery supply properties as sm8550 platforms so define qcom,sm8550-pmic-glink as fallback for Kaanapali. Glymur will have the same battery supply properties as x1e80100 platforms so define qcom,x1e80100-pmic-glink as fallback for Glymur. Signed-off-by: Anjelique Melendez Link: https://lore.kernel.org/r/20251027212250.3847537-2-anjelique.melendez@oss.qualcomm.com Signed-off-by: Rakesh Kota --- .../devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml index 7085bf88afaba..c570221094197 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml @@ -37,12 +37,19 @@ properties: - const: qcom,pmic-glink - items: - enum: + - qcom,kaanapali-pmic-glink - qcom,milos-pmic-glink - qcom,sm8650-pmic-glink - qcom,sm8750-pmic-glink - qcom,x1e80100-pmic-glink - const: qcom,sm8550-pmic-glink - const: qcom,pmic-glink + - items: + - enum: + - qcom,glymur-pmic-glink + - const: qcom,x1e80100-pmic-glink + - const: qcom,sm8550-pmic-glink + - const: qcom,pmic-glink '#address-cells': const: 1 From 3abaeb4acc31968457ef89caae98986d37ac9049 Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Mon, 27 Oct 2025 14:22:50 -0700 Subject: [PATCH 50/67] FROMLIST: soc: qcom: pmic_glink: Add charger PDR service path and service name to client data Currently, the charger PD service path and service name are hard coded however these paths are not guaranteed to be the same between PMICs. For example, on Kaanapali and Glymur, Charger FW runs on SOCCP(another subsystem) which does not have any specific charger PDs defined. Define charger PDR service path and service name as client data so that each PMIC generation can properly define these paths. While at it, add the qcom,kaanapali-pmic-glink and qcom,glymur-pmic-glink compatible strings. Signed-off-by: Anjelique Melendez Link: https://lore.kernel.org/r/20251027212250.3847537-3-anjelique.melendez@oss.qualcomm.com Signed-off-by: Rakesh Kota --- drivers/soc/qcom/pmic_glink.c | 66 ++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index c0a4be5df9267..aa5ba9a0285e5 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -23,13 +23,19 @@ enum { PMIC_GLINK_CLIENT_UCSI, }; +struct pmic_glink_data { + unsigned long client_mask; + char *charger_pdr_service_name; + char *charger_pdr_service_path; +}; + struct pmic_glink { struct device *dev; struct pdr_handle *pdr; struct rpmsg_endpoint *ept; - unsigned long client_mask; + const struct pmic_glink_data *data; struct auxiliary_device altmode_aux; struct auxiliary_device ps_aux; @@ -285,7 +291,6 @@ static struct rpmsg_driver pmic_glink_rpmsg_driver = { static int pmic_glink_probe(struct platform_device *pdev) { - const unsigned long *match_data; struct pdr_service *service; struct pmic_glink *pg; int ret; @@ -302,12 +307,10 @@ static int pmic_glink_probe(struct platform_device *pdev) spin_lock_init(&pg->client_lock); mutex_init(&pg->state_lock); - match_data = (unsigned long *)of_device_get_match_data(&pdev->dev); - if (!match_data) + pg->data = of_device_get_match_data(&pdev->dev); + if (!pg->data) return -EINVAL; - pg->client_mask = *match_data; - pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg); if (IS_ERR(pg->pdr)) { ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr), @@ -315,27 +318,30 @@ static int pmic_glink_probe(struct platform_device *pdev) return ret; } - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) { + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) { ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi"); if (ret) goto out_release_pdr_handle; } - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) { + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) { ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode"); if (ret) goto out_release_ucsi_aux; } - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) { + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) { ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply"); if (ret) goto out_release_altmode_aux; } - service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd"); - if (IS_ERR(service)) { - ret = dev_err_probe(&pdev->dev, PTR_ERR(service), - "failed adding pdr lookup for charger_pd\n"); - goto out_release_aux_devices; + if (pg->data->charger_pdr_service_name && pg->data->charger_pdr_service_path) { + service = pdr_add_lookup(pg->pdr, pg->data->charger_pdr_service_name, + pg->data->charger_pdr_service_path); + if (IS_ERR(service)) { + ret = dev_err_probe(&pdev->dev, PTR_ERR(service), + "failed adding pdr lookup for charger_pd\n"); + goto out_release_aux_devices; + } } mutex_lock(&__pmic_glink_lock); @@ -345,13 +351,13 @@ static int pmic_glink_probe(struct platform_device *pdev) return 0; out_release_aux_devices: - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) pmic_glink_del_aux_device(pg, &pg->ps_aux); out_release_altmode_aux: - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) pmic_glink_del_aux_device(pg, &pg->altmode_aux); out_release_ucsi_aux: - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) pmic_glink_del_aux_device(pg, &pg->ucsi_aux); out_release_pdr_handle: pdr_handle_release(pg->pdr); @@ -365,23 +371,35 @@ static void pmic_glink_remove(struct platform_device *pdev) pdr_handle_release(pg->pdr); - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) pmic_glink_del_aux_device(pg, &pg->ps_aux); - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) pmic_glink_del_aux_device(pg, &pg->altmode_aux); - if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) + if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) pmic_glink_del_aux_device(pg, &pg->ucsi_aux); guard(mutex)(&__pmic_glink_lock); __pmic_glink = NULL; } -static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | - BIT(PMIC_GLINK_CLIENT_ALTMODE) | - BIT(PMIC_GLINK_CLIENT_UCSI); +static const struct pmic_glink_data pmic_glink_sm8450_data = { + .client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | + BIT(PMIC_GLINK_CLIENT_ALTMODE) | + BIT(PMIC_GLINK_CLIENT_UCSI), + .charger_pdr_service_name = "tms/servreg", + .charger_pdr_service_path = "msm/adsp/charger_pd", +}; + +static const struct pmic_glink_data pmic_glink_kaanapali_data = { + .client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | + BIT(PMIC_GLINK_CLIENT_ALTMODE) | + BIT(PMIC_GLINK_CLIENT_UCSI), +}; static const struct of_device_id pmic_glink_of_match[] = { - { .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_client_mask }, + { .compatible = "qcom,glymur-pmic-glink", .data = &pmic_glink_kaanapali_data }, + { .compatible = "qcom,kaanapali-pmic-glink", .data = &pmic_glink_kaanapali_data }, + { .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_data }, {} }; MODULE_DEVICE_TABLE(of, pmic_glink_of_match); From b11fd98cf3f310414e7be7fe59b16a0bbb8b654a Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Tue, 18 Nov 2025 10:07:09 +0530 Subject: [PATCH 51/67] FROMLIST: drm/bridge: add support for lontium lt8713sx bridge driver The lt8713sx is a Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0 converter, with three configurable DP1.4/HDMI2.0/DP++ output interfaces and audio output interface. Driver is required for firmware upgrade in the bridge chip. Co-developed-by: Prahlad Valluru Signed-off-by: Prahlad Valluru Signed-off-by: Vishnu Saini Link: https://lore.kernel.org/all/20251118-lt8713sx-bridge-driver-v2-2-25ad49280a11@oss.qualcomm.com/ --- drivers/gpu/drm/bridge/Kconfig | 10 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/lontium-lt8713sx.c | 713 ++++++++++++++++++++++ 3 files changed, 724 insertions(+) create mode 100644 drivers/gpu/drm/bridge/lontium-lt8713sx.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index a250afd8d6622..7fef383ed7cb7 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -184,6 +184,16 @@ config DRM_LONTIUM_LT9611UXC HDMI signals Please say Y if you have such hardware. +config DRM_LONTIUM_LT8713SX + tristate "Lontium LT8713SX DP MST bridge" + depends on OF + select REGMAP_I2C + help + Driver for Lontium LT8713SX DP MST bridge + chip firmware upgrade, which converts Type-C/DP1.4 + to 3 configurable Type-C/DP1.4/HDMI2.0 outputs + Please say Y if you have such hardware. + config DRM_ITE_IT66121 tristate "ITE IT66121 HDMI bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index c7dc03182e592..07eeb13fa4978 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o +obj-$(CONFIG_DRM_LONTIUM_LT8713SX) += lontium-lt8713sx.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o obj-$(CONFIG_DRM_MICROCHIP_LVDS_SERIALIZER) += microchip-lvds.o diff --git a/drivers/gpu/drm/bridge/lontium-lt8713sx.c b/drivers/gpu/drm/bridge/lontium-lt8713sx.c new file mode 100644 index 0000000000000..a5aed2474a2e9 --- /dev/null +++ b/drivers/gpu/drm/bridge/lontium-lt8713sx.c @@ -0,0 +1,713 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FW_FILE "lt8713sx_fw.bin" + +#define LT8713SX_PAGE_SIZE 256 +#define FW_12K_SIZE (12 * 1024) +#define FW_64K_SIZE (64 * 1024) +#define FW_256K_SIZE (256 * 1024) + +struct crc_config { + u8 width; + u32 poly; + u32 crc_init; + u32 xor_out; + bool ref_in; + bool ref_out; +}; + +struct lt8713sx { + struct device *dev; + + struct regmap *regmap; + /* Protects all accesses to registers by stopping the on-chip MCU */ + struct mutex ocm_lock; + + struct gpio_desc *reset_gpio; + struct gpio_desc *enable_gpio; + + struct regulator_bulk_data supplies[2]; + + struct i2c_client *client; + const struct firmware *fw; + + u8 *fw_buffer; + + u32 main_crc_value; + u32 bank_crc_value[17]; + + int bank_num; +}; + +static void lt8713sx_reset(struct lt8713sx *lt8713sx); + +static const struct regmap_range lt8713sx_ranges[] = { + { + .range_min = 0, + .range_max = 0xffff + }, +}; + +static const struct regmap_access_table lt8713sx_table = { + .yes_ranges = lt8713sx_ranges, + .n_yes_ranges = ARRAY_SIZE(lt8713sx_ranges), +}; + +static const struct regmap_config lt8713sx_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = <8713sx_table, + .cache_type = REGCACHE_NONE, +}; + +static void lt8713sx_i2c_enable(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0xee, 0x01); +} + +static void lt8713sx_i2c_disable(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0xee, 0x00); +} + +static unsigned int bits_reverse(u32 in_val, u8 bits) +{ + u32 out_val = 0; + u8 i; + + for (i = 0; i < bits; i++) { + if (in_val & (1 << i)) + out_val |= 1 << (bits - 1 - i); + } + + return out_val; +} + +static unsigned int get_crc(struct crc_config crc_cfg, const u8 *buf, u64 buf_len) +{ + u8 width = crc_cfg.width; + u32 poly = crc_cfg.poly; + u32 crc = crc_cfg.crc_init; + u32 xorout = crc_cfg.xor_out; + bool refin = crc_cfg.ref_in; + bool refout = crc_cfg.ref_out; + u8 n; + u32 bits; + u32 data; + u8 i; + + n = (width < 8) ? 0 : (width - 8); + crc = (width < 8) ? (crc << (8 - width)) : crc; + bits = (width < 8) ? 0x80 : (1 << (width - 1)); + poly = (width < 8) ? (poly << (8 - width)) : poly; + + while (buf_len--) { + data = *(buf++); + if (refin) + data = bits_reverse(data, 8); + crc ^= (data << n); + for (i = 0; i < 8; i++) { + if (crc & bits) + crc = (crc << 1) ^ poly; + else + crc = crc << 1; + } + } + crc = (width < 8) ? (crc >> (8 - width)) : crc; + if (refout) + crc = bits_reverse(crc, width); + crc ^= xorout; + + return (crc & ((2 << (width - 1)) - 1)); +} + +static u32 calculate_64K_crc(const u8 *upgrade_data, u64 len) +{ + struct crc_config crc_cfg = { + .width = 8, + .poly = 0x31, + .crc_init = 0, + .xor_out = 0, + .ref_out = false, + .ref_in = false, + }; + u64 crc_size = FW_64K_SIZE - 1; + u8 default_val = 0xFF; + + crc_cfg.crc_init = get_crc(crc_cfg, upgrade_data, len); + + crc_size -= len; + while (crc_size--) + crc_cfg.crc_init = get_crc(crc_cfg, &default_val, 1); + + return crc_cfg.crc_init; +} + +static u32 calculate_12K_crc(const u8 *upgrade_data, u64 len) +{ + struct crc_config crc_cfg = { + .width = 8, + .poly = 0x31, + .crc_init = 0, + .xor_out = 0, + .ref_out = false, + .ref_in = false, + }; + u64 crc_size = FW_12K_SIZE; + u8 default_val = 0xFF; + + crc_cfg.crc_init = get_crc(crc_cfg, upgrade_data, len); + + crc_size -= len; + while (crc_size--) + crc_cfg.crc_init = get_crc(crc_cfg, &default_val, 1); + + return crc_cfg.crc_init; +} + +static int lt8713sx_prepare_firmware_data(struct lt8713sx *lt8713sx) +{ + int ret = 0; + + ret = request_firmware(<8713sx->fw, FW_FILE, lt8713sx->dev); + if (ret < 0) { + pr_err("request firmware failed\n"); + return ret; + } + + pr_debug("Firmware size: %zu bytes\n", lt8713sx->fw->size); + + if (lt8713sx->fw->size > FW_256K_SIZE - 1) { + pr_err("Firmware size exceeds 256KB limit\n"); + release_firmware(lt8713sx->fw); + return -EINVAL; + } + + lt8713sx->fw_buffer = kzalloc(FW_256K_SIZE, GFP_KERNEL); + if (!lt8713sx->fw_buffer) { + release_firmware(lt8713sx->fw); + return -ENOMEM; + } + + memset(lt8713sx->fw_buffer, 0xFF, FW_256K_SIZE); + + if (lt8713sx->fw->size < FW_64K_SIZE) { + /*TODO: CRC should be calculated with 0xff also */ + memcpy(lt8713sx->fw_buffer, lt8713sx->fw->data, lt8713sx->fw->size); + lt8713sx->fw_buffer[FW_64K_SIZE - 1] = + calculate_64K_crc(lt8713sx->fw->data, lt8713sx->fw->size); + lt8713sx->main_crc_value = lt8713sx->fw_buffer[FW_64K_SIZE - 1]; + pr_debug("Main Firmware Data Crc=0x%02X\n", lt8713sx->main_crc_value); + + } else { + //main firmware + memcpy(lt8713sx->fw_buffer, lt8713sx->fw->data, FW_64K_SIZE - 1); + lt8713sx->fw_buffer[FW_64K_SIZE - 1] = + calculate_64K_crc(lt8713sx->fw_buffer, FW_64K_SIZE - 1); + lt8713sx->main_crc_value = lt8713sx->fw_buffer[FW_64K_SIZE - 1]; + pr_debug("Main Firmware Data Crc=0x%02X\n", lt8713sx->main_crc_value); + + //bank firmware + memcpy(lt8713sx->fw_buffer + FW_64K_SIZE, + lt8713sx->fw->data + FW_64K_SIZE, + lt8713sx->fw->size - FW_64K_SIZE); + + lt8713sx->bank_num = (lt8713sx->fw->size - FW_64K_SIZE + FW_12K_SIZE - 1) / + FW_12K_SIZE; + pr_debug("Bank Number Total is %d.\n", lt8713sx->bank_num); + + for (int i = 0; i < lt8713sx->bank_num; i++) { + lt8713sx->bank_crc_value[i] = + calculate_12K_crc(lt8713sx->fw_buffer + FW_64K_SIZE + + i * FW_12K_SIZE, + FW_12K_SIZE); + pr_debug("Bank number:%d; Firmware Data Crc:0x%02X\n", + i, lt8713sx->bank_crc_value[i]); + } + } + return 0; +} + +static void lt8713sx_config_parameters(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xFF, 0xE0); + regmap_write(lt8713sx->regmap, 0xEE, 0x01); + regmap_write(lt8713sx->regmap, 0x5E, 0xC1); + regmap_write(lt8713sx->regmap, 0x58, 0x00); + regmap_write(lt8713sx->regmap, 0x59, 0x50); + regmap_write(lt8713sx->regmap, 0x5A, 0x10); + regmap_write(lt8713sx->regmap, 0x5A, 0x00); + regmap_write(lt8713sx->regmap, 0x58, 0x21); +} + +static void lt8713sx_wren(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe1); + regmap_write(lt8713sx->regmap, 0x03, 0xbf); + regmap_write(lt8713sx->regmap, 0x03, 0xff); + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0x5a, 0x04); + regmap_write(lt8713sx->regmap, 0x5a, 0x00); +} + +static void lt8713sx_wrdi(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0x5A, 0x08); + regmap_write(lt8713sx->regmap, 0x5A, 0x00); +} + +static void lt8713sx_fifo_reset(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe1); + regmap_write(lt8713sx->regmap, 0x03, 0xbf); + regmap_write(lt8713sx->regmap, 0x03, 0xff); +} + +static void lt8713sx_disable_sram_write(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0x55, 0x00); +} + +static void lt8713sx_sram_to_flash(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0x5a, 0x30); + regmap_write(lt8713sx->regmap, 0x5a, 0x00); +} + +static void lt8713sx_i2c_to_sram(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0x55, 0x80); + regmap_write(lt8713sx->regmap, 0x5e, 0xc0); + regmap_write(lt8713sx->regmap, 0x58, 0x21); +} + +static u8 lt8713sx_read_flash_status(struct lt8713sx *lt8713sx) +{ + u32 flash_status = 0; + + regmap_write(lt8713sx->regmap, 0xFF, 0xE1);//fifo_rst_n + regmap_write(lt8713sx->regmap, 0x03, 0x3F); + regmap_write(lt8713sx->regmap, 0x03, 0xFF); + + regmap_write(lt8713sx->regmap, 0xFF, 0xE0); + regmap_write(lt8713sx->regmap, 0x5e, 0x40); + regmap_write(lt8713sx->regmap, 0x56, 0x05);//opcode=read status register + regmap_write(lt8713sx->regmap, 0x55, 0x25); + regmap_write(lt8713sx->regmap, 0x55, 0x01); + regmap_write(lt8713sx->regmap, 0x58, 0x21); + + regmap_read(lt8713sx->regmap, 0x5f, &flash_status); + pr_debug("flash_status:%x\n", flash_status); + + return flash_status; +} + +static void lt8713sx_block_erase(struct lt8713sx *lt8713sx) +{ + u32 i = 0; + u8 flash_status = 0; + u8 blocknum = 0x00; + u32 flashaddr = 0x00; + + for (blocknum = 0; blocknum < 8; blocknum++) { + flashaddr = blocknum * 0x008000; + regmap_write(lt8713sx->regmap, 0xFF, 0xE0); + regmap_write(lt8713sx->regmap, 0xEE, 0x01); + regmap_write(lt8713sx->regmap, 0x5A, 0x04); + regmap_write(lt8713sx->regmap, 0x5A, 0x00); + regmap_write(lt8713sx->regmap, 0x5B, flashaddr >> 16);//set flash address[23:16] + regmap_write(lt8713sx->regmap, 0x5C, flashaddr >> 8);//set flash address[15:8] + regmap_write(lt8713sx->regmap, 0x5D, flashaddr);//set flash address[7:0] + regmap_write(lt8713sx->regmap, 0x5A, 0x01); + regmap_write(lt8713sx->regmap, 0x5A, 0x00); + msleep(100); //delay 100ms + i = 0; + while (1) { + flash_status = lt8713sx_read_flash_status(lt8713sx); //wait erase finish + if ((flash_status & 0x01) == 0) + break; + + if (i > 50) + break; + + i++; + msleep(50); //delay 50ms + } + } + pr_debug("erase flash done.\n"); +} + +static void lt8713sx_load_main_fw_to_sram(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0xee, 0x01); + regmap_write(lt8713sx->regmap, 0x68, 0x00); + regmap_write(lt8713sx->regmap, 0x69, 0x00); + regmap_write(lt8713sx->regmap, 0x6a, 0x00); + regmap_write(lt8713sx->regmap, 0x65, 0x00); + regmap_write(lt8713sx->regmap, 0x66, 0xff); + regmap_write(lt8713sx->regmap, 0x67, 0xff); + regmap_write(lt8713sx->regmap, 0x6b, 0x00); + regmap_write(lt8713sx->regmap, 0x6c, 0x00); + regmap_write(lt8713sx->regmap, 0x60, 0x01); + msleep(200); + regmap_write(lt8713sx->regmap, 0x60, 0x00); +} + +static void lt8713sx_load_bank_fw_to_sram(struct lt8713sx *lt8713sx, u64 addr) +{ + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_write(lt8713sx->regmap, 0xee, 0x01); + regmap_write(lt8713sx->regmap, 0x68, ((addr & 0xFF0000) >> 16)); + regmap_write(lt8713sx->regmap, 0x69, ((addr & 0x00FF00) >> 8)); + regmap_write(lt8713sx->regmap, 0x6a, (addr & 0x0000FF)); + regmap_write(lt8713sx->regmap, 0x65, 0x00); + regmap_write(lt8713sx->regmap, 0x66, 0x30); + regmap_write(lt8713sx->regmap, 0x67, 0x00); + regmap_write(lt8713sx->regmap, 0x6b, 0x00); + regmap_write(lt8713sx->regmap, 0x6c, 0x00); + regmap_write(lt8713sx->regmap, 0x60, 0x01); + msleep(50); + regmap_write(lt8713sx->regmap, 0x60, 0x00); +} + +static int lt8713sx_write_data(struct lt8713sx *lt8713sx, const u8 *data, u64 filesize) +{ + int page = 0, num = 0, i = 0, val; + + page = (filesize % LT8713SX_PAGE_SIZE) ? + ((filesize / LT8713SX_PAGE_SIZE) + 1) : (filesize / LT8713SX_PAGE_SIZE); + + pr_debug("Writing to Sram=%u pages, total size = %llu bytes\n", page, filesize); + + for (num = 0; num < page; num++) { + pr_debug("page[%d]\n", num); + lt8713sx_i2c_to_sram(lt8713sx); + + for (i = 0; i < LT8713SX_PAGE_SIZE; i++) { + if ((num * LT8713SX_PAGE_SIZE + i) < filesize) + val = *(data + (num * LT8713SX_PAGE_SIZE + i)); + else + val = 0xFF; + regmap_write(lt8713sx->regmap, 0x59, val); + } + + lt8713sx_wren(lt8713sx); + lt8713sx_sram_to_flash(lt8713sx); + } + + lt8713sx_wrdi(lt8713sx); + lt8713sx_disable_sram_write(lt8713sx); + + return 0; +} + +static void lt8713sx_main_upgrade_result(struct lt8713sx *lt8713sx) +{ + u32 main_crc_result; + + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + regmap_read(lt8713sx->regmap, 0x23, &main_crc_result); + + pr_debug("Main CRC HW: 0x%02X\n", main_crc_result); + pr_debug("Main CRC FW: 0x%02X\n", lt8713sx->main_crc_value); + + if (main_crc_result == lt8713sx->main_crc_value) + pr_debug("Main Firmware Upgrade Success.\n"); + else + pr_err("Main Firmware Upgrade Failed.\n"); +} + +static void lt8713sx_bank_upgrade_result(struct lt8713sx *lt8713sx, u8 banknum) +{ + u32 bank_crc_result; + + regmap_write(lt8713sx->regmap, 0xff, 0xe0); + + regmap_read(lt8713sx->regmap, 0x23, &bank_crc_result); + + pr_debug("Bank %d CRC Result: 0x%02X\n", banknum, bank_crc_result); + + if (bank_crc_result == lt8713sx->bank_crc_value[banknum]) + pr_debug("Bank %d Firmware Upgrade Success.\n", banknum); + else + pr_err("Bank %d Firmware Upgrade Failed.\n", banknum); +} + +static void lt8713sx_bank_result_check(struct lt8713sx *lt8713sx) +{ + int i; + u64 addr = 0x010000; + + for (i = 0; i < lt8713sx->bank_num; i++) { + lt8713sx_load_bank_fw_to_sram(lt8713sx, addr); + lt8713sx_bank_upgrade_result(lt8713sx, i); + addr += 0x3000; + } +} + +static int lt8713sx_firmware_upgrade(struct lt8713sx *lt8713sx) +{ + int ret; + + lt8713sx_config_parameters(lt8713sx); + + lt8713sx_block_erase(lt8713sx); + + if (lt8713sx->fw->size < FW_64K_SIZE) { + ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, FW_64K_SIZE); + if (ret < 0) { + pr_err("Failed to write firmware data: %d\n", ret); + return ret; + } + } else { + ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, lt8713sx->fw->size); + if (ret < 0) { + pr_err("Failed to write firmware data: %d\n", ret); + return ret; + } + } + + pr_debug("Write Data done.\n"); + + return 0; +} + +static int lt8713sx_firmware_update(struct lt8713sx *lt8713sx) +{ + int ret = 0; + + mutex_lock(<8713sx->ocm_lock); + lt8713sx_i2c_enable(lt8713sx); + + ret = lt8713sx_prepare_firmware_data(lt8713sx); + if (ret < 0) { + pr_err("Failed to prepare firmware data: %d\n", ret); + goto error; + } + + ret = lt8713sx_firmware_upgrade(lt8713sx); + if (ret < 0) { + pr_err("Upgrade failure.\n"); + goto error; + } else { + /* Validate CRC */ + lt8713sx_load_main_fw_to_sram(lt8713sx); + lt8713sx_main_upgrade_result(lt8713sx); + lt8713sx_wrdi(lt8713sx); + lt8713sx_fifo_reset(lt8713sx); + lt8713sx_bank_result_check(lt8713sx); + lt8713sx_wrdi(lt8713sx); + } + +error: + lt8713sx_i2c_disable(lt8713sx); + if (!ret) + lt8713sx_reset(lt8713sx); + + kfree(lt8713sx->fw_buffer); + lt8713sx->fw_buffer = NULL; + + if (lt8713sx->fw) { + release_firmware(lt8713sx->fw); + lt8713sx->fw = NULL; + } + mutex_unlock(<8713sx->ocm_lock); + + return ret; +} + +static void lt8713sx_reset(struct lt8713sx *lt8713sx) +{ + pr_debug("reset bridge.\n"); + gpiod_set_value_cansleep(lt8713sx->reset_gpio, 1); + msleep(20); + + gpiod_set_value_cansleep(lt8713sx->reset_gpio, 0); + msleep(20); + + gpiod_set_value_cansleep(lt8713sx->reset_gpio, 1); + msleep(20); + pr_debug("reset done.\n"); +} + +static int lt8713sx_regulator_init(struct lt8713sx *lt8713sx) +{ + int ret; + + lt8713sx->supplies[0].supply = "vdd"; + lt8713sx->supplies[1].supply = "vcc"; + + ret = devm_regulator_bulk_get(lt8713sx->dev, 2, lt8713sx->supplies); + if (ret < 0) + return dev_err_probe(lt8713sx->dev, ret, "failed to get regulators\n"); + + ret = regulator_set_load(lt8713sx->supplies[0].consumer, 200000); + if (ret < 0) + return dev_err_probe(lt8713sx->dev, ret, "failed to set regulator load\n"); + + return 0; +} + +static int lt8713sx_regulator_enable(struct lt8713sx *lt8713sx) +{ + int ret; + + ret = regulator_enable(lt8713sx->supplies[0].consumer); + if (ret < 0) + return dev_err_probe(lt8713sx->dev, ret, "failed to enable vdd regulator\n"); + + usleep_range(1000, 10000); + + ret = regulator_enable(lt8713sx->supplies[1].consumer); + if (ret < 0) { + regulator_disable(lt8713sx->supplies[0].consumer); + return dev_err_probe(lt8713sx->dev, ret, "failed to enable vcc regulator\n"); + } + return 0; +} + +static int lt8713sx_gpio_init(struct lt8713sx *lt8713sx) +{ + struct device *dev = lt8713sx->dev; + + lt8713sx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(lt8713sx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->reset_gpio), + "failed to acquire reset gpio\n"); + + /* power enable gpio */ + lt8713sx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(lt8713sx->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->enable_gpio), + "failed to acquire enable gpio\n"); + return 0; +} + +static ssize_t lt8713sx_firmware_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct lt8713sx *lt8713sx = dev_get_drvdata(dev); + int ret; + + ret = lt8713sx_firmware_update(lt8713sx); + if (ret < 0) + return ret; + return len; +} + +static DEVICE_ATTR_WO(lt8713sx_firmware); + +static struct attribute *lt8713sx_attrs[] = { + &dev_attr_lt8713sx_firmware.attr, + NULL, +}; + +static const struct attribute_group lt8713sx_attr_group = { + .attrs = lt8713sx_attrs, +}; + +static const struct attribute_group *lt8713sx_attr_groups[] = { + <8713sx_attr_group, + NULL, +}; + +static int lt8713sx_probe(struct i2c_client *client) +{ + struct lt8713sx *lt8713sx; + struct device *dev = &client->dev; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return dev_err_probe(dev, -ENODEV, "device doesn't support I2C\n"); + + lt8713sx = devm_kzalloc(dev, sizeof(*lt8713sx), GFP_KERNEL); + if (!lt8713sx) + return dev_err_probe(dev, -ENOMEM, "failed to allocate lt8713sx struct\n"); + + lt8713sx->dev = dev; + lt8713sx->client = client; + i2c_set_clientdata(client, lt8713sx); + + mutex_init(<8713sx->ocm_lock); + + lt8713sx->regmap = devm_regmap_init_i2c(client, <8713sx_regmap_config); + if (IS_ERR(lt8713sx->regmap)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->regmap), "regmap i2c init failed\n"); + + ret = lt8713sx_gpio_init(lt8713sx); + if (ret < 0) + goto err_of_put; + + ret = lt8713sx_regulator_init(lt8713sx); + if (ret < 0) + goto err_of_put; + + ret = lt8713sx_regulator_enable(lt8713sx); + if (ret) + goto err_of_put; + + lt8713sx_reset(lt8713sx); + + return 0; + +err_of_put: + return ret; +} + +static void lt8713sx_remove(struct i2c_client *client) +{ + struct lt8713sx *lt8713sx = i2c_get_clientdata(client); + + mutex_destroy(<8713sx->ocm_lock); + + regulator_bulk_disable(ARRAY_SIZE(lt8713sx->supplies), lt8713sx->supplies); +} + +static struct i2c_device_id lt8713sx_id[] = { + { "lontium,lt8713sx", 0 }, + { /* sentinel */ } +}; + +static const struct of_device_id lt8713sx_match_table[] = { + { .compatible = "lontium,lt8713sx" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, lt8713sx_match_table); + +static struct i2c_driver lt8713sx_driver = { + .driver = { + .name = "lt8713sx", + .of_match_table = lt8713sx_match_table, + .dev_groups = lt8713sx_attr_groups, + }, + .probe = lt8713sx_probe, + .remove = lt8713sx_remove, + .id_table = lt8713sx_id, +}; + +module_i2c_driver(lt8713sx_driver); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("lt8713sx drm bridge driver"); +MODULE_AUTHOR("Tony "); +MODULE_FIRMWARE(FW_FILE); From 05f65794a297d4511baa64e777d4a58f4e21a424 Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Tue, 18 Nov 2025 10:07:08 +0530 Subject: [PATCH 52/67] FROMLIST: dt-bindings: bridge: lt8713sx: Add bindings Add bindings for lt8713sx bridge. Co-developed-by: Prahlad Valluru Signed-off-by: Prahlad Valluru Signed-off-by: Vishnu Saini Link: https://lore.kernel.org/all/20251118-lt8713sx-bridge-driver-v2-1-25ad49280a11@oss.qualcomm.com/ --- .../display/bridge/lontium,lt8713sx.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml new file mode 100644 index 0000000000000..3fb7e042c6887 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt8713sx.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/lontium,lt8713sx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Lontium LT8713SX Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0/DP++ bridge-hub + +maintainers: + - Tony + +description: + The Lontium LT8713SX is a Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0 converter + that integrates one DP input and up to three configurable output interfaces + (DP1.4 / HDMI2.0 / DP++), with SST/MST functionality and audio support. + +properties: + compatible: + enum: + - lontium,lt8713sx + + reg: + maxItems: 1 + + vcc-supply: + description: Regulator for 3.3V vcc. + + vdd-supply: + description: Regulator for 1.1V vdd. + + reset-gpios: + description: GPIO connected to active high RESET pin. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + bridge@4f { + compatible = "lontium,lt8713sx"; + reg = <0x4f>; + reset-gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; + }; + }; From 5d5550ee890fba77132d28687a5f37ffcd8d4564 Mon Sep 17 00:00:00 2001 From: Gopi Botlagunta Date: Fri, 21 Nov 2025 19:12:06 +0530 Subject: [PATCH 53/67] FROMLIST: drm/bridge: lt9611uxc: Increase EDID wait time from 500ms to 1000ms EDID interrupt was coming 600-650 ms after HPD interrupt, resulting into EDID read timeout and default resolution of 1024x768 on display. Signed-off-by: Gopi Botlagunta Link: https://lore.kernel.org/all/20251121-hdmibridge-v1-1-14c63890f362@oss.qualcomm.com/ --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 38fb8776c0f44..6f2b72fba598e 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -382,7 +382,7 @@ lt9611uxc_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connect static int lt9611uxc_wait_for_edid(struct lt9611uxc *lt9611uxc) { return wait_event_interruptible_timeout(lt9611uxc->wq, lt9611uxc->edid_read, - msecs_to_jiffies(500)); + msecs_to_jiffies(1000)); } static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) From 6dc6571e67cca687812ce087310c0ba357da8c12 Mon Sep 17 00:00:00 2001 From: Ayushi Makhija Date: Tue, 25 Nov 2025 07:03:00 +0530 Subject: [PATCH 54/67] FROMLIST: dt-bindings: display: msm: document DSI controller and phy on QCS8300 Document DSI controller and phy on QCS8300 platform. Signed-off-by: Ayushi Makhija Link: https://lore.kernel.org/all/20251125013302.3835909-4-quic_amakhija@quicinc.com/ Signed-off-by: Arpit Saini --- .../display/msm/qcom,qcs8300-mdss.yaml | 102 +++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml index e96baaae9ba9e..c41a86203e78a 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,qcs8300-mdss.yaml @@ -53,13 +53,23 @@ patternProperties: contains: const: qcom,qcs8300-dp + "^dsi@[0-9a-f]+$": + type: object + additionalProperties: true + properties: + compatible: + contains: + const: qcom,qcs8300-dsi-ctrl + "^phy@[0-9a-f]+$": type: object additionalProperties: true properties: compatible: contains: - const: qcom,qcs8300-edp-phy + enum: + - qcom,qcs8300-dsi-phy-5nm + - qcom,qcs8300-edp-phy required: - compatible @@ -71,6 +81,7 @@ examples: #include #include #include + #include #include #include #include @@ -142,6 +153,13 @@ examples: remote-endpoint = <&mdss_dp0_in>; }; }; + + port@1 { + reg = <1>; + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; + }; }; mdp_opp_table: opp-table { @@ -169,6 +187,88 @@ examples: }; }; + dsi@ae94000 { + compatible = "qcom,qcs8300-dsi-ctrl", + "qcom,sa8775p-dsi-ctrl", + "qcom,mdss-dsi-ctrl"; + reg = <0x0ae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc MDSS_DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_ESC0_CLK>, + <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&dispcc MDSS_DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc MDSS_DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi0_phy 0>, <&mdss_dsi0_phy 1>; + phys = <&mdss_dsi0_phy>; + + operating-points-v2 = <&dsi0_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + vdda-supply = <&vreg_l5a>; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdss0_dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + mdss0_dsi0_out: endpoint { }; + }; + }; + + dsi0_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + mdss_dsi0_phy: phy@ae94400 { + compatible = "qcom,qcs8300-dsi-phy-5nm", + "qcom,sa8775p-dsi-phy-5nm"; + reg = <0x0ae94400 0x200>, + <0x0ae94600 0x280>, + <0x0ae94900 0x27c>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc MDSS_DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + + vdds-supply = <&vreg_l4a>; + }; + mdss_dp0_phy: phy@aec2a00 { compatible = "qcom,qcs8300-edp-phy", "qcom,sa8775p-edp-phy"; From 2f47b45511e8453c3ce4ff3513abb4004371bbbf Mon Sep 17 00:00:00 2001 From: Ayushi Makhija Date: Tue, 25 Nov 2025 07:02:59 +0530 Subject: [PATCH 55/67] FROMLIST: dt-bindings: msm: dsi-controller-main: document the QCS8300 DSI CTRL Document the DSI CTRL on the QCS8300 Platform. Signed-off-by: Ayushi Makhija Link: https://lore.kernel.org/all/20251125013302.3835909-3-quic_amakhija@quicinc.com/ Signed-off-by: Arpit Saini --- .../devicetree/bindings/display/msm/dsi-controller-main.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml index 4400d4cce0722..6276350e582f7 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml @@ -45,6 +45,11 @@ properties: - qcom,sm8650-dsi-ctrl - qcom,sm8750-dsi-ctrl - const: qcom,mdss-dsi-ctrl + - items: + - enum: + - qcom,qcs8300-dsi-ctrl + - const: qcom,sa8775p-dsi-ctrl + - const: qcom,mdss-dsi-ctrl - enum: - qcom,dsi-ctrl-6g-qcm2290 - qcom,mdss-dsi-ctrl # This should always come with an SoC-specific compatible From c31c79e26b200aa438e6ba878bf9ac24b8b9f7e1 Mon Sep 17 00:00:00 2001 From: Ayushi Makhija Date: Tue, 25 Nov 2025 07:02:58 +0530 Subject: [PATCH 56/67] FROMLIST: dt-bindings: display: msm-dsi-phy-7nm: document the QCS8300 DSI PHY Document the DSI PHY on the QCS8300 Platform. Signed-off-by: Ayushi Makhija Link: https://lore.kernel.org/all/20251125013302.3835909-2-quic_amakhija@quicinc.com/ Signed-off-by: Arpit Saini --- .../bindings/display/msm/dsi-phy-7nm.yaml | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml index 1ca820a500b72..7a83387502da1 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml @@ -14,18 +14,24 @@ allOf: properties: compatible: - enum: - - qcom,dsi-phy-7nm - - qcom,dsi-phy-7nm-8150 - - qcom,sa8775p-dsi-phy-5nm - - qcom,sar2130p-dsi-phy-5nm - - qcom,sc7280-dsi-phy-7nm - - qcom,sm6375-dsi-phy-7nm - - qcom,sm8350-dsi-phy-5nm - - qcom,sm8450-dsi-phy-5nm - - qcom,sm8550-dsi-phy-4nm - - qcom,sm8650-dsi-phy-4nm - - qcom,sm8750-dsi-phy-3nm + oneOf: + - items: + - enum: + - qcom,dsi-phy-7nm + - qcom,dsi-phy-7nm-8150 + - qcom,sa8775p-dsi-phy-5nm + - qcom,sar2130p-dsi-phy-5nm + - qcom,sc7280-dsi-phy-7nm + - qcom,sm6375-dsi-phy-7nm + - qcom,sm8350-dsi-phy-5nm + - qcom,sm8450-dsi-phy-5nm + - qcom,sm8550-dsi-phy-4nm + - qcom,sm8650-dsi-phy-4nm + - qcom,sm8750-dsi-phy-3nm + - items: + - enum: + - qcom,qcs8300-dsi-phy-5nm + - const: qcom,sa8775p-dsi-phy-5nm reg: items: From 0ba87d96a8af6ce07c160cd595589d01ec4760ad Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Sep 2025 22:31:02 +0530 Subject: [PATCH 57/67] FROMGIT: dt-bindings: pinctrl: qcom,pmic-gpio: Add GPIO bindings for Glymur PMICs Update the Qualcomm Technologies, Inc. PMIC GPIO binding documentation to include compatible strings for PMK8850, PMH0101, PMH0104, PMH0110 and PMCX0102 PMICs. Signed-off-by: Anjelique Melendez Signed-off-by: Jishnu Prakash Signed-off-by: Pankaj Patil Signed-off-by: Kamal Wadhwa Reviewed-by: Bartosz Golaszewski Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250924-glymur-pinctrl-driver-v2-1-11bef014a778@oss.qualcomm.com Signed-off-by: Kamal Wadhwa --- .../bindings/pinctrl/qcom,pmic-gpio.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml index 5e6dfcc3fe9b3..8ae4489637f3d 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml @@ -59,7 +59,11 @@ properties: - qcom,pmc8180-gpio - qcom,pmc8180c-gpio - qcom,pmc8380-gpio + - qcom,pmcx0102-gpio - qcom,pmd8028-gpio + - qcom,pmh0101-gpio + - qcom,pmh0104-gpio + - qcom,pmh0110-gpio - qcom,pmi632-gpio - qcom,pmi8950-gpio - qcom,pmi8994-gpio @@ -68,6 +72,7 @@ properties: - qcom,pmiv0104-gpio - qcom,pmk8350-gpio - qcom,pmk8550-gpio + - qcom,pmk8850-gpio - qcom,pmm8155au-gpio - qcom,pmm8654au-gpio - qcom,pmp8074-gpio @@ -191,6 +196,8 @@ allOf: - qcom,pm8950-gpio - qcom,pm8953-gpio - qcom,pmi632-gpio + - qcom,pmh0104-gpio + - qcom,pmk8850-gpio then: properties: gpio-line-names: @@ -303,6 +310,8 @@ allOf: compatible: contains: enum: + - qcom,pmcx0102-gpio + - qcom,pmh0110-gpio - qcom,pmi8998-gpio then: properties: @@ -318,6 +327,7 @@ allOf: compatible: contains: enum: + - qcom,pmh0101-gpio - qcom,pmih0108-gpio then: properties: @@ -481,13 +491,18 @@ $defs: - gpio1-gpio22 for pm8994 - gpio1-gpio26 for pm8998 - gpio1-gpio22 for pma8084 + - gpio1-gpio14 for pmcx0102 - gpio1-gpio4 for pmd8028 + - gpio1-gpio18 for pmh0101 + - gpio1-gpio8 for pmh0104 + - gpio1-gpio14 for pmh0110 - gpio1-gpio8 for pmi632 - gpio1-gpio2 for pmi8950 - gpio1-gpio10 for pmi8994 - gpio1-gpio18 for pmih0108 - gpio1-gpio4 for pmk8350 - gpio1-gpio6 for pmk8550 + - gpio1-gpio8 for pmk8850 - gpio1-gpio10 for pmm8155au - gpio1-gpio12 for pmm8654au - gpio1-gpio12 for pmp8074 (holes on gpio1 and gpio12) From 7bd07dc872971a4232d7bef4cc6b741e88fb10ba Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Wed, 24 Sep 2025 22:31:03 +0530 Subject: [PATCH 58/67] FROMGIT: pinctrl: qcom: spmi-gpio: Add PMCX0102, PMK8850 & PMH01XX PMICs support Add support for PMCX0102, PMH0101, PMH0104, PMH0110 and PMK8850 PMIC GPIOs with adding appropriate compatible strings. Signed-off-by: Anjelique Melendez Signed-off-by: Jishnu Prakash Signed-off-by: Kamal Wadhwa Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250924-glymur-pinctrl-driver-v2-2-11bef014a778@oss.qualcomm.com Signed-off-by: Kamal Wadhwa --- drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 485b68cc93f8e..c4f7d2d7a0176 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -1239,7 +1239,11 @@ static const struct of_device_id pmic_gpio_of_match[] = { { .compatible = "qcom,pm8998-gpio", .data = (void *) 26 }, { .compatible = "qcom,pma8084-gpio", .data = (void *) 22 }, { .compatible = "qcom,pmc8380-gpio", .data = (void *) 10 }, + { .compatible = "qcom,pmcx0102-gpio", .data = (void *)14 }, { .compatible = "qcom,pmd8028-gpio", .data = (void *) 4 }, + { .compatible = "qcom,pmh0101-gpio", .data = (void *)18 }, + { .compatible = "qcom,pmh0104-gpio", .data = (void *)8 }, + { .compatible = "qcom,pmh0110-gpio", .data = (void *)14 }, { .compatible = "qcom,pmi632-gpio", .data = (void *) 8 }, { .compatible = "qcom,pmi8950-gpio", .data = (void *) 2 }, { .compatible = "qcom,pmi8994-gpio", .data = (void *) 10 }, @@ -1248,6 +1252,7 @@ static const struct of_device_id pmic_gpio_of_match[] = { { .compatible = "qcom,pmiv0104-gpio", .data = (void *) 10 }, { .compatible = "qcom,pmk8350-gpio", .data = (void *) 4 }, { .compatible = "qcom,pmk8550-gpio", .data = (void *) 6 }, + { .compatible = "qcom,pmk8850-gpio", .data = (void *)8 }, { .compatible = "qcom,pmm8155au-gpio", .data = (void *) 10 }, { .compatible = "qcom,pmm8654au-gpio", .data = (void *) 12 }, /* pmp8074 has 12 GPIOs with holes on 1 and 12 */ From 2803dee8e1259a136907758bd0947a1fc63f6451 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Wed, 24 Sep 2025 22:31:04 +0530 Subject: [PATCH 59/67] FROMGIT:pinctrl: qcom: spmi-gpio: add support for {LV_VIN2, MV_VIN3}_CLK subtypes Add support for SPMI PMIC GPIO subtypes GPIO_LV_VIN2_CLK and GPIO_MV_VIN3_CLK. Signed-off-by: Subbaraman Narayanamurthy Signed-off-by: Jishnu Prakash Signed-off-by: Kamal Wadhwa Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250924-glymur-pinctrl-driver-v2-3-11bef014a778@oss.qualcomm.com Signed-off-by: Kamal Wadhwa --- drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index c4f7d2d7a0176..83f940fe30b26 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -42,6 +42,8 @@ #define PMIC_GPIO_SUBTYPE_GPIO_MV 0x11 #define PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2 0x12 #define PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3 0x13 +#define PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2_CLK 0x14 +#define PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3_CLK 0x15 #define PMIC_MPP_REG_RT_STS 0x10 #define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1 @@ -852,11 +854,13 @@ static int pmic_gpio_populate(struct pmic_gpio_state *state, pad->lv_mv_type = true; break; case PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2: + case PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2_CLK: pad->num_sources = 2; pad->have_buffer = true; pad->lv_mv_type = true; break; case PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3: + case PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3_CLK: pad->num_sources = 3; pad->have_buffer = true; pad->lv_mv_type = true; From 2c77b9d94b605b50569854527f538c09536b8c10 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 14 May 2025 02:30:00 +0300 Subject: [PATCH 60/67] FROMLIST: drm/msm/dpu: enable virtual planes by default Turn on the switch and use virtual planes by default, enhancing utilisation of the display pipelines. It is still possible to use legacy implementation by using `msm.dpu_use_virtual_planes=false` kernel boot parameter. Link:https://lore.kernel.org/all/20250514-dpu-enable-virt-planes-v1-1-bf5ba0088007@oss.qualcomm.com/ Signed-off-by: Dmitry Baryshkov Signed-off-by: Mahadevan P --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 4e5a8ecd31f75..45bf345493164 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -52,7 +52,7 @@ #define DPU_DEBUGFS_DIR "msm_dpu" #define DPU_DEBUGFS_HWMASKNAME "hw_log_mask" -bool dpu_use_virtual_planes; +bool dpu_use_virtual_planes = true; module_param(dpu_use_virtual_planes, bool, 0); static int dpu_kms_hw_init(struct msm_kms *kms); From 190ecfe792ee480fe20eb5ab3491675480b0cac5 Mon Sep 17 00:00:00 2001 From: Mahadevan P Date: Mon, 24 Nov 2025 19:57:01 +0530 Subject: [PATCH 61/67] FROMLIST: drm/msm/disp/dpu: add merge3d support for sc7280 Add support for the merge3d block on sc7280 which will allow merge of streams coming from two layer mixers routed to single non DSC interface. This change helps to support larger buffer width which exceeds max_linewidth of 2400. Link:https://lore.kernel.org/all/20251124-merge3d-sc7280-v1-1-798d94211626@oss.qualcomm.com/ Fixes: 591e34a091d1 ("drm/msm/disp/dpu1: add support for display for SC7280 target") Signed-off-by: Mahadevan P --- .../gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h index 8f978b9c34520..2f8688224f343 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h @@ -13,6 +13,7 @@ static const struct dpu_caps sc7280_dpu_caps = { .has_dim_layer = true, .has_idle_pc = true, .max_linewidth = 2400, + .has_3d_merge = true, .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, }; @@ -134,17 +135,24 @@ static const struct dpu_pingpong_cfg sc7280_pp[] = { .name = "pingpong_2", .id = PINGPONG_2, .base = 0x6b000, .len = 0, .sblk = &sc7280_pp_sblk, - .merge_3d = 0, + .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 = 0, + .merge_3d = MERGE_3D_1, .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), }, }; +static const struct dpu_merge_3d_cfg sc7280_merge_3d[] = { + { + .name = "merge_3d_1", .id = MERGE_3D_1, + .base = 0x4f000, .len = 0x8, + }, +}; + /* NOTE: sc7280 only has one DSC hard slice encoder */ static const struct dpu_dsc_cfg sc7280_dsc[] = { { @@ -247,6 +255,8 @@ const struct dpu_mdss_cfg dpu_sc7280_cfg = { .mixer = sc7280_lm, .pingpong_count = ARRAY_SIZE(sc7280_pp), .pingpong = sc7280_pp, + .merge_3d_count = ARRAY_SIZE(sc7280_merge_3d), + .merge_3d = sc7280_merge_3d, .dsc_count = ARRAY_SIZE(sc7280_dsc), .dsc = sc7280_dsc, .wb_count = ARRAY_SIZE(sc7280_wb), From f7bb3bb5720480c5988e5bc7d6c1f2518934a4a7 Mon Sep 17 00:00:00 2001 From: Nilesh Laad Date: Wed, 26 Nov 2025 17:01:18 +0530 Subject: [PATCH 62/67] FROMLIST: drm/bridge: lt9611uxc: extend mode valid checks Currently valid mode checks are only for hdisplay and vdisplay, add htotal and vtotal to filter only specific modes. Link:https://lore.kernel.org/lkml/20251126-lt9611uxc-modes-v2-1-34bf9b351921@oss.qualcomm.com/ Signed-off-by: Nilesh Laad Signed-off-by: Mahadevan P --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 36 ++++++++++++---------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 6f2b72fba598e..d0273a55687de 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -89,7 +89,9 @@ static const struct regmap_config lt9611uxc_regmap_config = { struct lt9611uxc_mode { u16 hdisplay; + u16 htotal; u16 vdisplay; + u16 vtotal; u8 vrefresh; }; @@ -98,22 +100,22 @@ struct lt9611uxc_mode { * Enumerate them here to check whether the mode is supported. */ static struct lt9611uxc_mode lt9611uxc_modes[] = { - { 1920, 1080, 60 }, - { 1920, 1080, 30 }, - { 1920, 1080, 25 }, - { 1366, 768, 60 }, - { 1360, 768, 60 }, - { 1280, 1024, 60 }, - { 1280, 800, 60 }, - { 1280, 720, 60 }, - { 1280, 720, 50 }, - { 1280, 720, 30 }, - { 1152, 864, 60 }, - { 1024, 768, 60 }, - { 800, 600, 60 }, - { 720, 576, 50 }, - { 720, 480, 60 }, - { 640, 480, 60 }, + { 1920, 2200, 1080, 1125, 60 }, + { 1920, 2200, 1080, 1125, 30 }, + { 1920, 2640, 1080, 1125, 25 }, + { 1366, 1792, 768, 798, 60 }, + { 1360, 1792, 768, 795, 60 }, + { 1280, 1688, 1024, 1066, 60 }, + { 1280, 1680, 800, 831, 60 }, + { 1280, 1650, 720, 750, 60 }, + { 1280, 1980, 720, 750, 50 }, + { 1280, 3300, 720, 750, 30 }, + { 1152, 1600, 864, 900, 60 }, + { 1024, 1344, 768, 806, 60 }, + { 800, 1056, 600, 628, 60 }, + { 720, 864, 576, 625, 50 }, + { 720, 858, 480, 525, 60 }, + { 640, 800, 480, 525, 60 }, }; static struct lt9611uxc *bridge_to_lt9611uxc(struct drm_bridge *bridge) @@ -237,7 +239,9 @@ static struct lt9611uxc_mode *lt9611uxc_find_mode(const struct drm_display_mode for (i = 0; i < ARRAY_SIZE(lt9611uxc_modes); i++) { if (lt9611uxc_modes[i].hdisplay == mode->hdisplay && + lt9611uxc_modes[i].htotal == mode->htotal && lt9611uxc_modes[i].vdisplay == mode->vdisplay && + lt9611uxc_modes[i].vtotal == mode->vtotal && lt9611uxc_modes[i].vrefresh == drm_mode_vrefresh(mode)) { return <9611uxc_modes[i]; } From 0d74e4315149eb9dbcd4d3150bc1a37b220cab5e Mon Sep 17 00:00:00 2001 From: Nilesh Laad Date: Wed, 26 Nov 2025 18:52:37 +0530 Subject: [PATCH 63/67] FROMLIST: drm/bridge: lt9611uxc: add support for 4K@30 resolution Add 3840x2160@30 mode in lt9611uxc modes to add support for 4K@30 resolution. Link:https://lore.kernel.org/r/20251126-lt9611uxc-4k30-v2-1-3de0ea58c24e@oss.qualcomm.com Signed-off-by: Nilesh Laad Signed-off-by: Mahadevan P --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index d0273a55687de..d8ab95bb3a612 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -100,6 +100,7 @@ struct lt9611uxc_mode { * Enumerate them here to check whether the mode is supported. */ static struct lt9611uxc_mode lt9611uxc_modes[] = { + { 3840, 4400, 2160, 2250, 30 }, { 1920, 2200, 1080, 1125, 60 }, { 1920, 2200, 1080, 1125, 30 }, { 1920, 2640, 1080, 1125, 25 }, From a7f49233ff477f2cbd471a1c81a44162c3df602b Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Thu, 4 Dec 2025 20:38:48 +0530 Subject: [PATCH 64/67] Add qcom-next log files for 20251204 Adding merge log file and topic_SHA1 file Signed-off-by: Salendarsingh Gaud --- qcom-next/merge.log | 415 +++++++++++++++++++++++++++++++++++++++++++ qcom-next/topic_SHA1 | 39 ++++ 2 files changed, 454 insertions(+) create mode 100644 qcom-next/merge.log create mode 100644 qcom-next/topic_SHA1 diff --git a/qcom-next/merge.log b/qcom-next/merge.log new file mode 100644 index 0000000000000..fbd82e6d6d9bd --- /dev/null +++ b/qcom-next/merge.log @@ -0,0 +1,415 @@ +Verified existence of local and remote repos: Success +/local/mnt/workspace/automerge/actions-runner/_work/kernel-automation/kernel-automation/kernel-topics /local/mnt/workspace/automerge/actions-runner/_work/kernel-automation/kernel-automation/kernel-topics +Reuse-Recorded-Resolution: Enabled +Downloaded shared rerere cache +Local tree is clean +Removing old remotes ... +The remote origin https://github.com/qualcomm-linux/kernel-topics.git is no longer tracked. +Delete it [Y/n]? Done, removed 1 old remote(s). +Adding new remotes... +Adding remote baseline https://github.com/qualcomm-linux/kernel.git qcom-next-staging +Updating baseline +Adding remote tech/bsp/clk https://github.com/qualcomm-linux/kernel-topics.git tech/bsp/clk +Updating tech/bsp/clk +Adding remote tech/bsp/interconnect https://github.com/qualcomm-linux/kernel-topics.git tech/bsp/interconnect +Updating tech/bsp/interconnect +Adding remote tech/mem/secure-buffer https://github.com/qualcomm-linux/kernel-topics.git tech/mem/secure-buffer +Updating tech/mem/secure-buffer +Adding remote tech/security/firmware-smc https://github.com/qualcomm-linux/kernel-topics.git tech/security/firmware-smc +Updating tech/security/firmware-smc +Adding remote tech/bsp/soc-infra https://github.com/qualcomm-linux/kernel-topics.git tech/bsp/soc-infra +Updating tech/bsp/soc-infra +Adding remote tech/debug/soc https://github.com/qualcomm-linux/kernel-topics.git tech/debug/soc +Updating tech/debug/soc +Adding remote tech/bsp/pinctrl https://github.com/qualcomm-linux/kernel-topics.git tech/bsp/pinctrl +Updating tech/bsp/pinctrl +Adding remote tech/bsp/remoteproc https://github.com/qualcomm-linux/kernel-topics.git tech/bsp/remoteproc +Updating tech/bsp/remoteproc +Adding remote tech/bus/peripherals https://github.com/qualcomm-linux/kernel-topics.git tech/bus/peripherals +Updating tech/bus/peripherals +Adding remote tech/bus/pci/all https://github.com/qualcomm-linux/kernel-topics.git tech/bus/pci/all +Updating tech/bus/pci/all +Adding remote tech/bus/pci/mhi https://github.com/qualcomm-linux/kernel-topics.git tech/bus/pci/mhi +Updating tech/bus/pci/mhi +Adding remote tech/bus/pci/phy https://github.com/qualcomm-linux/kernel-topics.git tech/bus/pci/phy +Updating tech/bus/pci/phy +Adding remote tech/bus/pci/pwrctl https://github.com/qualcomm-linux/kernel-topics.git tech/bus/pci/pwrctl +Updating tech/bus/pci/pwrctl +Adding remote tech/bus/usb/dwc https://github.com/qualcomm-linux/kernel-topics.git tech/bus/usb/dwc +Updating tech/bus/usb/dwc +Adding remote tech/bus/usb/gadget https://github.com/qualcomm-linux/kernel-topics.git tech/bus/usb/gadget +Updating tech/bus/usb/gadget +Adding remote tech/bus/usb/phy https://github.com/qualcomm-linux/kernel-topics.git tech/bus/usb/phy +Updating tech/bus/usb/phy +Adding remote tech/debug/eud https://github.com/qualcomm-linux/kernel-topics.git tech/debug/eud +Updating tech/debug/eud +Adding remote tech/debug/hwtracing https://github.com/qualcomm-linux/kernel-topics.git tech/debug/hwtracing +Updating tech/debug/hwtracing +Adding remote tech/debug/rdbg https://github.com/qualcomm-linux/kernel-topics.git tech/debug/rdbg +Updating tech/debug/rdbg +Adding remote tech/pmic/backlight https://github.com/qualcomm-linux/kernel-topics.git tech/pmic/backlight +Updating tech/pmic/backlight +Adding remote tech/pmic/mfd https://github.com/qualcomm-linux/kernel-topics.git tech/pmic/mfd +Updating tech/pmic/mfd +Adding remote tech/pmic/misc https://github.com/qualcomm-linux/kernel-topics.git tech/pmic/misc +Updating tech/pmic/misc +Adding remote tech/pmic/regulator https://github.com/qualcomm-linux/kernel-topics.git tech/pmic/regulator +Updating tech/pmic/regulator +Adding remote tech/pmic/supply https://github.com/qualcomm-linux/kernel-topics.git tech/pmic/supply +Updating tech/pmic/supply +Adding remote tech/mem/dma-buf https://github.com/qualcomm-linux/kernel-topics.git tech/mem/dma-buf +Updating tech/mem/dma-buf +Adding remote tech/mem/iommu https://github.com/qualcomm-linux/kernel-topics.git tech/mem/iommu +Updating tech/mem/iommu +Adding remote tech/mm/audio/all https://github.com/qualcomm-linux/kernel-topics.git tech/mm/audio/all +Updating tech/mm/audio/all +Adding remote tech/mm/audio/soundwire https://github.com/qualcomm-linux/kernel-topics.git tech/mm/audio/soundwire +Updating tech/mm/audio/soundwire +Adding remote tech/mm/camss https://github.com/qualcomm-linux/kernel-topics.git tech/mm/camss +Updating tech/mm/camss +Adding remote tech/mm/drm https://github.com/qualcomm-linux/kernel-topics.git tech/mm/drm +Updating tech/mm/drm +Adding remote tech/mm/fastrpc https://github.com/qualcomm-linux/kernel-topics.git tech/mm/fastrpc +Updating tech/mm/fastrpc +Adding remote tech/mm/phy https://github.com/qualcomm-linux/kernel-topics.git tech/mm/phy +Updating tech/mm/phy +Adding remote tech/mm/video https://github.com/qualcomm-linux/kernel-topics.git tech/mm/video +Updating tech/mm/video +Adding remote tech/mm/gpu https://github.com/qualcomm-linux/kernel-topics.git tech/mm/gpu +Updating tech/mm/gpu +Adding remote tech/mproc/rpmsg https://github.com/qualcomm-linux/kernel-topics.git tech/mproc/rpmsg +Updating tech/mproc/rpmsg +Adding remote tech/mproc/qmi https://github.com/qualcomm-linux/kernel-topics.git tech/mproc/qmi +Updating tech/mproc/qmi +Adding remote tech/net/ath https://github.com/qualcomm-linux/kernel-topics.git tech/net/ath +Updating tech/net/ath +Adding remote tech/net/eth https://github.com/qualcomm-linux/kernel-topics.git tech/net/eth +Updating tech/net/eth +Adding remote tech/net/rmnet https://github.com/qualcomm-linux/kernel-topics.git tech/net/rmnet +Updating tech/net/rmnet +Adding remote tech/net/qrtr https://github.com/qualcomm-linux/kernel-topics.git tech/net/qrtr +Updating tech/net/qrtr +Adding remote tech/net/phy https://github.com/qualcomm-linux/kernel-topics.git tech/net/phy +Updating tech/net/phy +Adding remote tech/net/bluetooth https://github.com/qualcomm-linux/kernel-topics.git tech/net/bluetooth +Updating tech/net/bluetooth +Adding remote tech/pm/opp https://github.com/qualcomm-linux/kernel-topics.git tech/pm/opp +Updating tech/pm/opp +Adding remote tech/pm/pmdomain https://github.com/qualcomm-linux/kernel-topics.git tech/pm/pmdomain +Updating tech/pm/pmdomain +Adding remote tech/pm/power https://github.com/qualcomm-linux/kernel-topics.git tech/pm/power +Updating tech/pm/power +Adding remote tech/pm/thermal https://github.com/qualcomm-linux/kernel-topics.git tech/pm/thermal +Updating tech/pm/thermal +Adding remote tech/security/crypto https://github.com/qualcomm-linux/kernel-topics.git tech/security/crypto +Updating tech/security/crypto +Adding remote tech/security/fscrypt https://github.com/qualcomm-linux/kernel-topics.git tech/security/fscrypt +Updating tech/security/fscrypt +Adding remote tech/security/ice https://github.com/qualcomm-linux/kernel-topics.git tech/security/ice +Updating tech/security/ice +Adding remote tech/storage/nvmem https://github.com/qualcomm-linux/kernel-topics.git tech/storage/nvmem +Updating tech/storage/nvmem +Adding remote tech/storage/phy https://github.com/qualcomm-linux/kernel-topics.git tech/storage/phy +Updating tech/storage/phy +Adding remote tech/storage/all https://github.com/qualcomm-linux/kernel-topics.git tech/storage/all +Updating tech/storage/all +Adding remote tech/virt/gunyah https://github.com/qualcomm-linux/kernel-topics.git tech/virt/gunyah +Updating tech/virt/gunyah +Adding remote tech/all/dt/qcs6490 https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/qcs6490 +Updating tech/all/dt/qcs6490 +Adding remote tech/all/dt/qcs9100 https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/qcs9100 +Updating tech/all/dt/qcs9100 +Adding remote tech/all/dt/qcs8300 https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/qcs8300 +Updating tech/all/dt/qcs8300 +Adding remote tech/all/dt/qcs615 https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/qcs615 +Updating tech/all/dt/qcs615 +Adding remote tech/all/dt/hamoa https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/hamoa +Updating tech/all/dt/hamoa +Adding remote tech/all/dt/glymur https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/glymur +Updating tech/all/dt/glymur +Adding remote tech/all/dt/kaanapali https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/kaanapali +Updating tech/all/dt/kaanapali +Adding remote tech/all/dt/pakala https://github.com/qualcomm-linux/kernel-topics.git tech/all/dt/pakala +Updating tech/all/dt/pakala +Adding remote tech/all/config https://github.com/qualcomm-linux/kernel-topics.git tech/all/config +Updating tech/all/config +Adding remote tech/overlay/dt https://github.com/qualcomm-linux/kernel-topics.git tech/overlay/dt +Updating tech/overlay/dt +Adding remote tech/all/workaround https://github.com/qualcomm-linux/kernel-topics.git tech/all/workaround +Updating tech/all/workaround +Done, added 65 new remote(s). +Updating the remotes ... +Updating tech/bsp/clk +Updating tech/bsp/interconnect +Updating tech/mem/secure-buffer +Updating tech/security/firmware-smc +Updating tech/bsp/soc-infra +Updating tech/debug/soc +Updating tech/bsp/pinctrl +Updating tech/bsp/remoteproc +Updating tech/bus/peripherals +Updating tech/bus/pci/all +Updating tech/bus/pci/mhi +Updating tech/bus/pci/phy +Updating tech/bus/pci/pwrctl +Updating tech/bus/usb/dwc +Updating tech/bus/usb/gadget +Updating tech/bus/usb/phy +Updating tech/debug/eud +Updating tech/debug/hwtracing +Updating tech/debug/rdbg +Updating tech/pmic/backlight +Updating tech/pmic/mfd +Updating tech/pmic/misc +Updating tech/pmic/regulator +Updating tech/pmic/supply +Updating tech/mem/dma-buf +Updating tech/mem/iommu +Updating tech/mm/audio/all +Updating tech/mm/audio/soundwire +Updating tech/mm/camss +Updating tech/mm/drm +Updating tech/mm/fastrpc +Updating tech/mm/phy +Updating tech/mm/video +Updating tech/mm/gpu +Updating tech/mproc/rpmsg +Updating tech/mproc/qmi +Updating tech/net/ath +Updating tech/net/eth +Updating tech/net/rmnet +Updating tech/net/qrtr +Updating tech/net/phy +Updating tech/net/bluetooth +Updating tech/pm/opp +Updating tech/pm/pmdomain +Updating tech/pm/power +Updating tech/pm/thermal +Updating tech/security/crypto +Updating tech/security/fscrypt +Updating tech/security/ice +Updating tech/storage/nvmem +Updating tech/storage/phy +Updating tech/storage/all +Updating tech/virt/gunyah +Updating tech/all/dt/qcs6490 +Updating tech/all/dt/qcs9100 +Updating tech/all/dt/qcs8300 +Updating tech/all/dt/qcs615 +Updating tech/all/dt/hamoa +Updating tech/all/dt/glymur +Updating tech/all/dt/kaanapali +Updating tech/all/dt/pakala +Updating tech/all/config +Updating tech/overlay/dt +Updating tech/all/workaround +Done, updated 0 remote(s). +Updating baseline ... +Fetching baseline +latest tag/id is 7d0a66e4bb9081d75c82ec4957c50034cb0ea449 +Done, updated baseline. +Latest tag is 7d0a66e4bb9081d75c82ec4957c50034cb0ea449 +Create a new integration branch based on 7d0a66e4bb9081d75c82ec4957c50034cb0ea449 +Merging topic branches... +------------------------------------------ + ** Merging topic branch: tech/bsp/clk/tech/bsp/clk +Merge successful : tech/bsp/clk : aea4f0c77e2524664061c3756cf8cadccec41145 : 8 +------------------------------------------ + ** Merging topic branch: tech/bsp/interconnect/tech/bsp/interconnect +Merge successful : tech/bsp/interconnect : 938409e3faa500839cfe2db3a2e3becfd9fb7fc6 : 2 +------------------------------------------ + ** Merging topic branch: tech/mem/secure-buffer/tech/mem/secure-buffer +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/security/firmware-smc/tech/security/firmware-smc +Merge successful : tech/security/firmware-smc : 829c78b71ef815f34cfadc407ddf7438d396ef1d : 1 +------------------------------------------ + ** Merging topic branch: tech/bsp/soc-infra/tech/bsp/soc-infra +Merge successful : tech/bsp/soc-infra : 797d5a2c99ee52b6fdbafcd0862e867d151c0539 : 18 +------------------------------------------ + ** Merging topic branch: tech/debug/soc/tech/debug/soc +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/bsp/pinctrl/tech/bsp/pinctrl +Merge successful : tech/bsp/pinctrl : 9a297f4d9e88c69bd9a650364126da4d2dbb658f : 2 +------------------------------------------ + ** Merging topic branch: tech/bsp/remoteproc/tech/bsp/remoteproc +Merge successful : tech/bsp/remoteproc : 806913442c1fd5fc6195a904f574a334df280b80 : 12 +------------------------------------------ + ** Merging topic branch: tech/bus/peripherals/tech/bus/peripherals +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/bus/pci/all/tech/bus/pci/all +Merge successful : tech/bus/pci/all : 4490847265d4793f82a141c92a05f536ed00f2b5 : 7 +------------------------------------------ + ** Merging topic branch: tech/bus/pci/mhi/tech/bus/pci/mhi +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/bus/pci/phy/tech/bus/pci/phy +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/bus/pci/pwrctl/tech/bus/pci/pwrctl +Merge successful : tech/bus/pci/pwrctl : c36944ebc50ed5d40b3c550cbe5792b93c32dc27 : 7 +------------------------------------------ + ** Merging topic branch: tech/bus/usb/dwc/tech/bus/usb/dwc +Merge successful : tech/bus/usb/dwc : c29f570c16249b9ae1472b08a3570f2985fa5532 : 1 +------------------------------------------ + ** Merging topic branch: tech/bus/usb/gadget/tech/bus/usb/gadget +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/bus/usb/phy/tech/bus/usb/phy +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/debug/eud/tech/debug/eud +Merge successful : tech/debug/eud : eb36d9dbce445b0a2032775a5668ba02dd4b67cb : 1 +------------------------------------------ + ** Merging topic branch: tech/debug/hwtracing/tech/debug/hwtracing +Merge successful : tech/debug/hwtracing : 961640988eb239085e7643c0ec26e627d8389049 : 34 +------------------------------------------ + ** Merging topic branch: tech/debug/rdbg/tech/debug/rdbg +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/pmic/backlight/tech/pmic/backlight +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/pmic/mfd/tech/pmic/mfd +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/pmic/misc/tech/pmic/misc +Merge successful : tech/pmic/misc : 2803dee8e1259a136907758bd0947a1fc63f6451 : 8 +------------------------------------------ + ** Merging topic branch: tech/pmic/regulator/tech/pmic/regulator +Merge successful : tech/pmic/regulator : 81fc8fbf0f0a02a7b2d855aee574b88bd7d59107 : 6 +------------------------------------------ + ** Merging topic branch: tech/pmic/supply/tech/pmic/supply +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/mem/dma-buf/tech/mem/dma-buf +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/mem/iommu/tech/mem/iommu +Merge successful : tech/mem/iommu : fc1b59c1f4305fd3630a4205d2db8f680626ef5c : 1 +------------------------------------------ + ** Merging topic branch: tech/mm/audio/all/tech/mm/audio/all +Merge successful : tech/mm/audio/all : 553419127a35c4d857a1d9a6fe68c2b4d23cac48 : 2 +------------------------------------------ + ** Merging topic branch: tech/mm/audio/soundwire/tech/mm/audio/soundwire +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/mm/camss/tech/mm/camss +Merge successful : tech/mm/camss : d1d2c38f53e8f67b6a11866d4202561fbed0a988 : 3 +------------------------------------------ + ** Merging topic branch: tech/mm/drm/tech/mm/drm +Merge successful : tech/mm/drm : 0d74e4315149eb9dbcd4d3150bc1a37b220cab5e : 39 +------------------------------------------ + ** Merging topic branch: tech/mm/fastrpc/tech/mm/fastrpc +Merge successful : tech/mm/fastrpc : dba4eb255febb4cc38d2e340978c58f8f21ff6cc : 3 +------------------------------------------ + ** Merging topic branch: tech/mm/phy/tech/mm/phy +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/mm/video/tech/mm/video +Merge successful : tech/mm/video : 1af1bf9935671af7c556b7e952a9afd2def6a58d : 13 +------------------------------------------ + ** Merging topic branch: tech/mm/gpu/tech/mm/gpu +Merge successful : tech/mm/gpu : 229115a988e2a9ac5c6dcbf06e396be043b81592 : 4 +------------------------------------------ + ** Merging topic branch: tech/mproc/rpmsg/tech/mproc/rpmsg +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/mproc/qmi/tech/mproc/qmi +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/net/ath/tech/net/ath +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/net/eth/tech/net/eth +Merge successful : tech/net/eth : c280d7e86faa86b16d3c1e313e95207503cf3770 : 1 +------------------------------------------ + ** Merging topic branch: tech/net/rmnet/tech/net/rmnet +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/net/qrtr/tech/net/qrtr +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/net/phy/tech/net/phy +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/net/bluetooth/tech/net/bluetooth +Merge successful : tech/net/bluetooth : b5902f2daf61ad3eed61a9fbf3d75ba3748cf53e : 2 +------------------------------------------ + ** Merging topic branch: tech/pm/opp/tech/pm/opp +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/pm/pmdomain/tech/pm/pmdomain +Merge successful : tech/pm/pmdomain : c2e58ee4e1ed72c4fe6fb6a48d8d83d4ea2269fc : 3 +------------------------------------------ + ** Merging topic branch: tech/pm/power/tech/pm/power +Merge successful : tech/pm/power : 9fe45cfe84f7873accec2689b312180897cb56d0 : 7 +------------------------------------------ + ** Merging topic branch: tech/pm/thermal/tech/pm/thermal +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/security/crypto/tech/security/crypto +Merge successful : tech/security/crypto : 0ff2ae7f2e708a083b489a9a4a34c07bd701aec1 : 11 +------------------------------------------ + ** Merging topic branch: tech/security/fscrypt/tech/security/fscrypt +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/security/ice/tech/security/ice +Merge successful : tech/security/ice : e6140349dfc670e22f2507bb8f053be15b353ddd : 3 +------------------------------------------ + ** Merging topic branch: tech/storage/nvmem/tech/storage/nvmem +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/storage/phy/tech/storage/phy +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/storage/all/tech/storage/all +Merge successful : tech/storage/all : ba8c93ddc42883a8b91db3e5fd0f19d0c79a9ddb : 6 +------------------------------------------ + ** Merging topic branch: tech/virt/gunyah/tech/virt/gunyah +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/all/dt/qcs6490/tech/all/dt/qcs6490 +Merge successful : tech/all/dt/qcs6490 : 91a5f259df1c65b4981c51e7d825a26617afbd50 : 7 +------------------------------------------ + ** Merging topic branch: tech/all/dt/qcs9100/tech/all/dt/qcs9100 +Merge successful : tech/all/dt/qcs9100 : ae04b95f30a6b56d2bbbf59fdb94d45e2be7d0f9 : 15 +------------------------------------------ + ** Merging topic branch: tech/all/dt/qcs8300/tech/all/dt/qcs8300 +Merge successful : tech/all/dt/qcs8300 : 32998bbef522f5cb37374467b732d89442bcfdc6 : 26 +------------------------------------------ + ** Merging topic branch: tech/all/dt/qcs615/tech/all/dt/qcs615 +Merge successful : tech/all/dt/qcs615 : ac047bf2fb68a45c0708be88eb78482f1b5278f3 : 8 +------------------------------------------ + ** Merging topic branch: tech/all/dt/hamoa/tech/all/dt/hamoa +Merge successful : tech/all/dt/hamoa : 85bf4e6cc25178294e99ce9ec8885395ed820178 : 7 +------------------------------------------ + ** Merging topic branch: tech/all/dt/glymur/tech/all/dt/glymur +Nothing to merge: Already up to date. +------------------------------------------ + ** Merging topic branch: tech/all/dt/kaanapali/tech/all/dt/kaanapali +Merge successful : tech/all/dt/kaanapali : 746a2029c703df8d18c3b3209cd1cb635a2abd92 : 3 +------------------------------------------ + ** Merging topic branch: tech/all/dt/pakala/tech/all/dt/pakala +Merge successful : tech/all/dt/pakala : e0326f1e866dc1c82669249763e1c76fd60f49f0 : 4 +------------------------------------------ + ** Merging topic branch: tech/all/config/tech/all/config +Merge successful : tech/all/config : aa56c495865001bd138f511336954990b328f7c7 : 27 +------------------------------------------ + ** Merging topic branch: tech/overlay/dt/tech/overlay/dt +Merge failed, manual merge +No files need merging +[qcom-next d538862b7e35] Merge remote-tracking branch tech/overlay/dt into qcom-next +Merge successful : tech/overlay/dt : 03e0b7b70b8df2b6b498a1f7ed565c2bc4a0833b : 5 +------------------------------------------ + ** Merging topic branch: tech/all/workaround/tech/all/workaround +Merge failed, manual merge +No files need merging +[qcom-next cc1847f31cba] Merge remote-tracking branch tech/all/workaround into qcom-next +Merge successful : tech/all/workaround : 841239d0dc8294a4a9bb5f63b3f4c0dbcf21247f : 3 +Done, merged 37 topic(s). +[main c1f8173] New rr-cache entries from ci-merge + 2 files changed, 225 insertions(+) + create mode 100644 rr-cache/47353e0ce93cdc0c4e304da7b4ba1e43424984fa/thisimage diff --git a/qcom-next/topic_SHA1 b/qcom-next/topic_SHA1 new file mode 100644 index 0000000000000..1731165d81d1c --- /dev/null +++ b/qcom-next/topic_SHA1 @@ -0,0 +1,39 @@ +Name SHA Commits +------------------------------------------------------------------------------------ +tech/bsp/clk aea4f0c77e2524664061c3756cf8cadccec41145 8 +tech/bsp/interconnect 938409e3faa500839cfe2db3a2e3becfd9fb7fc6 2 +tech/security/firmware-smc 829c78b71ef815f34cfadc407ddf7438d396ef1d 1 +tech/bsp/soc-infra 797d5a2c99ee52b6fdbafcd0862e867d151c0539 18 +tech/bsp/pinctrl 9a297f4d9e88c69bd9a650364126da4d2dbb658f 2 +tech/bsp/remoteproc 806913442c1fd5fc6195a904f574a334df280b80 12 +tech/bus/pci/all 4490847265d4793f82a141c92a05f536ed00f2b5 7 +tech/bus/pci/pwrctl c36944ebc50ed5d40b3c550cbe5792b93c32dc27 7 +tech/bus/usb/dwc c29f570c16249b9ae1472b08a3570f2985fa5532 1 +tech/debug/eud eb36d9dbce445b0a2032775a5668ba02dd4b67cb 1 +tech/debug/hwtracing 961640988eb239085e7643c0ec26e627d8389049 34 +tech/pmic/misc 2803dee8e1259a136907758bd0947a1fc63f6451 8 +tech/pmic/regulator 81fc8fbf0f0a02a7b2d855aee574b88bd7d59107 6 +tech/mem/iommu fc1b59c1f4305fd3630a4205d2db8f680626ef5c 1 +tech/mm/audio/all 553419127a35c4d857a1d9a6fe68c2b4d23cac48 2 +tech/mm/camss d1d2c38f53e8f67b6a11866d4202561fbed0a988 3 +tech/mm/drm 0d74e4315149eb9dbcd4d3150bc1a37b220cab5e 39 +tech/mm/fastrpc dba4eb255febb4cc38d2e340978c58f8f21ff6cc 3 +tech/mm/video 1af1bf9935671af7c556b7e952a9afd2def6a58d 13 +tech/mm/gpu 229115a988e2a9ac5c6dcbf06e396be043b81592 4 +tech/net/eth c280d7e86faa86b16d3c1e313e95207503cf3770 1 +tech/net/bluetooth b5902f2daf61ad3eed61a9fbf3d75ba3748cf53e 2 +tech/pm/pmdomain c2e58ee4e1ed72c4fe6fb6a48d8d83d4ea2269fc 3 +tech/pm/power 9fe45cfe84f7873accec2689b312180897cb56d0 7 +tech/security/crypto 0ff2ae7f2e708a083b489a9a4a34c07bd701aec1 11 +tech/security/ice e6140349dfc670e22f2507bb8f053be15b353ddd 3 +tech/storage/all ba8c93ddc42883a8b91db3e5fd0f19d0c79a9ddb 6 +tech/all/dt/qcs6490 91a5f259df1c65b4981c51e7d825a26617afbd50 7 +tech/all/dt/qcs9100 ae04b95f30a6b56d2bbbf59fdb94d45e2be7d0f9 15 +tech/all/dt/qcs8300 32998bbef522f5cb37374467b732d89442bcfdc6 26 +tech/all/dt/qcs615 ac047bf2fb68a45c0708be88eb78482f1b5278f3 8 +tech/all/dt/hamoa 85bf4e6cc25178294e99ce9ec8885395ed820178 7 +tech/all/dt/kaanapali 746a2029c703df8d18c3b3209cd1cb635a2abd92 3 +tech/all/dt/pakala e0326f1e866dc1c82669249763e1c76fd60f49f0 4 +tech/all/config aa56c495865001bd138f511336954990b328f7c7 27 +tech/overlay/dt 03e0b7b70b8df2b6b498a1f7ed565c2bc4a0833b 5 +tech/all/workaround 841239d0dc8294a4a9bb5f63b3f4c0dbcf21247f 3 From ff91616e507e7c77bc374b9342eb3c6389f99746 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Thu, 4 Dec 2025 09:41:58 +0530 Subject: [PATCH 65/67] FROMLIST: arm64: dts: qcom: monaco-evk: Enable AMC6821 fan controller Enable AMC6821 fan controller for monaco-evk platform and configure pwm polarity as inverted. Signed-off-by: Gaurav Kohli Link: https://lore.kernel.org/r/20251204041158.2613340-1-gaurav.kohli@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/monaco-evk.dts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts index 4b3e00444c331..697a30a9a4755 100644 --- a/arch/arm64/boot/dts/qcom/monaco-evk.dts +++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts @@ -6,6 +6,7 @@ /dts-v1/; #include +#include #include #include @@ -418,6 +419,16 @@ status = "okay"; + fan_controller: fan@18 { + compatible = "ti,amc6821"; + reg = <0x18>; + #pwm-cells = <2>; + + fan { + pwms = <&fan_controller 40000 PWM_POLARITY_INVERTED>; + }; + }; + eeprom0: eeprom@50 { compatible = "atmel,24c256"; reg = <0x50>; From 763d814cc46a5a6ae6645360712e8a2cb5416f8b Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Mon, 8 Dec 2025 17:15:58 +0530 Subject: [PATCH 66/67] FROMLIST: arm64: dts: qcom: monaco: Enable cpufreq cooling devices Add cooling-cells property to the CPU nodes to support cpufreq cooling devices. Signed-off-by: Gaurav Kohli Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251208114558.2343462-1-gaurav.kohli@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 515512a79fd73..44b18be1bbd8a 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -56,6 +56,7 @@ power-domain-names = "psci"; capacity-dmips-mhz = <1946>; dynamic-power-coefficient = <472>; + #cooling-cells = <2>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -80,6 +81,7 @@ power-domains = <&cpu_pd1>; power-domain-names = "psci"; capacity-dmips-mhz = <1946>; + #cooling-cells = <2>; dynamic-power-coefficient = <472>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; @@ -105,6 +107,7 @@ power-domains = <&cpu_pd2>; power-domain-names = "psci"; capacity-dmips-mhz = <1946>; + #cooling-cells = <2>; dynamic-power-coefficient = <507>; qcom,freq-domain = <&cpufreq_hw 2>; operating-points-v2 = <&cpu2_opp_table>; @@ -130,6 +133,7 @@ power-domains = <&cpu_pd3>; power-domain-names = "psci"; capacity-dmips-mhz = <1946>; + #cooling-cells = <2>; dynamic-power-coefficient = <507>; qcom,freq-domain = <&cpufreq_hw 2>; operating-points-v2 = <&cpu2_opp_table>; @@ -155,6 +159,7 @@ power-domains = <&cpu_pd4>; power-domain-names = "psci"; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; @@ -180,6 +185,7 @@ power-domains = <&cpu_pd5>; power-domain-names = "psci"; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; @@ -205,6 +211,7 @@ power-domains = <&cpu_pd6>; power-domain-names = "psci"; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; @@ -230,6 +237,7 @@ power-domains = <&cpu_pd7>; power-domain-names = "psci"; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; From de0747b1fc26ed5c1b784dd7ba5f56c76a407312 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Mon, 15 Dec 2025 10:24:51 +0530 Subject: [PATCH 67/67] FROMLIST: arm64: dts: qcom: lemans: Enable cpufreq cooling devices Add cooling-cells property to the CPU nodes to support cpufreq cooling devices. Signed-off-by: Gaurav Kohli Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251215045451.3150894-1-gaurav.kohli@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/lemans.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index 8b77e2a5ef01f..fc9ebf7d2cf0b 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -55,6 +55,7 @@ qcom,freq-domain = <&cpufreq_hw 0>; next-level-cache = <&l2_0>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -84,6 +85,7 @@ qcom,freq-domain = <&cpufreq_hw 0>; next-level-cache = <&l2_1>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -108,6 +110,7 @@ qcom,freq-domain = <&cpufreq_hw 0>; next-level-cache = <&l2_2>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -132,6 +135,7 @@ qcom,freq-domain = <&cpufreq_hw 0>; next-level-cache = <&l2_3>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -156,6 +160,7 @@ qcom,freq-domain = <&cpufreq_hw 1>; next-level-cache = <&l2_4>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -186,6 +191,7 @@ qcom,freq-domain = <&cpufreq_hw 1>; next-level-cache = <&l2_5>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -210,6 +216,7 @@ qcom,freq-domain = <&cpufreq_hw 1>; next-level-cache = <&l2_6>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -234,6 +241,7 @@ qcom,freq-domain = <&cpufreq_hw 1>; next-level-cache = <&l2_7>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; dynamic-power-coefficient = <100>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY