* [PATCH v4 1/6] dt-bindings: i2c: qcom,i2c-cci: Add Hawi compatible
2026-11-06 6:50 [PATCH v4 0/6] Add CAMSS support for Qualcomm Hawi and Maili Nihal Kumar Gupta
@ 2026-11-06 6:50 ` Nihal Kumar Gupta
2026-11-06 6:57 ` sashiko-bot
2026-11-06 6:50 ` [PATCH v4 2/6] dt-bindings: phy: qcom,x1e80100-csi2-phy: Add Hawi and Maili compatibles Nihal Kumar Gupta
` (4 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Nihal Kumar Gupta @ 2026-11-06 6:50 UTC (permalink / raw)
To: Loic Poulain, Robert Foss, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bryan O'Donoghue,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
Vladimir Zapolskiy, Mauro Carvalho Chehab, Hangxiang Ma,
Nihal Kumar Gupta, Bryan O'Donoghue
Cc: Suresh Vankadara, Vikram Sharma, linux-i2c, linux-arm-msm,
devicetree, linux-kernel, linux-phy, linux-media,
Krzysztof Kozlowski
From: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
Document the Camera Control Interface (CCI) compatible for the Qualcomm
Hawi platform. Like other recent platforms it requires two clocks, so
add it to the corresponding clocks constraint as well.
Reviewed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
index 1e8def25ec0ec1ef6b34859709d10a2a36fe36f5..b2b4d4bcf780792515ec153c873bace1764fb3e3 100644
--- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
+++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
@@ -27,6 +27,7 @@ properties:
- items:
- enum:
- qcom,glymur-cci
+ - qcom,hawi-cci
- qcom,kaanapali-cci
- qcom,milos-cci
- qcom,qcm2290-cci
@@ -137,6 +138,7 @@ allOf:
contains:
enum:
- qcom,glymur-cci
+ - qcom,hawi-cci
- qcom,kaanapali-cci
- qcom,qcm2290-cci
- qcom,qcs8300-cci
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v4 1/6] dt-bindings: i2c: qcom,i2c-cci: Add Hawi compatible
2026-11-06 6:50 ` [PATCH v4 1/6] dt-bindings: i2c: qcom,i2c-cci: Add Hawi compatible Nihal Kumar Gupta
@ 2026-11-06 6:57 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-11-06 6:57 UTC (permalink / raw)
To: Nihal Kumar Gupta
Cc: devicetree, linux-phy, robh, conor+dt, media-ci, vkoul,
neil.armstrong, olteanv
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Medium] dt-bindings: i2c: qcom,hawi-cci falls back to
qcom,msm8996-cci
--
commit eeb66a38f27dd112905efa0a186dff7682ef33dd
Author: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
dt-bindings: i2c: qcom,i2c-cci: Add Hawi compatible
This commit documents the qcom,hawi-cci compatible string and its
two-clock requirement in the Qualcomm CCI I2C binding.
> diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
> index 1e8def25ec0ec..b2b4d4bcf7807 100644
> --- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
> +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
> @@ -27,6 +27,7 @@ properties:
> - items:
> - enum:
> - qcom,glymur-cci
> + - qcom,hawi-cci
> - qcom,kaanapali-cci
> - qcom,milos-cci
> - qcom,qcm2290-cci
[Severity: Medium]
As reported by Loic Poulain on RFC [1], should qcom,hawi-cci stop falling
back to qcom,msm8996-cci and use a dedicated variant entry instead?
Placing qcom,hawi-cci in the qcom,msm8996-cci fallback list without a
dedicated entry in cci_dt_match[] causes cci_probe() to bind Hawi CCI
controllers to the legacy cci_v2_data configuration (queue_size = { 64, 16 }
and max_write_len = 11) rather than matching the newer IP revision's FIFO
and queue sizes.
[1] https://lore.kernel.org/r/CAFEp6-1Zvt0hhBd7LNx2hsyi9J+bxCT8EWN3jZ4B30SO58SCow@mail.gmail.com
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261106-hawi-maili-camss-v4-0-d528c7a797b4@oss.qualcomm.com?part=1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 2/6] dt-bindings: phy: qcom,x1e80100-csi2-phy: Add Hawi and Maili compatibles
2026-11-06 6:50 [PATCH v4 0/6] Add CAMSS support for Qualcomm Hawi and Maili Nihal Kumar Gupta
2026-11-06 6:50 ` [PATCH v4 1/6] dt-bindings: i2c: qcom,i2c-cci: Add Hawi compatible Nihal Kumar Gupta
@ 2026-11-06 6:50 ` Nihal Kumar Gupta
2026-11-06 6:50 ` [PATCH v4 3/6] dt-bindings: media: Add CAMSS device for Hawi and Maili Nihal Kumar Gupta
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Nihal Kumar Gupta @ 2026-11-06 6:50 UTC (permalink / raw)
To: Loic Poulain, Robert Foss, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bryan O'Donoghue,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
Vladimir Zapolskiy, Mauro Carvalho Chehab, Hangxiang Ma,
Nihal Kumar Gupta, Bryan O'Donoghue
Cc: Suresh Vankadara, Vikram Sharma, linux-i2c, linux-arm-msm,
devicetree, linux-kernel, linux-phy, linux-media,
Krzysztof Kozlowski
Hawi and Maili integrate the same CSIPHY IP as Kaanapali with an
identical register interface. Add qcom,hawi-csi2-phy and
qcom,maili-csi2-phy falling back to qcom,hawi-csi2-phy.
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Co-developed-by: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
Signed-off-by: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml
index 6e9eb8e265df93b631101ae13f31f6365b6239b6..627aebc7cd9b7ca313457d3f70f72796e9671e8a 100644
--- a/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml
@@ -18,11 +18,16 @@ properties:
compatible:
oneOf:
- enum:
+ - qcom,hawi-csi2-phy
- qcom,kaanapali-csi2-phy
- qcom,x1e80100-csi2-phy
- items:
- const: qcom,glymur-csi2-phy
- const: qcom,x1e80100-csi2-phy
+ - items:
+ - enum:
+ - qcom,maili-csi2-phy
+ - const: qcom,hawi-csi2-phy
reg:
maxItems: 1
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v4 3/6] dt-bindings: media: Add CAMSS device for Hawi and Maili
2026-11-06 6:50 [PATCH v4 0/6] Add CAMSS support for Qualcomm Hawi and Maili Nihal Kumar Gupta
2026-11-06 6:50 ` [PATCH v4 1/6] dt-bindings: i2c: qcom,i2c-cci: Add Hawi compatible Nihal Kumar Gupta
2026-11-06 6:50 ` [PATCH v4 2/6] dt-bindings: phy: qcom,x1e80100-csi2-phy: Add Hawi and Maili compatibles Nihal Kumar Gupta
@ 2026-11-06 6:50 ` Nihal Kumar Gupta
2026-11-06 6:50 ` [PATCH v4 4/6] phy: qcom-mipi-csi2: Add Hawi support Nihal Kumar Gupta
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Nihal Kumar Gupta @ 2026-11-06 6:50 UTC (permalink / raw)
To: Loic Poulain, Robert Foss, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bryan O'Donoghue,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
Vladimir Zapolskiy, Mauro Carvalho Chehab, Hangxiang Ma,
Nihal Kumar Gupta, Bryan O'Donoghue
Cc: Suresh Vankadara, Vikram Sharma, linux-i2c, linux-arm-msm,
devicetree, linux-kernel, linux-phy, linux-media
From: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
Add bindings for Camera Subsystem (CAMSS) on the Qualcomm Hawi platform.
The Hawi platform provides:
- 6 x CSIPHY (CSI Physical Layer)
- 3 x TPG (Test Pattern Generator)
- 3 x CSID (CSI Decoder)
- 2 x CSID Lite
- 3 x VFE (Video Front End), 5 RDI per VFE
- 2 x VFE Lite, 4 RDI per VFE Lite
Signed-off-by: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
Co-developed-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
.../devicetree/bindings/media/qcom,hawi-camss.yaml | 317 +++++++++++++++++++++
1 file changed, 317 insertions(+)
diff --git a/Documentation/devicetree/bindings/media/qcom,hawi-camss.yaml b/Documentation/devicetree/bindings/media/qcom,hawi-camss.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..22629064ed7132cd19b7b0521ebd7c33d79a1417
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/qcom,hawi-camss.yaml
@@ -0,0 +1,317 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/qcom,hawi-camss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Hawi and Maili Camera Subsystem (CAMSS)
+
+maintainers:
+ - Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
+ - Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
+
+description:
+ The CAMSS IP is a CSI decoder and ISP present on Qualcomm platforms.
+
+properties:
+ compatible:
+ oneOf:
+ - const: qcom,hawi-camss
+ - items:
+ - const: qcom,maili-camss
+ - const: qcom,hawi-camss
+
+ reg:
+ maxItems: 14
+
+ reg-names:
+ items:
+ - const: top
+ - const: csid0
+ - const: csid1
+ - const: csid2
+ - const: csid_lite0
+ - const: csid_lite1
+ - const: tpg0
+ - const: tpg1
+ - const: tpg2
+ - const: vfe0
+ - const: vfe1
+ - const: vfe2
+ - const: vfe_lite0
+ - const: vfe_lite1
+
+ clocks:
+ maxItems: 26
+
+ clock-names:
+ items:
+ - const: camnoc_nrt_axi
+ - const: camnoc_rt_axi
+ - const: camnoc_dcd_xo
+ - const: cpas_ahb
+ - const: cpas_fast_ahb
+ - const: cpas_mnoc_hf
+ - const: cpas_mnoc_sf
+ - const: cpas_vfe0
+ - const: cpas_vfe1
+ - const: cpas_vfe2
+ - const: cpas_vfe_lite
+ - const: csid
+ - const: csiphy_rx
+ - const: gcc_axi_hf
+ - const: gcc_axi_sf
+ - const: vfe0
+ - const: vfe0_fast_ahb
+ - const: vfe1
+ - const: vfe1_fast_ahb
+ - const: vfe2
+ - const: vfe2_fast_ahb
+ - const: vfe_lite
+ - const: vfe_lite_ahb
+ - const: vfe_lite_cphy_rx
+ - const: vfe_lite_csid
+ - const: qdss_debug_xo
+
+ interrupts:
+ maxItems: 10
+
+ interrupt-names:
+ items:
+ - const: csid0
+ - const: csid1
+ - const: csid2
+ - const: csid_lite0
+ - const: csid_lite1
+ - const: vfe0
+ - const: vfe1
+ - const: vfe2
+ - const: vfe_lite0
+ - const: vfe_lite1
+
+ interconnects:
+ maxItems: 2
+
+ interconnect-names:
+ items:
+ - const: ahb
+ - const: hf_mnoc
+
+ iommus:
+ items:
+ - description: S1 HLOS IFE and IFE_LITE non-protected stream
+
+ power-domains:
+ items:
+ - description: IFE0 GDSC - Global Distributed Switch Controller for IFE0.
+ - description: IFE1 GDSC - Global Distributed Switch Controller for IFE1.
+ - description: IFE2 GDSC - Global Distributed Switch Controller for IFE2.
+ - description: Titan GDSC - Global Distributed Switch Controller for the entire camss.
+
+ power-domain-names:
+ items:
+ - const: ife0
+ - const: ife1
+ - const: ife2
+ - const: top
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ description:
+ CSI input ports.
+
+ patternProperties:
+ "^port@[0-5]$":
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description:
+ Input ports for receiving CSI data on CSIPHY 0-5.
+
+ properties:
+ endpoint:
+ $ref: video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ minItems: 1
+ maxItems: 4
+
+ bus-type:
+ enum:
+ - 1 # MEDIA_BUS_TYPE_CSI2_CPHY
+ - 4 # MEDIA_BUS_TYPE_CSI2_DPHY
+
+ required:
+ - data-lanes
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - clocks
+ - clock-names
+ - interrupts
+ - interrupt-names
+ - interconnects
+ - interconnect-names
+ - iommus
+ - power-domains
+ - power-domain-names
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,hawi-gcc.h>
+ #include <dt-bindings/clock/qcom,hawi-camcc.h>
+ #include <dt-bindings/interconnect/qcom,icc.h>
+ #include <dt-bindings/interconnect/qcom,hawi-rpmh.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/power/qcom,rpmhpd.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ isp@900b000 {
+ compatible = "qcom,hawi-camss";
+
+ reg = <0x0 0x0900b000 0x0 0x1000>,
+ <0x0 0x09253000 0x0 0x5e80>,
+ <0x0 0x09263000 0x0 0x5e80>,
+ <0x0 0x09273000 0x0 0x5e80>,
+ <0x0 0x092d3000 0x0 0x3880>,
+ <0x0 0x092e7000 0x0 0x3880>,
+ <0x0 0x093fd000 0x0 0x400>,
+ <0x0 0x093fe000 0x0 0x400>,
+ <0x0 0x093ff000 0x0 0x400>,
+ <0x0 0x09151000 0x0 0x20000>,
+ <0x0 0x09171000 0x0 0x20000>,
+ <0x0 0x09191000 0x0 0x20000>,
+ <0x0 0x092dc000 0x0 0x6800>,
+ <0x0 0x092f0000 0x0 0x6800>;
+ reg-names = "top",
+ "csid0",
+ "csid1",
+ "csid2",
+ "csid_lite0",
+ "csid_lite1",
+ "tpg0",
+ "tpg1",
+ "tpg2",
+ "vfe0",
+ "vfe1",
+ "vfe2",
+ "vfe_lite0",
+ "vfe_lite1";
+
+ clocks = <&camcc CAM_CC_CAMNOC_NRT_AXI_CLK>,
+ <&camcc CAM_CC_CAMNOC_RT_AXI_CLK>,
+ <&camcc CAM_CC_CAMNOC_DCD_XO_CLK>,
+ <&camcc CAM_CC_CAM_TOP_AHB_CLK>,
+ <&camcc CAM_CC_CAM_TOP_FAST_AHB_CLK>,
+ <&camcc CAM_CC_TITAN_MNOC_HF_CLK>,
+ <&camcc CAM_CC_TITAN_MNOC_SF_CLK>,
+ <&camcc CAM_CC_CAMNOC_RT_TFE_0_MAIN_CLK>,
+ <&camcc CAM_CC_CAMNOC_RT_TFE_1_MAIN_CLK>,
+ <&camcc CAM_CC_CAMNOC_RT_TFE_2_MAIN_CLK>,
+ <&camcc CAM_CC_CAMNOC_RT_IFE_LITE_CLK>,
+ <&camcc CAM_CC_CSID_CLK>,
+ <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>,
+ <&gcc GCC_CAMERA_HF_AXI_CLK>,
+ <&gcc GCC_CAMERA_SF_AXI_CLK>,
+ <&camcc CAM_CC_TFE_0_MAIN_CLK>,
+ <&camcc CAM_CC_TFE_0_MAIN_FAST_AHB_CLK>,
+ <&camcc CAM_CC_TFE_1_MAIN_CLK>,
+ <&camcc CAM_CC_TFE_1_MAIN_FAST_AHB_CLK>,
+ <&camcc CAM_CC_TFE_2_MAIN_CLK>,
+ <&camcc CAM_CC_TFE_2_MAIN_FAST_AHB_CLK>,
+ <&camcc CAM_CC_IFE_LITE_CLK>,
+ <&camcc CAM_CC_IFE_LITE_AHB_CLK>,
+ <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>,
+ <&camcc CAM_CC_IFE_LITE_CSID_CLK>,
+ <&camcc CAM_CC_QDSS_DEBUG_XO_CLK>;
+ clock-names = "camnoc_nrt_axi",
+ "camnoc_rt_axi",
+ "camnoc_dcd_xo",
+ "cpas_ahb",
+ "cpas_fast_ahb",
+ "cpas_mnoc_hf",
+ "cpas_mnoc_sf",
+ "cpas_vfe0",
+ "cpas_vfe1",
+ "cpas_vfe2",
+ "cpas_vfe_lite",
+ "csid",
+ "csiphy_rx",
+ "gcc_axi_hf",
+ "gcc_axi_sf",
+ "vfe0",
+ "vfe0_fast_ahb",
+ "vfe1",
+ "vfe1_fast_ahb",
+ "vfe2",
+ "vfe2_fast_ahb",
+ "vfe_lite",
+ "vfe_lite_ahb",
+ "vfe_lite_cphy_rx",
+ "vfe_lite_csid",
+ "qdss_debug_xo";
+
+ interrupts = <GIC_SPI 601 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 603 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 431 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 605 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 376 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 433 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 436 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 457 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 606 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 377 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "csid0",
+ "csid1",
+ "csid2",
+ "csid_lite0",
+ "csid_lite1",
+ "vfe0",
+ "vfe1",
+ "vfe2",
+ "vfe_lite0",
+ "vfe_lite1";
+
+ interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY
+ &config_noc SLAVE_CAMERA_CFG QCOM_ICC_TAG_ACTIVE_ONLY>,
+ <&mmss_noc MASTER_CAMNOC_HF QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
+ interconnect-names = "ahb",
+ "hf_mnoc";
+
+ iommus = <&apps_smmu 0x1800 0x00>;
+
+ power-domains = <&camcc CAM_CC_TFE_0_GDSC>,
+ <&camcc CAM_CC_TFE_1_GDSC>,
+ <&camcc CAM_CC_TFE_2_GDSC>,
+ <&camcc CAM_CC_TITAN_TOP_GDSC>;
+ power-domain-names = "ife0",
+ "ife1",
+ "ife2",
+ "top";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ camss_csiphy0_ep: endpoint {
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&csiphy0_out>;
+ };
+ };
+ };
+ };
+ };
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v4 4/6] phy: qcom-mipi-csi2: Add Hawi support
2026-11-06 6:50 [PATCH v4 0/6] Add CAMSS support for Qualcomm Hawi and Maili Nihal Kumar Gupta
` (2 preceding siblings ...)
2026-11-06 6:50 ` [PATCH v4 3/6] dt-bindings: media: Add CAMSS device for Hawi and Maili Nihal Kumar Gupta
@ 2026-11-06 6:50 ` Nihal Kumar Gupta
2026-11-06 6:50 ` [PATCH v4 5/6] media: qcom: camss: csid: Scale the clocks with the CSI-2 link rate Nihal Kumar Gupta
2026-11-06 6:50 ` [PATCH v4 6/6] media: qcom: camss: Add support for Hawi Nihal Kumar Gupta
5 siblings, 0 replies; 9+ messages in thread
From: Nihal Kumar Gupta @ 2026-11-06 6:50 UTC (permalink / raw)
To: Loic Poulain, Robert Foss, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bryan O'Donoghue,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
Vladimir Zapolskiy, Mauro Carvalho Chehab, Hangxiang Ma,
Nihal Kumar Gupta, Bryan O'Donoghue
Cc: Suresh Vankadara, Vikram Sharma, linux-i2c, linux-arm-msm,
devicetree, linux-kernel, linux-phy, linux-media
From: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
Add support for the Hawi 2nm CSI-2 D-PHY.
Reuse the Kaanapali lane table and adjust the data-lane CTRL0 value
from 0x8e to 0x8c for Hawi-specific tuning. This prevents potential
stream stalls and SMMU faults.
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Reviewed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Signed-off-by: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c | 136 +++++++++++++++++++++
drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c | 1 +
drivers/phy/qualcomm/phy-qcom-mipi-csi2.h | 1 +
3 files changed, 138 insertions(+)
diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
index ed40934d67eaeba0c6ac7ac75324ac6292fe7d9e..5d91303e0df2e8c5bca3ea8fa2bb831429a8f1ff 100644
--- a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
+++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-3ph-dphy.c
@@ -162,6 +162,126 @@ mipi_csi2phy_lane_regs lane_regs_x1e80100[] = {
{.reg_addr = 0x0c64, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL},
};
+/* 2nm 2PH 2p5Gbps 4 lane DPHY mode, Kaanapali table with data-lane CTRL0 0x8c */
+static const struct mipi_csi2phy_lane_regs lane_regs_hawi[] = {
+ /* Power up lanes in 2ph mode. */
+ { .reg_addr = 0x101c, .reg_data = 0x7a, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x1018, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS },
+
+ { .reg_addr = 0x0094, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x00a0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0090, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0098, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0094, .reg_data = 0x07, .delay_us = 1,
+ .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0030, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0000, .reg_data = 0x8c, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0038, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x002c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0034, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x001c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0014, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x003c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0004, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0020, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0008, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE },
+ { .reg_addr = 0x0010, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0094, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x005c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x0060, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x0064, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL },
+
+ { .reg_addr = 0x0e94, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0ea0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e90, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e98, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e94, .reg_data = 0x07, .delay_us = 1,
+ .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e30, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e28, .reg_data = 0x04, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e00, .reg_data = 0x80, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e0c, .reg_data = 0xff, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e38, .reg_data = 0x1f, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e2c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e34, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e1c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e14, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e3c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e04, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e20, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0e08, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE },
+ { .reg_addr = 0x0e10, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS },
+
+ { .reg_addr = 0x0494, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x04a0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0490, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0498, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0494, .reg_data = 0x07, .delay_us = 1,
+ .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0430, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0400, .reg_data = 0x8c, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0438, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x042c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0434, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x041c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0414, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x043c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0404, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0420, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0408, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE },
+ { .reg_addr = 0x0410, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0494, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x045c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x0460, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x0464, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL },
+
+ { .reg_addr = 0x0894, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x08a0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0890, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0898, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0894, .reg_data = 0x07, .delay_us = 1,
+ .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0830, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0800, .reg_data = 0x8c, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0838, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x082c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0834, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x081c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0814, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x083c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0804, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0820, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0808, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE },
+ { .reg_addr = 0x0810, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0894, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x085c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x0860, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x0864, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL },
+
+ { .reg_addr = 0x0c94, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0ca0, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c90, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c98, .reg_data = 0x08, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c94, .reg_data = 0x07, .delay_us = 1,
+ .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c30, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c00, .reg_data = 0x8c, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c38, .reg_data = 0xfe, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c2c, .reg_data = 0x01, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c34, .reg_data = 0x0f, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c1c, .reg_data = 0x0a, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c14, .reg_data = 0x60, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c3c, .reg_data = 0xb8, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c04, .reg_data = 0x0c, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c20, .reg_data = 0x00, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c08, .reg_data = 0x10, .param_type = CSIPHY_SETTLE_CNT_LOWER_BYTE },
+ { .reg_addr = 0x0c10, .reg_data = 0x52, .param_type = CSIPHY_DEFAULT_PARAMS },
+ { .reg_addr = 0x0c94, .reg_data = 0xd7, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x0c5c, .reg_data = 0x00, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x0c60, .reg_data = 0xbd, .param_type = CSIPHY_SKEW_CAL },
+ { .reg_addr = 0x0c64, .reg_data = 0x7f, .param_type = CSIPHY_SKEW_CAL },
+};
+
static inline const struct mipi_csi2phy_device_regs *
csi2phy_dev_to_regs(struct mipi_csi2phy_device *csi2phy)
{
@@ -374,6 +494,22 @@ static struct mipi_csi2_genpd x1e_genpds[] = {
{ .name = "mx", .scaled = true },
};
+const struct mipi_csi2phy_soc_cfg mipi_csi2_dphy_2nm_hawi = {
+ .ops = &phy_qcom_mipi_csi2_ops_3ph_1_0,
+ .reg_info = {
+ .init_seq = lane_regs_hawi,
+ .lane_array_size = ARRAY_SIZE(lane_regs_hawi),
+ .common_regs_offset = 0x1000,
+ .common_status_offset = 0x138,
+ },
+ .supply_names = (const char **)x1e_supplies,
+ .num_supplies = ARRAY_SIZE(x1e_supplies),
+ .clk_names = (const char **)x1e_clks,
+ .num_clk = ARRAY_SIZE(x1e_clks),
+ .genpds = x1e_genpds,
+ .num_genpds = ARRAY_SIZE(x1e_genpds),
+};
+
const struct mipi_csi2phy_soc_cfg mipi_csi2_dphy_3nm_kaanapali = {
.ops = &phy_qcom_mipi_csi2_ops_3ph_1_0,
.reg_info = {
diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c
index 941f8b920b1d632edfc4c35d1f9e22bdc1811d18..54e3135cec5c3b534aa081d790ffae480a6675d4 100644
--- a/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c
+++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2-core.c
@@ -443,6 +443,7 @@ static int phy_qcom_mipi_csi2_probe(struct platform_device *pdev)
}
static const struct of_device_id phy_qcom_mipi_csi2_of_match_table[] = {
+ { .compatible = "qcom,hawi-csi2-phy", .data = &mipi_csi2_dphy_2nm_hawi },
{ .compatible = "qcom,kaanapali-csi2-phy", .data = &mipi_csi2_dphy_3nm_kaanapali },
{ .compatible = "qcom,x1e80100-csi2-phy", .data = &mipi_csi2_dphy_4nm_x1e },
{ }
diff --git a/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h b/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
index 832c8d048b77f6c821180244220904815be756d5..01636df3c07dda9ca9c7e37c0bfd892bbb6a1304 100644
--- a/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
+++ b/drivers/phy/qualcomm/phy-qcom-mipi-csi2.h
@@ -93,6 +93,7 @@ struct mipi_csi2phy_device {
u32 hw_version;
};
+extern const struct mipi_csi2phy_soc_cfg mipi_csi2_dphy_2nm_hawi;
extern const struct mipi_csi2phy_soc_cfg mipi_csi2_dphy_3nm_kaanapali;
extern const struct mipi_csi2phy_soc_cfg mipi_csi2_dphy_4nm_x1e;
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v4 5/6] media: qcom: camss: csid: Scale the clocks with the CSI-2 link rate
2026-11-06 6:50 [PATCH v4 0/6] Add CAMSS support for Qualcomm Hawi and Maili Nihal Kumar Gupta
` (3 preceding siblings ...)
2026-11-06 6:50 ` [PATCH v4 4/6] phy: qcom-mipi-csi2: Add Hawi support Nihal Kumar Gupta
@ 2026-11-06 6:50 ` Nihal Kumar Gupta
2026-11-06 6:50 ` [PATCH v4 6/6] media: qcom: camss: Add support for Hawi Nihal Kumar Gupta
5 siblings, 0 replies; 9+ messages in thread
From: Nihal Kumar Gupta @ 2026-11-06 6:50 UTC (permalink / raw)
To: Loic Poulain, Robert Foss, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bryan O'Donoghue,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
Vladimir Zapolskiy, Mauro Carvalho Chehab, Hangxiang Ma,
Nihal Kumar Gupta, Bryan O'Donoghue
Cc: Suresh Vankadara, Vikram Sharma, linux-i2c, linux-arm-msm,
devicetree, linux-kernel, linux-phy, linux-media
From: Loic Poulain <loic.poulain@oss.qualcomm.com>
Only the gen1 "csiN" clocks are scaled with the link rate of the sensor,
the CSID core and CSIPHY receive clocks of all the other SoCs are set to
the first rate of the resource table. A SoC can therefore only be
described for one sensor bandwidth: the lowest rate first breaks fast
sensors, the highest one burns power with the slow ones.
Compute the minimum rate from the link frequency for all generations.
The CSIPHY passes each D-PHY lane to the CSID over an 8 bit wide
interface clocked by the receive clock, so that clock has to run at the
per lane bit rate divided by 8, which is link_freq / 4. The core clock
must not be slower, hence the same minimum for it and the cap of the
receive clock at the core rate. The clocks are matched by suffix and
voted for with clk_set_rate_range(), as the CSIDs of the recent SoCs
share them.
Up to 1.8 Gbps/lane the selected rates are unchanged on every supported
SoC.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
drivers/media/platform/qcom/camss/camss-csid.c | 208 ++++++++++++++++++++-----
1 file changed, 169 insertions(+), 39 deletions(-)
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index a00791b00feb79bcdea7dccf6d1d120f01a8c485..26d754d72b66747abfa02fbbe3f2b2bd662b6d40 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/string.h>
#include <media/media-entity.h>
#include <media/mipi-csi2.h>
#include <media/v4l2-device.h>
@@ -532,72 +533,197 @@ const struct csid_format_info *csid_get_fmt_entry(const struct csid_format_info
return &formats[0];
}
+/* Match the core clock of the CSID */
+static bool csid_match_core_clock_name(struct camss_clock *clock)
+{
+ /* "csid", "vfe0_csid", "vfe_lite_csid", ... */
+ if (strends(clock->name, "csid"))
+ return true;
+
+ /* Named after the CSI port on the SoCs with a gen1 CSID */
+ return !strcmp(clock->name, "csi0") || !strcmp(clock->name, "csi1") ||
+ !strcmp(clock->name, "csi2") || !strcmp(clock->name, "csi3");
+}
+
+/* Match the clock of the CSIPHY to CSID interface */
+static bool csid_match_phy_rx_clock_name(struct camss_clock *clock)
+{
+ /* "csiphy_rx", "csid_csiphy_rx", "vfe0_cphy_rx", ... */
+ return strends(clock->name, "phy_rx");
+}
+
+/* Match a clock whose rate depends on the CSI-2 link rate */
+static bool csid_match_scaled_clock_name(struct camss_clock *clock)
+{
+ return csid_match_core_clock_name(clock) ||
+ csid_match_phy_rx_clock_name(clock);
+}
+
/*
- * csid_set_clock_rates - Calculate and set clock rates on CSID module
- * @csiphy: CSID device
+ * csid_get_min_clock_rate - Get the rate the CSI-2 link requires
+ * @csid: CSID device
+ *
+ * The CSIPHY deserialises every D-PHY data lane into bytes and passes them to
+ * the CSID over an interface which is, as per the CSID HPG, 8 bits wide per
+ * lane and clocked by the CSIPHY receive clock. That clock has to run at the
+ * per lane bit rate divided by 8 at the very least. The link frequency is the
+ * DDR clock of the link, i.e. half the per lane bit rate, which makes the
+ * minimum rate link_freq / 4.
+ *
+ * Qualcomm recommends clocking the CSID core at least as fast as the CSIPHY
+ * receive clock feeding it, so the same minimum applies to the core clock.
+ *
+ * C-PHY maps 16 bits onto 7 symbols and needs a different ratio, but CAMSS
+ * does not support it so far.
+ *
+ * Return the minimum rate in Hz, clock margin included, or 0 if the link
+ * frequency of the sensor is not known
*/
-static int csid_set_clock_rates(struct csid_device *csid)
+static u64 csid_get_min_clock_rate(struct csid_device *csid)
{
- struct device *dev = csid->camss->dev;
const struct csid_format_info *fmt;
s64 link_freq;
- int i, j;
- int ret;
+ u64 min_rate;
fmt = csid_get_fmt_entry(csid->res->formats->formats, csid->res->formats->nformats,
- csid->fmt[MSM_CSIPHY_PAD_SINK].code);
+ csid->fmt[MSM_CSID_PAD_SINK].code);
link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp,
csid->phy.lane_cnt);
if (link_freq < 0)
- link_freq = 0;
+ return 0;
+
+ min_rate = link_freq / 4;
+ camss_add_clock_margin(&min_rate);
+
+ return min_rate;
+}
+
+/* Get the lowest level of a clock above min_rate, or -EINVAL if there is none */
+static int csid_find_clock_level(struct camss_clock *clock, u64 min_rate)
+{
+ int i;
+
+ /* Play safe with the highest level if the link rate is not known */
+ if (!min_rate)
+ return clock->nfreqs - 1;
+
+ for (i = 0; i < clock->nfreqs; i++)
+ if (clock->freq[i] > min_rate)
+ return i;
+
+ return -EINVAL;
+}
+
+/* Lower a level down to max_rate, but never below what min_rate needs */
+static int csid_cap_clock_level(struct camss_clock *clock, int level,
+ u64 min_rate, u64 max_rate)
+{
+ while (level > 0 && clock->freq[level] > max_rate &&
+ clock->freq[level - 1] > min_rate)
+ level--;
+
+ return level;
+}
+
+/*
+ * csid_set_clock_rates - Calculate and set clock rates on CSID module
+ * @csid: CSID device
+ */
+static int csid_set_clock_rates(struct csid_device *csid)
+{
+ struct device *dev = csid->camss->dev;
+ u64 min_rate = csid_get_min_clock_rate(csid);
+ u64 core_rate = 0;
+ int i, j;
+ int ret;
+
+ /*
+ * Settle the rate of the core clock first, as the receive clock must
+ * not outrun it and the clocks are not listed in a fixed order.
+ */
for (i = 0; i < csid->nclocks; i++) {
struct camss_clock *clock = &csid->clock[i];
- if (!strcmp(clock->name, "csi0") ||
- !strcmp(clock->name, "csi1") ||
- !strcmp(clock->name, "csi2") ||
- !strcmp(clock->name, "csi3")) {
- u64 min_rate = link_freq / 4;
- long rate;
+ if (!clock->nfreqs || !csid_match_core_clock_name(clock))
+ continue;
- camss_add_clock_margin(&min_rate);
+ j = csid_find_clock_level(clock, min_rate);
+ if (j < 0) {
+ dev_err(dev, "Link rate is too high for the %s clock\n",
+ clock->name);
+ return j;
+ }
- for (j = 0; j < clock->nfreqs; j++)
- if (min_rate < clock->freq[j])
- break;
+ core_rate = max_t(u64, core_rate, clock->freq[j]);
+ }
- if (j == clock->nfreqs) {
- dev_err(dev,
- "Pixel clock is too high for CSID\n");
- return -EINVAL;
- }
+ for (i = 0; i < csid->nclocks; i++) {
+ struct camss_clock *clock = &csid->clock[i];
- /* if sensor pixel clock is not available */
- /* set highest possible CSID clock rate */
- if (min_rate == 0)
- j = clock->nfreqs - 1;
+ if (!clock->nfreqs)
+ continue;
- rate = clk_round_rate(clock->clk, clock->freq[j]);
- if (rate < 0) {
- dev_err(dev, "clk round rate failed: %ld\n",
- rate);
- return -EINVAL;
- }
+ if (!csid_match_scaled_clock_name(clock)) {
+ /* The remaining clocks run at their lowest level */
- ret = clk_set_rate(clock->clk, rate);
- if (ret < 0) {
- dev_err(dev, "clk set rate failed: %d\n", ret);
- return ret;
- }
- } else if (clock->nfreqs) {
clk_set_rate(clock->clk, clock->freq[0]);
+ continue;
+ }
+
+ j = csid_find_clock_level(clock, min_rate);
+ if (j < 0) {
+ dev_err(dev, "Link rate is too high for the %s clock\n",
+ clock->name);
+ return j;
+ }
+
+ /*
+ * There is nothing to gain from running the receive clock
+ * faster than the core clock, as long as the link rate is
+ * still covered.
+ */
+ if (core_rate && csid_match_phy_rx_clock_name(clock))
+ j = csid_cap_clock_level(clock, j, min_rate, core_rate);
+
+ /*
+ * Vote for the rate as a minimum, as the clock may be shared
+ * with another CSID which needs it to run faster.
+ */
+ ret = clk_set_rate_range(clock->clk, clock->freq[j], ULONG_MAX);
+ if (ret < 0) {
+ dev_err(dev, "clk set rate range failed: %d\n", ret);
+ return ret;
}
}
return 0;
}
+/*
+ * Drop the minimum rates the CSID votes for and take its clocks back to their
+ * lowest level, or to the lowest level the other users of a shared clock need.
+ */
+static void csid_release_clock_rates(struct csid_device *csid)
+{
+ int i;
+
+ for (i = 0; i < csid->nclocks; i++) {
+ struct camss_clock *clock = &csid->clock[i];
+ long rate;
+
+ if (!clock->nfreqs || !csid_match_scaled_clock_name(clock))
+ continue;
+
+ clk_drop_range(clock->clk);
+
+ /* Round first, so that the rate respects the other votes */
+ rate = clk_round_rate(clock->clk, clock->freq[0]);
+ if (rate > 0)
+ clk_set_rate(clock->clk, rate);
+ }
+}
+
/*
* csid_hw_version - CSID hardware version query
* @csid: CSID device
@@ -707,6 +833,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
ret = csid_set_clock_rates(csid);
if (ret < 0) {
+ csid_release_clock_rates(csid);
regulator_bulk_disable(csid->num_supplies,
csid->supplies);
pm_runtime_put_sync(dev);
@@ -715,6 +842,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
ret = camss_enable_clocks(csid->nclocks, csid->clock, dev);
if (ret < 0) {
+ csid_release_clock_rates(csid);
regulator_bulk_disable(csid->num_supplies,
csid->supplies);
pm_runtime_put_sync(dev);
@@ -729,6 +857,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
if (ret < 0) {
disable_irq(csid->irq);
camss_disable_clocks(csid->nclocks, csid->clock);
+ csid_release_clock_rates(csid);
regulator_bulk_disable(csid->num_supplies,
csid->supplies);
pm_runtime_put_sync(dev);
@@ -739,6 +868,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
} else {
disable_irq(csid->irq);
camss_disable_clocks(csid->nclocks, csid->clock);
+ csid_release_clock_rates(csid);
regulator_bulk_disable(csid->num_supplies,
csid->supplies);
pm_runtime_put_sync(dev);
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v4 6/6] media: qcom: camss: Add support for Hawi
2026-11-06 6:50 [PATCH v4 0/6] Add CAMSS support for Qualcomm Hawi and Maili Nihal Kumar Gupta
` (4 preceding siblings ...)
2026-11-06 6:50 ` [PATCH v4 5/6] media: qcom: camss: csid: Scale the clocks with the CSI-2 link rate Nihal Kumar Gupta
@ 2026-11-06 6:50 ` Nihal Kumar Gupta
2026-11-06 7:12 ` sashiko-bot
5 siblings, 1 reply; 9+ messages in thread
From: Nihal Kumar Gupta @ 2026-11-06 6:50 UTC (permalink / raw)
To: Loic Poulain, Robert Foss, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bryan O'Donoghue,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam,
Vladimir Zapolskiy, Mauro Carvalho Chehab, Hangxiang Ma,
Nihal Kumar Gupta, Bryan O'Donoghue
Cc: Suresh Vankadara, Vikram Sharma, linux-i2c, linux-arm-msm,
devicetree, linux-kernel, linux-phy, linux-media
From: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
Add CAMSS support for the Hawi SoC. The CSIPHY resource table is reused
from Kaanapali and the TPG table from X1E80100.
Hawi calls its front-end blocks TFEs (Thin Front Ends), but the VFE 1190
driver keeps the VFE naming for consistency. The common CPAS clocks are
managed as PM clocks of the CAMSS resources rather than per-VFE clocks.
CSID 1190 splits RUP and AUP updates into separate registers committed
through a SET register, so the driver provides separate reg_update and
addr_update operations, and VFE 1190 wires up addr_update. The SOF and
EOF INFO bits are also defined.
Signed-off-by: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
Co-developed-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
---
drivers/media/platform/qcom/camss/Makefile | 2 +
.../media/platform/qcom/camss/camss-csid-1190.c | 417 +++++++++++++++++++++
drivers/media/platform/qcom/camss/camss-csid.h | 1 +
drivers/media/platform/qcom/camss/camss-vfe-1190.c | 217 +++++++++++
drivers/media/platform/qcom/camss/camss-vfe.c | 2 +
drivers/media/platform/qcom/camss/camss-vfe.h | 1 +
drivers/media/platform/qcom/camss/camss.c | 228 +++++++++++
drivers/media/platform/qcom/camss/camss.h | 1 +
8 files changed, 869 insertions(+)
diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 42a14e8fe1b7f28ba5ffcbe59769093b08db4d6b..e48df14933fa0e2b1910de5e68bec0b5c57dd1b2 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -9,6 +9,7 @@ qcom-camss-objs += \
camss-csid-340.o \
camss-csid-680.o \
camss-csid-1080.o \
+ camss-csid-1190.o \
camss-csid-gen2.o \
camss-csid-gen3.o \
camss-csiphy.o \
@@ -27,6 +28,7 @@ qcom-camss-objs += \
camss-vfe-480.o \
camss-vfe-680.o \
camss-vfe-1080.o \
+ camss-vfe-1190.o \
camss-vfe-gen1.o \
camss-vfe-gen3.o \
camss-vfe-vbif.o \
diff --git a/drivers/media/platform/qcom/camss/camss-csid-1190.c b/drivers/media/platform/qcom/camss/camss-csid-1190.c
new file mode 100644
index 0000000000000000000000000000000000000000..4bd2cce0944022ce0f987faa0e34417a665c0aa4
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-csid-1190.c
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-csid-1190.c
+ *
+ * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include "camss.h"
+#include "camss-csid.h"
+#include "camss-csid-gen3.h"
+
+/* Reset and Command Registers */
+#define CSID_RST_CFG 0x108
+#define RST_MODE BIT(0)
+#define RST_LOCATION BIT(4)
+
+/* Reset and Command Registers */
+#define CSID_RST_CMD 0x10C
+#define SELECT_HW_RST BIT(0)
+#define SELECT_IRQ_RST BIT(2)
+#define CSID_IRQ_CMD 0x110
+#define IRQ_CMD_CLEAR BIT(0)
+
+/* Register Update Commands, RUP/AUP */
+#define CSID_RUP_CMD 0x114
+#define CSID_AUP_CMD 0x118
+#define CSID_RUP_AUP_RDI(rdi) (BIT(8) << (rdi))
+#define CSID_RUP_AUP_CMD 0x11C
+#define RUP_SET BIT(0)
+#define MUP BIT(4)
+
+/* Top level interrupt registers */
+#define CSID_TOP_IRQ_STATUS 0x180
+#define CSID_TOP_IRQ_MASK 0x184
+#define CSID_TOP_IRQ_CLEAR 0x188
+#define INFO_RST_DONE BIT(0)
+#define CSI2_RX_IRQ_STATUS BIT(2)
+#define BUF_DONE_IRQ_STATUS BIT(3)
+#define TOP_IRQ_STATUS_RDI_OFFSET 16
+
+/* Buffer done interrupt registers */
+#define CSID_BUF_DONE_IRQ_STATUS 0x1A0
+#define BUF_DONE_IRQ_STATUS_RDI_OFFSET 16
+#define CSID_BUF_DONE_IRQ_MASK 0x1A4
+#define CSID_BUF_DONE_IRQ_CLEAR 0x1A8
+#define CSID_BUF_DONE_IRQ_SET 0x1AC
+
+/* CSI2 RX interrupt registers */
+#define CSID_CSI2_RX_IRQ_STATUS 0x1B0
+#define CSID_CSI2_RX_IRQ_MASK 0x1B4
+#define CSID_CSI2_RX_IRQ_CLEAR 0x1B8
+#define CSID_CSI2_RX_IRQ_SET 0x1BC
+
+/* CSI2 RX Configuration */
+#define CSID_CSI2_RX_CFG0 0x880
+#define CSI2_RX_CFG0_NUM_ACTIVE_LANES 0
+#define CSI2_RX_CFG0_DL0_INPUT_SEL 4
+#define CSI2_RX_CFG0_PHY_NUM_SEL 20
+#define CSI2_RX_CFG0_TPG_MUX_EN BIT(27)
+#define CSI2_RX_CFG0_TPG_MUX_SEL GENMASK(29, 28)
+#define CSI2_RX_CFG0_PHY_SEL_BASE_IDX 1
+#define CSID_CSI2_RX_CFG1 0x884
+#define CSI2_RX_CFG1_ECC_CORRECTION_EN BIT(0)
+#define CSI2_RX_CFG1_VC_MODE BIT(2)
+
+#define MSM_CSID_MAX_SRC_STREAMS_1190 (csid_is_lite(csid) ? 4 : 5)
+
+/* RDI Configuration */
+#define CSID_RDI_CFG0(rdi) (csid_is_lite(csid) ?\
+ (0x3080 + 0x200 * (rdi)) :\
+ (0x5480 + 0x200 * (rdi)))
+#define RDI_CFG0_RETIME_BS BIT(5)
+#define RDI_CFG0_TIMESTAMP_EN BIT(6)
+#define RDI_CFG0_TIMESTAMP_STB_SEL BIT(8)
+#define RDI_CFG0_DECODE_FORMAT 12
+#define RDI_CFG0_DT 16
+#define RDI_CFG0_VC 22
+#define RDI_CFG0_EN BIT(31)
+
+/* RDI Control and Configuration */
+#define CSID_RDI_CTRL(rdi) (csid_is_lite(csid) ?\
+ (0x3088 + 0x200 * (rdi)) :\
+ (0x5488 + 0x200 * (rdi)))
+#define RDI_CTRL_START_CMD BIT(0)
+
+#define CSID_RDI_CFG1(rdi) (csid_is_lite(csid) ?\
+ (0x3094 + 0x200 * (rdi)) :\
+ (0x5494 + 0x200 * (rdi)))
+#define RDI_CFG1_DROP_H_EN BIT(5)
+#define RDI_CFG1_DROP_V_EN BIT(6)
+#define RDI_CFG1_CROP_H_EN BIT(7)
+#define RDI_CFG1_CROP_V_EN BIT(8)
+#define RDI_CFG1_PACKING_FORMAT_MIPI BIT(15)
+
+/* RDI Pixel Store Configuration */
+#define CSID_RDI_PIX_STORE_CFG0(rdi) (0x5498 + 0x200 * (rdi))
+#define RDI_PIX_STORE_CFG0_EN BIT(0)
+#define RDI_PIX_STORE_CFG0_MIN_HBI 1
+
+/* RDI IRQ Status in wrapper */
+#define CSID_CSI2_RDIN_IRQ_STATUS(rdi) (0x224 + (0x10 * (rdi)))
+#define CSID_CSI2_RDIN_IRQ_MASK(rdi) (0x228 + (0x10 * (rdi)))
+#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi) (0x22C + (0x10 * (rdi)))
+#define INFO_RUP_DONE BIT(23)
+#define INFO_INPUT_SOF BIT(12)
+#define INFO_INPUT_EOF BIT(9)
+#define INFO_CAMIF_SOF BIT(4)
+#define INFO_CAMIF_EOF BIT(3)
+
+static void __csid_aup_rup_trigger(struct csid_device *csid)
+{
+ /* trigger SET in combined register */
+ writel(RUP_SET, csid->base + CSID_RUP_AUP_CMD);
+}
+
+static void __csid_addr_update(struct csid_device *csid, int port_id)
+{
+ csid->addr_update |= CSID_RUP_AUP_RDI(port_id);
+ writel(csid->addr_update, csid->base + CSID_AUP_CMD);
+
+ __csid_aup_rup_trigger(csid);
+}
+
+static void __csid_addr_update_clear(struct csid_device *csid, int port_id)
+{
+ /* Hardware clears the registers upon consuming the settings */
+ csid->addr_update &= ~CSID_RUP_AUP_RDI(port_id);
+}
+
+static void __csid_reg_update(struct csid_device *csid, int port_id)
+{
+ csid->reg_update |= CSID_RUP_AUP_RDI(port_id);
+ writel(csid->reg_update, csid->base + CSID_RUP_CMD);
+
+ __csid_aup_rup_trigger(csid);
+}
+
+static void __csid_reg_update_clear(struct csid_device *csid, int port_id)
+{
+ /* Hardware clears the registers upon consuming the settings */
+ csid->reg_update &= ~CSID_RUP_AUP_RDI(port_id);
+}
+
+static void __csid_configure_rx(struct csid_device *csid,
+ struct csid_phy_config *phy)
+{
+ struct camss *camss = csid->camss;
+ u8 lane_cnt = csid->phy.lane_cnt;
+ int val;
+
+ if (!lane_cnt)
+ lane_cnt = 4;
+
+ val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES;
+ val |= phy->lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL;
+
+ if (camss->tpg && csid->tpg_linked &&
+ camss->tpg[phy->csiphy_id].testgen.mode != TPG_PAYLOAD_MODE_DISABLED) {
+ val |= FIELD_PREP(CSI2_RX_CFG0_TPG_MUX_SEL, phy->csiphy_id + 1);
+ val |= CSI2_RX_CFG0_TPG_MUX_EN;
+ } else {
+ val |= (phy->csiphy_id + CSI2_RX_CFG0_PHY_SEL_BASE_IDX)
+ << CSI2_RX_CFG0_PHY_NUM_SEL;
+ }
+
+ writel(val, csid->base + CSID_CSI2_RX_CFG0);
+
+ val = CSI2_RX_CFG1_ECC_CORRECTION_EN;
+ writel(val, csid->base + CSID_CSI2_RX_CFG1);
+}
+
+static void __csid_configure_rx_vc(struct csid_device *csid, int vc)
+{
+ int val;
+
+ if (vc > 3) {
+ val = readl(csid->base + CSID_CSI2_RX_CFG1);
+ val |= CSI2_RX_CFG1_VC_MODE;
+ writel(val, csid->base + CSID_CSI2_RX_CFG1);
+ }
+}
+
+static void __csid_ctrl_rdi(struct csid_device *csid, int enable, u8 rdi)
+{
+ int val = 0;
+
+ if (enable)
+ val = RDI_CTRL_START_CMD;
+
+ writel(val, csid->base + CSID_RDI_CTRL(rdi));
+}
+
+static void __csid_configure_rdi_pix_store(struct csid_device *csid, u8 rdi)
+{
+ u32 val;
+
+ /*
+ * Configure pixel store to allow absorption of hblanking or idle time.
+ * This helps with horizontal crop and prevents line buffer conflicts.
+ * Reset state is 0x8 which has MIN_HBI=4, we keep the default MIN_HBI
+ * and just enable the pixel store functionality.
+ */
+ val = (4 << RDI_PIX_STORE_CFG0_MIN_HBI) | RDI_PIX_STORE_CFG0_EN;
+ writel(val, csid->base + CSID_RDI_PIX_STORE_CFG0(rdi));
+}
+
+static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 port, u8 vc)
+{
+ u32 val;
+ u8 lane_cnt = csid->phy.lane_cnt;
+
+ /* Source pads matching RDI channels on hardware.
+ * E.g. Pad 1 -> RDI0, Pad 2 -> RDI1, etc.
+ */
+ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port];
+ const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats,
+ csid->res->formats->nformats,
+ input_format->code);
+
+ if (!lane_cnt)
+ lane_cnt = 4;
+
+ val = RDI_CFG0_TIMESTAMP_EN;
+ val |= RDI_CFG0_TIMESTAMP_STB_SEL;
+ val |= RDI_CFG0_RETIME_BS;
+
+ /* note: for non-RDI path, this should be format->decode_format */
+ val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT;
+ val |= vc << RDI_CFG0_VC;
+ val |= format->data_type << RDI_CFG0_DT;
+ writel(val, csid->base + CSID_RDI_CFG0(port));
+
+ val = RDI_CFG1_PACKING_FORMAT_MIPI;
+ writel(val, csid->base + CSID_RDI_CFG1(port));
+
+ /* Configure pixel store using dedicated register in 1190 */
+ if (!csid_is_lite(csid))
+ __csid_configure_rdi_pix_store(csid, port);
+
+ val = 0;
+ writel(val, csid->base + CSID_RDI_CTRL(port));
+
+ val = readl(csid->base + CSID_RDI_CFG0(port));
+
+ if (enable)
+ val |= RDI_CFG0_EN;
+
+ writel(val, csid->base + CSID_RDI_CFG0(port));
+}
+
+static void csid_configure_stream(struct csid_device *csid, u8 enable)
+{
+ u8 i, k;
+
+ __csid_configure_rx(csid, &csid->phy);
+
+ for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS_1190; i++) {
+ if (csid->phy.en_vc & BIT(i)) {
+ __csid_configure_rdi_stream(csid, enable, i, 0);
+ __csid_configure_rx_vc(csid, 0);
+
+ for (k = 0; k < CAMSS_INIT_BUF_COUNT; k++)
+ __csid_addr_update(csid, i);
+
+ __csid_reg_update(csid, i);
+
+ __csid_ctrl_rdi(csid, enable, i);
+ }
+ }
+}
+
+static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
+{
+ return 0;
+}
+
+static void csid_subdev_reg_update(struct csid_device *csid, int port_id,
+ bool clear)
+{
+ if (clear)
+ __csid_reg_update_clear(csid, port_id);
+ else
+ __csid_reg_update(csid, port_id);
+}
+
+static void csid_subdev_addr_update(struct csid_device *csid, int port_id,
+ bool clear)
+{
+ if (clear)
+ __csid_addr_update_clear(csid, port_id);
+ else
+ __csid_addr_update(csid, port_id);
+}
+
+/**
+ * csid_isr - CSID module interrupt service routine
+ * @irq: Interrupt line
+ * @dev: CSID device
+ *
+ * Return IRQ_HANDLED on success
+ */
+static irqreturn_t csid_isr(int irq, void *dev)
+{
+ struct csid_device *csid = dev;
+ u32 val, buf_done_val;
+ u8 reset_done;
+ int i;
+
+ val = readl(csid->base + CSID_TOP_IRQ_STATUS);
+ writel(val, csid->base + CSID_TOP_IRQ_CLEAR);
+
+ reset_done = val & INFO_RST_DONE;
+
+ buf_done_val = readl(csid->base + CSID_BUF_DONE_IRQ_STATUS);
+ writel(buf_done_val, csid->base + CSID_BUF_DONE_IRQ_CLEAR);
+
+ for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS_1190; i++) {
+ if (csid->phy.en_vc & BIT(i)) {
+ val = readl(csid->base + CSID_CSI2_RDIN_IRQ_STATUS(i));
+ writel(val, csid->base + CSID_CSI2_RDIN_IRQ_CLEAR(i));
+
+ if (val & INFO_RUP_DONE) {
+ __csid_addr_update_clear(csid, i);
+ __csid_reg_update_clear(csid, i);
+ }
+
+ if (buf_done_val & BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET + i))
+ camss_buf_done(csid->camss, csid->id, i);
+ }
+ }
+
+ val = IRQ_CMD_CLEAR;
+ writel(val, csid->base + CSID_IRQ_CMD);
+
+ if (reset_done)
+ complete(&csid->reset_complete);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * csid_reset - Trigger reset on CSID module and wait to complete
+ * @csid: CSID device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int csid_reset(struct csid_device *csid)
+{
+ unsigned long time;
+ u32 val;
+ int i;
+
+ reinit_completion(&csid->reset_complete);
+
+ val = INFO_RST_DONE | BUF_DONE_IRQ_STATUS;
+ writel(val, csid->base + CSID_TOP_IRQ_CLEAR);
+ writel(val, csid->base + CSID_TOP_IRQ_MASK);
+
+ val = 0;
+ for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS_1190; i++) {
+ if (csid->phy.en_vc & BIT(i)) {
+ /*
+ * Only need to clear buf done IRQ status here,
+ * RUP done IRQ status will be cleared once isr
+ * strobe generated by CSID_RST_CMD
+ */
+ val |= BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET + i);
+ }
+ }
+ writel(val, csid->base + CSID_BUF_DONE_IRQ_CLEAR);
+ writel(val, csid->base + CSID_BUF_DONE_IRQ_MASK);
+
+ /* Clear all IRQ status with CLEAR bits set */
+ val = IRQ_CMD_CLEAR;
+ writel(val, csid->base + CSID_IRQ_CMD);
+
+ val = RST_LOCATION | RST_MODE;
+ writel(val, csid->base + CSID_RST_CFG);
+
+ val = SELECT_HW_RST | SELECT_IRQ_RST;
+ writel(val, csid->base + CSID_RST_CMD);
+
+ time = wait_for_completion_timeout(&csid->reset_complete,
+ msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
+
+ if (!time) {
+ dev_err(csid->camss->dev, "CSID reset timeout\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void csid_subdev_init(struct csid_device *csid)
+{
+ csid->testgen.nmodes = CSID_PAYLOAD_MODE_DISABLED;
+}
+
+const struct csid_hw_ops csid_ops_1190 = {
+ .configure_stream = csid_configure_stream,
+ .configure_testgen_pattern = csid_configure_testgen_pattern,
+ .hw_version = csid_hw_version,
+ .isr = csid_isr,
+ .reset = csid_reset,
+ .src_pad_code = csid_src_pad_code,
+ .subdev_init = csid_subdev_init,
+ .reg_update = csid_subdev_reg_update,
+ .addr_update = csid_subdev_addr_update,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index a3ab2a384bb49ac24955e86c8452a8ce36ce71b2..7bdf183d28c8ac33833cc974cae2cc79d4bef415 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -226,6 +226,7 @@ extern const struct csid_hw_ops csid_ops_4_7;
extern const struct csid_hw_ops csid_ops_340;
extern const struct csid_hw_ops csid_ops_680;
extern const struct csid_hw_ops csid_ops_1080;
+extern const struct csid_hw_ops csid_ops_1190;
extern const struct csid_hw_ops csid_ops_gen2;
extern const struct csid_hw_ops csid_ops_gen3;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-1190.c b/drivers/media/platform/qcom/camss/camss-vfe-1190.c
new file mode 100644
index 0000000000000000000000000000000000000000..246519c2294b8d5021ebdd95e056f00d20897a0f
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-vfe-1190.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-vfe-1190.c
+ *
+ * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module 1190
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#include "camss.h"
+#include "camss-vfe.h"
+
+/* VFE-1190 Bus Register Base Addresses */
+#define BUS_REG_BASE (0x800)
+#define BUS_REG_OFFSET(n) (0x1000 + (n) * 0x200)
+
+#define VFE_BUS_WM_CGC_OVERRIDE (BUS_REG_BASE + 0x4)
+#define WM_CGC_OVERRIDE_ALL (0x7FFFFFF)
+
+#define VFE_BUS_WM_TEST_BUS_CTRL (BUS_REG_BASE + 0x144)
+
+#define VFE_BUS_WM_CFG(n) (BUS_REG_BASE + BUS_REG_OFFSET(n))
+#define WM_CFG_EN BIT(0)
+#define WM_VIR_FRM_EN BIT(1)
+#define WM_CFG_MODE BIT(16)
+#define VFE_BUS_WM_IMAGE_ADDR(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x4)
+#define VFE_BUS_WM_FRAME_INCR(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x8)
+#define VFE_BUS_WM_IMAGE_CFG_0(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0xC)
+#define WM_IMAGE_CFG_0_DEFAULT_WIDTH (0xFFFF)
+#define VFE_BUS_WM_IMAGE_CFG_2(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x14)
+#define WM_IMAGE_CFG_2_DEFAULT_STRIDE (0xFFFF)
+#define VFE_BUS_WM_PACKER_CFG(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x18)
+
+#define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x30)
+#define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x34)
+
+/* VFE lite has no such registers */
+#define VFE_BUS_WM_FRAMEDROP_PERIOD(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x38)
+#define VFE_BUS_WM_FRAMEDROP_PATTERN(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x3C)
+
+#define VFE_BUS_WM_MMU_PREFETCH_CFG(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x64)
+#define VFE_BUS_WM_MMU_PREFETCH_MAX_OFFSET(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x68)
+
+/*
+ * VFE 1190 write master client IDs
+ *
+ * VIDEO_FULL_Y 0
+ * VIDEO_FULL_UV 1
+ * VIDEO_DC4_Y 2
+ * VIDEO_DC4_C 3
+ * VIDEO_DC16_Y 4
+ * VIDEO_DC16_C 5
+ * FD_Y 6
+ * FD_C 7
+ * RAW_OUT 8
+ * STATS_AEC_BG 9
+ * STATS_AEC_BHIST 10
+ * STATS_TINTLESS_BG 11
+ * STATS_AWB_BG 12
+ * STATS_AWB_BFW 13
+ * STATS_AF_BHIST 14
+ * STATS_ALSC_BG 15
+ * STATS_FLICKER_BAYERRS 16
+ * STATS_TMC_BHIST 17
+ * PDAF_0 18
+ * PDAF_1 19
+ * PDAF_2 20
+ * PDAF_3 21
+ * PDAF_4 22
+ * RDI0 23
+ * RDI1 24
+ * RDI2 25
+ * RDI3 26
+ * RDI4 27
+ * C2PA Y 28
+ * C2PA C 29
+ *
+ * VFE Lite 1190 write master client IDs
+ *
+ * RDI0 0
+ * RDI1 1
+ * RDI2 2
+ * RDI3 3
+ * GAMMA 4
+ * STATES_BG 5
+ */
+#define RDI_WM(n) ((vfe_is_lite(vfe) ? 0x0 : 0x17) + (n))
+
+static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
+{
+ struct v4l2_pix_format_mplane *pix =
+ &line->video_out.active_fmt.fmt.pix_mp;
+
+ wm = RDI_WM(wm);
+
+ /* no clock gating at bus input */
+ writel(WM_CGC_OVERRIDE_ALL, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
+
+ writel(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
+
+ writel(ALIGN(pix->plane_fmt[0].bytesperline, 16) * pix->height >> 8,
+ vfe->base + VFE_BUS_WM_FRAME_INCR(wm));
+ writel((WM_IMAGE_CFG_0_DEFAULT_WIDTH & 0xFFFF),
+ vfe->base + VFE_BUS_WM_IMAGE_CFG_0(wm));
+ writel(WM_IMAGE_CFG_2_DEFAULT_STRIDE,
+ vfe->base + VFE_BUS_WM_IMAGE_CFG_2(wm));
+ writel(0, vfe->base + VFE_BUS_WM_PACKER_CFG(wm));
+
+ /* no dropped frames, one irq per frame */
+ if (!vfe_is_lite(vfe)) {
+ writel(0, vfe->base + VFE_BUS_WM_FRAMEDROP_PERIOD(wm));
+ writel(1, vfe->base + VFE_BUS_WM_FRAMEDROP_PATTERN(wm));
+ }
+
+ writel(0, vfe->base + VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(wm));
+ writel(1, vfe->base + VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(wm));
+
+ writel(1, vfe->base + VFE_BUS_WM_MMU_PREFETCH_CFG(wm));
+ writel(0xFFFFFFFF, vfe->base + VFE_BUS_WM_MMU_PREFETCH_MAX_OFFSET(wm));
+
+ writel(WM_CFG_EN | WM_CFG_MODE, vfe->base + VFE_BUS_WM_CFG(wm));
+}
+
+static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
+{
+ wm = RDI_WM(wm);
+ writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
+}
+
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
+ struct vfe_line *line)
+{
+ wm = RDI_WM(wm);
+ writel(addr >> 8, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
+
+ dev_dbg(vfe->camss->dev, "wm:%d, image buf addr:0x%x\n", wm, addr);
+}
+
+static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+ int port_id = line_id;
+
+ camss_reg_update(vfe->camss, vfe->id, port_id, false);
+}
+
+static inline void vfe_reg_update_clear(struct vfe_device *vfe,
+ enum vfe_line_id line_id)
+{
+ int port_id = line_id;
+
+ camss_reg_update(vfe->camss, vfe->id, port_id, true);
+}
+
+static void vfe_addr_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+ int port_id = line_id;
+
+ camss_addr_update(vfe->camss, vfe->id, port_id, false);
+}
+
+static inline void vfe_addr_update_clear(struct vfe_device *vfe,
+ enum vfe_line_id line_id)
+{
+ int port_id = line_id;
+
+ camss_addr_update(vfe->camss, vfe->id, port_id, true);
+}
+
+static const struct camss_video_ops vfe_video_ops_1190 = {
+ .queue_buffer = vfe_queue_buffer_v2,
+ .flush_buffers = vfe_flush_buffers,
+};
+
+static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
+{
+ vfe->video_ops = vfe_video_ops_1190;
+}
+
+static void vfe_global_reset(struct vfe_device *vfe)
+{
+ vfe_isr_reset_ack(vfe);
+}
+
+static irqreturn_t vfe_isr(int irq, void *dev)
+{
+ /* nop */
+ return IRQ_HANDLED;
+}
+
+static int vfe_halt(struct vfe_device *vfe)
+{
+ /* rely on vfe_disable_output() to stop the VFE */
+ return 0;
+}
+
+const struct vfe_hw_ops vfe_ops_1190 = {
+ .addr_update = vfe_addr_update,
+ .addr_update_clear = vfe_addr_update_clear,
+ .global_reset = vfe_global_reset,
+ .hw_version = vfe_hw_version,
+ .isr = vfe_isr,
+ .pm_domain_off = vfe_pm_domain_off,
+ .pm_domain_on = vfe_pm_domain_on,
+ .reg_update = vfe_reg_update,
+ .reg_update_clear = vfe_reg_update_clear,
+ .subdev_init = vfe_subdev_init,
+ .vfe_disable = vfe_disable,
+ .vfe_enable = vfe_enable_v2,
+ .vfe_halt = vfe_halt,
+ .vfe_wm_start = vfe_wm_start,
+ .vfe_wm_stop = vfe_wm_stop,
+ .vfe_buf_done = vfe_buf_done,
+ .vfe_wm_update = vfe_wm_update,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 221abf7bfd47e43e685d4b9a5efc10b066ff8bc2..96ac839663752b9c5164cc35f9fb7f877e67fda7 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -353,6 +353,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
case CAMSS_8550:
case CAMSS_8650:
case CAMSS_8775P:
+ case CAMSS_HAWI:
case CAMSS_KAANAPALI:
case CAMSS_X1E80100:
switch (sink_code) {
@@ -2021,6 +2022,7 @@ static int vfe_bpl_align_rdi(struct vfe_device *vfe)
case CAMSS_8550:
case CAMSS_8650:
case CAMSS_8775P:
+ case CAMSS_HAWI:
case CAMSS_KAANAPALI:
case CAMSS_X1E80100:
ret = 16;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 0a91440cfe438625f7f1b71b60186491b3d24d5d..8cc5571e0b91080705c675bb09ff6eb931e6e5fc 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -252,6 +252,7 @@ extern const struct vfe_hw_ops vfe_ops_340;
extern const struct vfe_hw_ops vfe_ops_480;
extern const struct vfe_hw_ops vfe_ops_680;
extern const struct vfe_hw_ops vfe_ops_1080;
+extern const struct vfe_hw_ops vfe_ops_1190;
extern const struct vfe_hw_ops vfe_ops_gen3;
int vfe_get(struct vfe_device *vfe);
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 7976796dca5980a34923cd7a336f47106cf68df0..70d4306581a233907af6cf04c9147cd813a717ae 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -4308,6 +4308,218 @@ static const struct resources_icc icc_res_sa8775p[] = {
},
};
+static const struct camss_subdev_resources vfe_res_hawi[] = {
+ /* VFE0 - TFE Full */
+ {
+ .clock = { "vfe0_fast_ahb", "vfe0", "cpas_vfe0",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
+ "cpas_mnoc_hf", "cpas_mnoc_sf" },
+ .clock_rate = { { 0 },
+ { 238200000, 397000000, 440000000, 480000000,
+ 630000000, 750000000, 833000000 },
+ { 0 },
+ { 171428571, 240000000, 300000000, 400000000,
+ 480000000, 600000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe0" },
+ .interrupt = { "vfe0" },
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .pd_name = "ife0",
+ .hw_ops = &vfe_ops_1190,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE1 - TFE Full */
+ {
+ .clock = { "vfe1_fast_ahb", "vfe1", "cpas_vfe1",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
+ "cpas_mnoc_hf", "cpas_mnoc_sf" },
+ .clock_rate = { { 0 },
+ { 238200000, 397000000, 440000000, 480000000,
+ 630000000, 750000000, 833000000 },
+ { 0 },
+ { 171428571, 240000000, 300000000, 400000000,
+ 480000000, 600000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe1" },
+ .interrupt = { "vfe1" },
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .pd_name = "ife1",
+ .hw_ops = &vfe_ops_1190,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE2 - TFE Full */
+ {
+ .clock = { "vfe2_fast_ahb", "vfe2", "cpas_vfe2",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
+ "cpas_mnoc_hf", "cpas_mnoc_sf" },
+ .clock_rate = { { 0 },
+ { 238200000, 397000000, 440000000, 480000000,
+ 630000000, 750000000, 833000000 },
+ { 0 },
+ { 171428571, 240000000, 300000000, 400000000,
+ 480000000, 600000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe2" },
+ .interrupt = { "vfe2" },
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .pd_name = "ife2",
+ .hw_ops = &vfe_ops_1190,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE3 - IFE Lite */
+ {
+ .clock = { "vfe_lite_ahb", "vfe_lite", "cpas_vfe_lite",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
+ "cpas_mnoc_hf", "cpas_mnoc_sf" },
+ .clock_rate = { { 0 },
+ { 200000000, 400000000, 480000000 },
+ { 0 },
+ { 171428571, 240000000, 300000000, 400000000,
+ 480000000, 600000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe_lite0" },
+ .interrupt = { "vfe_lite0" },
+ .vfe = {
+ .line_num = 3,
+ .is_lite = true,
+ .hw_ops = &vfe_ops_1190,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE4 - IFE Lite */
+ {
+ .clock = { "vfe_lite_ahb", "vfe_lite", "cpas_vfe_lite",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
+ "cpas_mnoc_hf", "cpas_mnoc_sf" },
+ .clock_rate = { { 0 },
+ { 200000000, 400000000, 480000000 },
+ { 0 },
+ { 171428571, 240000000, 300000000, 400000000,
+ 480000000, 600000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe_lite1" },
+ .interrupt = { "vfe_lite1" },
+ .vfe = {
+ .line_num = 3,
+ .is_lite = true,
+ .hw_ops = &vfe_ops_1190,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+};
+
+static const struct camss_subdev_resources csid_res_hawi[] = {
+ /* CSID0 */
+ {
+ .clock = { "csid", "csiphy_rx" },
+ .clock_rate = { { 200000000, 300000000, 480000000 },
+ { 200000000, 300000000, 480000000 } },
+ .reg = { "csid0" },
+ .interrupt = { "csid0" },
+ .csid = {
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .hw_ops = &csid_ops_1190,
+ .formats = &csid_formats_gen2
+ }
+ },
+ /* CSID1 */
+ {
+ .clock = { "csid", "csiphy_rx" },
+ .clock_rate = { { 200000000, 300000000, 480000000 },
+ { 200000000, 300000000, 480000000 } },
+ .reg = { "csid1" },
+ .interrupt = { "csid1" },
+ .csid = {
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .hw_ops = &csid_ops_1190,
+ .formats = &csid_formats_gen2
+ }
+ },
+ /* CSID2 */
+ {
+ .clock = { "csid", "csiphy_rx" },
+ .clock_rate = { { 200000000, 300000000, 480000000 },
+ { 200000000, 300000000, 480000000 } },
+ .reg = { "csid2" },
+ .interrupt = { "csid2" },
+ .csid = {
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .hw_ops = &csid_ops_1190,
+ .formats = &csid_formats_gen2
+ }
+ },
+ /* CSID_LITE0 */
+ {
+ .clock = { "vfe_lite_csid", "vfe_lite_cphy_rx" },
+ .clock_rate = { { 200000000, 300000000, 480000000 },
+ { 200000000, 300000000, 480000000 } },
+ .reg = { "csid_lite0" },
+ .interrupt = { "csid_lite0" },
+ .csid = {
+ .is_lite = true,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .hw_ops = &csid_ops_1190,
+ .formats = &csid_formats_gen2
+ }
+ },
+ /* CSID_LITE1 */
+ {
+ .clock = { "vfe_lite_csid", "vfe_lite_cphy_rx" },
+ .clock_rate = { { 200000000, 300000000, 480000000 },
+ { 200000000, 300000000, 480000000 } },
+ .reg = { "csid_lite1" },
+ .interrupt = { "csid_lite1" },
+ .csid = {
+ .is_lite = true,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .hw_ops = &csid_ops_1190,
+ .formats = &csid_formats_gen2
+ }
+ }
+};
+
+static const struct resources_icc icc_res_hawi[] = {
+ {
+ .name = "ahb",
+ .icc_bw_tbl.avg = 38400,
+ .icc_bw_tbl.peak = 76800,
+ },
+ {
+ .name = "hf_mnoc",
+ .icc_bw_tbl.avg = 2097152,
+ .icc_bw_tbl.peak = 2097152,
+ },
+};
+
static const struct camss_subdev_resources csiphy_res_x1e80100[] = {
/* CSIPHY0 */
{
@@ -6030,6 +6242,21 @@ static const struct camss_resources sm8650_resources = {
.vfe_num = ARRAY_SIZE(vfe_res_sm8650),
};
+static const struct camss_resources hawi_resources = {
+ .version = CAMSS_HAWI,
+ .pd_name = "top",
+ .pm_clks = { "cpas_fast_ahb", "cpas_ahb", "gcc_axi_hf" },
+ .tpg_res = tpg_res_8775p,
+ .csid_res = csid_res_hawi,
+ .vfe_res = vfe_res_hawi,
+ .icc_res = icc_res_hawi,
+ .icc_path_num = ARRAY_SIZE(icc_res_hawi),
+ .csiphy_num = 6,
+ .tpg_num = ARRAY_SIZE(tpg_res_8775p),
+ .csid_num = ARRAY_SIZE(csid_res_hawi),
+ .vfe_num = ARRAY_SIZE(vfe_res_hawi),
+};
+
static const struct camss_resources x1e80100_resources = {
.version = CAMSS_X1E80100,
.pd_name = "top",
@@ -6047,6 +6274,7 @@ static const struct camss_resources x1e80100_resources = {
};
static const struct of_device_id camss_dt_match[] = {
+ { .compatible = "qcom,hawi-camss", .data = &hawi_resources },
{ .compatible = "qcom,kaanapali-camss", .data = &kaanapali_resources },
{ .compatible = "qcom,msm8916-camss", .data = &msm8916_resources },
{ .compatible = "qcom,msm8939-camss", .data = &msm8939_resources },
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 97fec24e680461a477add23bf5fb0b486903ba5b..95bbf4eb2a63fcd1852716a8d47493f49247c732 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -96,6 +96,7 @@ enum camss_version {
CAMSS_8550,
CAMSS_8650,
CAMSS_8775P,
+ CAMSS_HAWI,
CAMSS_KAANAPALI,
CAMSS_X1E80100,
};
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v4 6/6] media: qcom: camss: Add support for Hawi
2026-11-06 6:50 ` [PATCH v4 6/6] media: qcom: camss: Add support for Hawi Nihal Kumar Gupta
@ 2026-11-06 7:12 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-11-06 7:12 UTC (permalink / raw)
To: Nihal Kumar Gupta
Cc: devicetree, linux-phy, robh, conor+dt, media-ci, vkoul,
neil.armstrong, olteanv
Thank you for your contribution! Sashiko AI review found 5 potential
issues to consider:
- [High] media: qcom: camss: unconditional AUP strobes in
csid_configure_stream()
- [Medium] media: qcom: camss: race on csid->addr_update and
csid->reg_update
- [Medium] media: qcom: camss: wrong camnoc_rt_axi clock rates in
vfe_res_hawi
- [Low] media: qcom: camss: duplicate CSID/VFE 1080 code and inaccurate
changelog
- [Low] media: qcom: camss: commit message mismatch with hawi_resources
--
commit 56bf9cdebfcac8b831c8b140e2703b5aa2fdcc78
Author: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
media: qcom: camss: Add support for Hawi
This commit adds CAMSS support for the Qualcomm Hawi SoC, including CSID
1190, VFE 1190, and the Hawi subdevice resource tables.
> diff --git a/drivers/media/platform/qcom/camss/camss-csid-1190.c b/drivers/media/platform/qcom/camss/camss-csid-1190.c
> new file mode 100644
> index 0000000000000..4bd2cce094402
> --- /dev/null
> +++ b/drivers/media/platform/qcom/camss/camss-csid-1190.c
[ ... ]
> +static void __csid_aup_rup_trigger(struct csid_device *csid)
> +{
> + /* trigger SET in combined register */
> + writel(RUP_SET, csid->base + CSID_RUP_AUP_CMD);
> +}
> +
> +static void __csid_addr_update(struct csid_device *csid, int port_id)
> +{
> + csid->addr_update |= CSID_RUP_AUP_RDI(port_id);
> + writel(csid->addr_update, csid->base + CSID_AUP_CMD);
> +
> + __csid_aup_rup_trigger(csid);
> +}
> +
> +static void __csid_addr_update_clear(struct csid_device *csid, int port_id)
> +{
> + /* Hardware clears the registers upon consuming the settings */
> + csid->addr_update &= ~CSID_RUP_AUP_RDI(port_id);
> +}
> +
> +static void __csid_reg_update(struct csid_device *csid, int port_id)
> +{
> + csid->reg_update |= CSID_RUP_AUP_RDI(port_id);
> + writel(csid->reg_update, csid->base + CSID_RUP_CMD);
> +
> + __csid_aup_rup_trigger(csid);
> +}
> +
> +static void __csid_reg_update_clear(struct csid_device *csid, int port_id)
> +{
> + /* Hardware clears the registers upon consuming the settings */
> + csid->reg_update &= ~CSID_RUP_AUP_RDI(port_id);
> +}
[Severity: Medium]
Can concurrent updates to csid->addr_update and csid->reg_update race with
csid_isr()?
vfe_queue_buffer_v2() and vfe_enable_output_v2() call ops->addr_update() and
ops->reg_update() under vfe->output_lock, whereas csid_isr() clears those
bitmasks on INFO_RUP_DONE without holding vfe->output_lock or a CSID
spinlock, and csid_configure_stream() sets them without a spinlock:
CPU0 CPU1 (<hardirq>)
vfe_queue_buffer_v2() csid_isr()
spin_lock_irqsave(&vfe->output_lock)
... __csid_addr_update_clear(csid, i)
__csid_addr_update(csid, port_id) load csid->addr_update
load csid->addr_update and ~CSID_RUP_AUP_RDI(i)
or CSID_RUP_AUP_RDI(port_id) store csid->addr_update
store csid->addr_update <-- clobbers clear (or loses set bit)
writel(csid->addr_update, ...)
This data race can drop a pending RDI address or register update or
re-write a stale RDI bit to CSID_AUP_CMD and CSID_RUP_CMD.
[ ... ]
> +static void csid_configure_stream(struct csid_device *csid, u8 enable)
> +{
> + u8 i, k;
> +
> + __csid_configure_rx(csid, &csid->phy);
> +
> + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS_1190; i++) {
> + if (csid->phy.en_vc & BIT(i)) {
> + __csid_configure_rdi_stream(csid, enable, i, 0);
> + __csid_configure_rx_vc(csid, 0);
> +
> + for (k = 0; k < CAMSS_INIT_BUF_COUNT; k++)
> + __csid_addr_update(csid, i);
> +
> + __csid_reg_update(csid, i);
> +
> + __csid_ctrl_rdi(csid, enable, i);
> + }
> + }
> +}
[Severity: High]
Does unconditionally issuing CAMSS_INIT_BUF_COUNT address updates here
desynchronize the hardware write master when fewer than two buffers are
queued before VIDIOC_STREAMON?
Because vb2_queue.min_queued_buffers is 0 in msm_video_register(),
vfe_enable_output_v2() only programs VFE_BUS_WM_IMAGE_ADDR for as many
pending buffers as are actually queued (0, 1, or 2):
drivers/media/platform/qcom/camss/camss-vfe.c:vfe_enable_output_v2() {
for (i = 0; i < CAMSS_INIT_BUF_COUNT; i++) {
output->buf[i] = vfe_buf_get_pending(output);
if (!output->buf[i])
break;
output->gen2.active_num++;
ops->vfe_wm_update(vfe, output->wm_idx[0],
output->buf[i]->addr[0], line);
if (!ops->addr_update)
ops->reg_update(vfe, line->id);
}
}
csid_configure_stream() then runs and triggers two __csid_addr_update()
strobes even if 0 or 1 buffer was written to VFE_BUS_WM_IMAGE_ADDR (and also
when enable is 0 or on other link-enabled RDI ports in csid->phy.en_vc).
Latching uninitialized or duplicate buffer addresses into the hardware FIFO
and then issuing further addr_update strobes from vfe_queue_buffer_v2() when
buffers arrive while active_num < 2 corrupts buffer tracking and DMA target
addresses.
[ ... ]
> +const struct csid_hw_ops csid_ops_1190 = {
> + .configure_stream = csid_configure_stream,
> + .configure_testgen_pattern = csid_configure_testgen_pattern,
> + .hw_version = csid_hw_version,
> + .isr = csid_isr,
> + .reset = csid_reset,
> + .src_pad_code = csid_src_pad_code,
> + .subdev_init = csid_subdev_init,
> + .reg_update = csid_subdev_reg_update,
> + .addr_update = csid_subdev_addr_update,
> +};
[Severity: Low]
This isn't a bug, but camss-csid-1190.c is register-for-register and
functionally identical to camss-csid-1080.c, including the unused local
variable lane_cnt in __csid_configure_rdi_stream(). Could csid_res_hawi
reuse csid_ops_1080 directly instead of duplicating the file, and could
camss-vfe-1190.c share the identical helper functions with camss-vfe-1080.c?
> diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> index 7976796dca598..70d4306581a23 100644
> --- a/drivers/media/platform/qcom/camss/camss.c
> +++ b/drivers/media/platform/qcom/camss/camss.c
> @@ -4308,6 +4308,218 @@ static const struct resources_icc icc_res_sa8775p[] = {
> },
> };
>
> +static const struct camss_subdev_resources vfe_res_hawi[] = {
> + /* VFE0 - TFE Full */
> + {
> + .clock = { "vfe0_fast_ahb", "vfe0", "cpas_vfe0",
> + "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
> + "cpas_mnoc_hf", "cpas_mnoc_sf" },
> + .clock_rate = { { 0 },
> + { 238200000, 397000000, 440000000, 480000000,
> + 630000000, 750000000, 833000000 },
> + { 0 },
> + { 171428571, 240000000, 300000000, 400000000,
> + 480000000, 600000000 },
[Severity: Medium]
Do the camnoc_rt_axi frequencies in vfe_res_hawi (VFE0 through VFE4) match
the Hawi CAMCC clock driver?
In drivers/clk/qcom/camcc-hawi.c, ftbl_cam_cc_camnoc_rt_axi_clk_src defines
the supported rates on Hawi as 19.2 MHz, 120 MHz, 160 MHz, 240 MHz, 320 MHz,
and a maximum of 480 MHz:
drivers/clk/qcom/camcc-hawi.c:
static const struct freq_tbl ftbl_cam_cc_camnoc_rt_axi_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
F(120000000, P_CAM_CC_PLL6_OUT_EVEN, 4, 0, 0),
F(160000000, P_CAM_CC_PLL6_OUT_EVEN, 3, 0, 0),
F(240000000, P_CAM_CC_PLL6_OUT_EVEN, 2, 0, 0),
F(320000000, P_CAM_CC_PLL6_OUT_EVEN, 1.5, 0, 0),
F(480000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0),
{ }
};
When vfe_set_clock_rates() selects 600 MHz for a min_rate between 480 MHz
and 600 MHz, clk_round_rate() clamps the rate down to 480 MHz, causing a
subsequent vfe_check_clock_rates() call on the same VFE to fail with -EBUSY
because clk_get_rate() is below min_rate.
[ ... ]
> @@ -6030,6 +6242,21 @@ static const struct camss_resources sm8650_resources = {
> .vfe_num = ARRAY_SIZE(vfe_res_sm8650),
> };
>
> +static const struct camss_resources hawi_resources = {
> + .version = CAMSS_HAWI,
> + .pd_name = "top",
> + .pm_clks = { "cpas_fast_ahb", "cpas_ahb", "gcc_axi_hf" },
> + .tpg_res = tpg_res_8775p,
> + .csid_res = csid_res_hawi,
> + .vfe_res = vfe_res_hawi,
> + .icc_res = icc_res_hawi,
> + .icc_path_num = ARRAY_SIZE(icc_res_hawi),
> + .csiphy_num = 6,
> + .tpg_num = ARRAY_SIZE(tpg_res_8775p),
> + .csid_num = ARRAY_SIZE(csid_res_hawi),
> + .vfe_num = ARRAY_SIZE(vfe_res_hawi),
> +};
[Severity: Low]
Does the commit message match hawi_resources?
The changelog states that the CSIPHY resource table is reused from Kaanapali,
the TPG table is reused from X1E80100, and the common CPAS clocks are managed
as PM clocks rather than per-VFE clocks. However, hawi_resources sets
.tpg_res to tpg_res_8775p (not tpg_res_x1e80100), has no .csiphy_res table,
and vfe_res_hawi still lists the shared cpas_mnoc_hf and cpas_mnoc_sf clocks
in every VFE entry rather than in .pm_clks.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261106-hawi-maili-camss-v4-0-d528c7a797b4@oss.qualcomm.com?part=6
^ permalink raw reply [flat|nested] 9+ messages in thread