Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] drm/bridge: add glue driver for T-Head TH1520 DW MIPI DSI
@ 2026-10-30  7:47 Icenowy Zheng
  2026-10-30  7:47 ` [PATCH 1/3] dt-bindings: display: bridge: document TH1520 MIPI DSI controller Icenowy Zheng
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Icenowy Zheng @ 2026-10-30  7:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sandy Huang,
	Heiko Stübner, Andy Yan
  Cc: dri-devel, devicetree, linux-kernel, linux-rockchip,
	linux-arm-kernel, linux-riscv, Icneowy Zheng, Han Gao,
	Icenowy Zheng

T-Head TH1520 contains a DesignWare MIPI DSI host controller paired with
an internal DesignWare PHY, as a similar design (but with a different
PHY) with the Rockchip DW MIPI DSI.

The functionality to write to the PHY is shared between these two
implementations of DW MIPI DSI, so it's extracted from the Rockchip
driver to the common code. (The same sequence could be seen in the
HiSilicon Kirin DRM driver, but that one hasn't been converted to common
DW MIPI DSI.)

Tested on a Lichee Console 4A (with a Mingjun MJ070BI30IA2 panel) with
further pending DT patches.

One question remains: I have to copy the extra lane bandwidth headroom
from the Rockchip driver, otherwise the Mingjun panel cannot keep sync
to the display signal; from my testing, changing the hardcoded
PHY_STOP_WAIT_TIME from 0x20 to 0x2 (which is written by the vendor
driver) can also make this panel to work w/o the extra headroom. I want
some advice on whether to keep the extra headroom or changing the common
code to make the PHY_STOP_WAIT_TIME parameter adjustable.

Signed-off-by: Icenowy Zheng <zhengxingda@iscas.ac.cn>
---
Icenowy Zheng (3):
      dt-bindings: display: bridge: document TH1520 MIPI DSI controller
      drm/bridge: dw-mipi-dsi: add PHY write function
      drm/bridge: add TH1520 DesignWare MIPI DSI host controller

 .../display/bridge/thead,th1520-dw-mipi-dsi.yaml   | 102 ++++
 drivers/gpu/drm/bridge/Kconfig                     |  10 +
 drivers/gpu/drm/bridge/Makefile                    |   1 +
 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c      |  21 +
 drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c        | 530 +++++++++++++++++++++
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c    |  86 ++--
 include/drm/bridge/dw_mipi_dsi.h                   |   3 +
 7 files changed, 700 insertions(+), 53 deletions(-)
---
base-commit: c03c1a14507dfaf8b856c2608f9ac216021fc222
change-id: 20261030-th1520-dw-mipi-dsi-580d5b2792f9

Best regards,
--  
Icenowy Zheng <zhengxingda@iscas.ac.cn>



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/3] dt-bindings: display: bridge: document TH1520 MIPI DSI controller
  2026-10-30  7:47 [PATCH 0/3] drm/bridge: add glue driver for T-Head TH1520 DW MIPI DSI Icenowy Zheng
@ 2026-10-30  7:47 ` Icenowy Zheng
  2026-10-30  7:47 ` [PATCH 2/3] drm/bridge: dw-mipi-dsi: add PHY write function Icenowy Zheng
  2026-10-30  7:47 ` [PATCH 3/3] drm/bridge: add TH1520 DesignWare MIPI DSI host controller Icenowy Zheng
  2 siblings, 0 replies; 5+ messages in thread
From: Icenowy Zheng @ 2026-10-30  7:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sandy Huang,
	Heiko Stübner, Andy Yan
  Cc: dri-devel, devicetree, linux-kernel, linux-rockchip,
	linux-arm-kernel, linux-riscv, Icneowy Zheng, Han Gao,
	Icenowy Zheng

T-Head TH1520 SoC contains two DesignWare MIPI DSI host controllers.

Add a binding document for them, referencing the common dw-mipi-dsi
binding file.

Signed-off-by: Icenowy Zheng <zhengxingda@iscas.ac.cn>
---
 .../display/bridge/thead,th1520-dw-mipi-dsi.yaml   | 102 +++++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/bridge/thead,th1520-dw-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/bridge/thead,th1520-dw-mipi-dsi.yaml
new file mode 100644
index 0000000000000..23c249f1c1b71
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/thead,th1520-dw-mipi-dsi.yaml
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/thead,th1520-dw-mipi-dsi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: T-Head TH1520 DesignWare MIPI DSI Host Controller
+
+maintainers:
+  - Icenowy Zheng <zhengxingda@iscas.ac.cn>
+
+description:
+  The MIPI DSI host controller in TH1520 is a Synopsys DesignWare MIPI DSI
+  host controller paired with an integrated Synopsys MIPI D-PHY.
+
+allOf:
+  - $ref: snps,dw-mipi-dsi.yaml#
+
+properties:
+  compatible:
+    const: thead,th1520-dw-mipi-dsi
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: DSI controller APB clock
+      - description: PHY configuration clock
+      - description: PHY reference clock
+      - description: DSI controller input pixel clock gate
+
+  clock-names:
+    items:
+      - const: pclk
+      - const: phy_cfg
+      - const: ref
+      - const: pixel
+
+  syscon:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to the VO subsystem system controller.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - interrupts
+  - syscon
+  - ports
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/thead,th1520-clk-ap.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/reset/thead,th1520-reset.h>
+
+    soc {
+      #address-cells = <2>;
+      #size-cells = <2>;
+
+      dsi0: dsi@ffef500000 {
+        compatible = "thead,th1520-dw-mipi-dsi";
+        reg = <0xff 0xef500000 0x0 0x1000>;
+        interrupts = <119 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clk_vo CLK_MIPI_DSI0_PCLK>,
+                 <&clk_vo CLK_MIPI_DSI0_CFG>,
+                 <&clk_vo CLK_MIPI_DSI0_REFCLK>,
+                 <&clk_vo CLK_MIPIDSI0_PIXCLK>;
+        clock-names = "pclk", "phy_cfg", "ref", "pixel";
+        resets = <&rst TH1520_RESET_ID_DSI0_APB>;
+        reset-names = "apb";
+        syscon = <&syscon_vo>;
+
+        ports {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          port@0 {
+            reg = <0>;
+
+            dsi0_in: endpoint {
+              remote-endpoint = <&dpu_out_dpi0>;
+            };
+          };
+
+          dsi0_out_port: port@1 {
+            reg = <1>;
+
+            dsi0_out_panel: endpoint {
+              remote-endpoint = <&panel_in>;
+            };
+          };
+        };
+      };
+    };

-- 
2.56.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] drm/bridge: dw-mipi-dsi: add PHY write function
  2026-10-30  7:47 [PATCH 0/3] drm/bridge: add glue driver for T-Head TH1520 DW MIPI DSI Icenowy Zheng
  2026-10-30  7:47 ` [PATCH 1/3] dt-bindings: display: bridge: document TH1520 MIPI DSI controller Icenowy Zheng
@ 2026-10-30  7:47 ` Icenowy Zheng
  2026-10-30  7:47 ` [PATCH 3/3] drm/bridge: add TH1520 DesignWare MIPI DSI host controller Icenowy Zheng
  2 siblings, 0 replies; 5+ messages in thread
From: Icenowy Zheng @ 2026-10-30  7:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sandy Huang,
	Heiko Stübner, Andy Yan
  Cc: dri-devel, devicetree, linux-kernel, linux-rockchip,
	linux-arm-kernel, linux-riscv, Icneowy Zheng, Han Gao,
	Icenowy Zheng

The dw_mipi_dsi_phy_write() function in the rockchip glue code only
accesses registers defined in the DSI host controller, and the same
process is also present in the kirin dw_drm_dsi driver (which isn't
converted to use the common dw-mipi-dsi code yet) and downstream DSI
driver for T-Head TH1520.

Move this function from dw-mipi-dsi-rockchip driver to the common
dw-mipi-dsi code, and change "test code" (which seems to be the name
used for addresses by DW DPHY) to "address" (which seems to be the name
used by the DW DSI host controller).

Signed-off-by: Icenowy Zheng <zhengxingda@iscas.ac.cn>
---
 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c   | 21 ++++++
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 86 ++++++++++---------------
 include/drm/bridge/dw_mipi_dsi.h                |  3 +
 3 files changed, 57 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index 5dd475fcaacf8..87f210ba113ee 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -1104,6 +1104,27 @@ static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
 	.attach			= dw_mipi_dsi_bridge_attach,
 };
 
+void dw_mipi_dsi_phy_write(struct dw_mipi_dsi *dsi, u8 addr, u8 data)
+{
+	/*
+	 * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
+	 * is latched internally as the current address. Data is programmed
+	 * internally by rising edge on TESTCLK.
+	 */
+	dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
+
+	dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN | PHY_TESTDOUT(0) |
+					  PHY_TESTDIN(addr));
+
+	dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
+
+	dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_UNTESTEN | PHY_TESTDOUT(0) |
+					  PHY_TESTDIN(data));
+
+	dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
+}
+EXPORT_SYMBOL_GPL(dw_mipi_dsi_phy_write);
+
 #ifdef CONFIG_DEBUG_FS
 
 static int dw_mipi_dsi_debugfs_write(void *data, u64 val)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 268d4993a04fd..469123620f302 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -379,28 +379,6 @@ static inline void dsi_write(struct dw_mipi_dsi_rockchip *dsi, u32 reg, u32 val)
 	writel(val, dsi->base + reg);
 }
 
-static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi_rockchip *dsi,
-				  u8 test_code,
-				  u8 test_data)
-{
-	/*
-	 * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
-	 * is latched internally as the current test code. Test data is
-	 * programmed internally by rising edge on TESTCLK.
-	 */
-	dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
-
-	dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN | PHY_TESTDOUT(0) |
-					  PHY_TESTDIN(test_code));
-
-	dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
-
-	dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_UNTESTEN | PHY_TESTDOUT(0) |
-					  PHY_TESTDIN(test_data));
-
-	dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
-}
-
 /*
  * ns2bc - Nanoseconds to byte clock cycles
  */
@@ -420,6 +398,7 @@ static inline unsigned int ns2ui(struct dw_mipi_dsi_rockchip *dsi, int ns)
 static int dw_mipi_dsi_phy_init(void *priv_data)
 {
 	struct dw_mipi_dsi_rockchip *dsi = priv_data;
+	struct dw_mipi_dsi *dmd = dsi->dmd;
 	int ret, i, vco;
 
 	if (dsi->phy)
@@ -453,24 +432,24 @@ static int dw_mipi_dsi_phy_init(void *priv_data)
 		return ret;
 	}
 
-	dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
 			      BYPASS_VCO_RANGE |
 			      VCO_RANGE_CON_SEL(vco) |
 			      VCO_IN_CAP_CON_LOW |
 			      REF_BIAS_CUR_SEL);
 
-	dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
+	dw_mipi_dsi_phy_write(dmd, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
 			      CP_CURRENT_SEL(dppa_map[i].icpctrl));
-	dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, PLL_LPF_AND_CP_CONTROL,
 			      CP_PROGRAM_EN | LPF_PROGRAM_EN |
 			      LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
 
-	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
+	dw_mipi_dsi_phy_write(dmd, HS_RX_CONTROL_OF_LANE_0,
 			      HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
 
-	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
+	dw_mipi_dsi_phy_write(dmd, PLL_INPUT_DIVIDER_RATIO,
 			      INPUT_DIVIDER(dsi->input_div));
-	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
+	dw_mipi_dsi_phy_write(dmd, PLL_LOOP_DIVIDER_RATIO,
 			      LOOP_DIV_LOW_SEL(dsi->feedback_div) |
 			      LOW_PROGRAM_EN);
 	/*
@@ -479,53 +458,53 @@ static int dw_mipi_dsi_phy_init(void *priv_data)
 	 * and lab test results.
 	 * Only in this way can we get correct mipi phy pll frequency.
 	 */
-	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
 			      PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
-	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
+	dw_mipi_dsi_phy_write(dmd, PLL_LOOP_DIVIDER_RATIO,
 			      LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
 			      HIGH_PROGRAM_EN);
-	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
 			      PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
 
-	dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
+	dw_mipi_dsi_phy_write(dmd, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
 			      LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
-	dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
+	dw_mipi_dsi_phy_write(dmd, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
 			      HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
 
-	dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, BANDGAP_AND_BIAS_CONTROL,
 			      POWER_CONTROL | INTERNAL_REG_CURRENT |
 			      BIAS_BLOCK_ON | BANDGAP_ON);
 
-	dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, TERMINATION_RESISTER_CONTROL,
 			      TER_RESISTOR_LOW | TER_CAL_DONE |
 			      SETRD_MAX | TER_RESISTORS_ON);
-	dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, TERMINATION_RESISTER_CONTROL,
 			      TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
 			      SETRD_MAX | POWER_MANAGE |
 			      TER_RESISTORS_ON);
 
-	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
 			      TLP_PROGRAM_EN | ns2bc(dsi, 500));
-	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
 			      THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
-	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
 			      THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
-	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
 			      THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
-	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
 			      BIT(5) | ns2bc(dsi, 100));
-	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
 			      BIT(5) | (ns2bc(dsi, 60) + 7));
 
-	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
 			      TLP_PROGRAM_EN | ns2bc(dsi, 500));
-	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
 			      THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 20));
-	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
 			      THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
-	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
 			      THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
-	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
+	dw_mipi_dsi_phy_write(dmd, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
 			      BIT(5) | ns2bc(dsi, 100));
 
 	clk_disable_unprepare(dsi->phy_cfg_clk);
@@ -1224,6 +1203,7 @@ static int dw_mipi_dsi_dphy_configure(struct phy *phy, union phy_configure_opts
 static int dw_mipi_dsi_dphy_power_on(struct phy *phy)
 {
 	struct dw_mipi_dsi_rockchip *dsi = phy_get_drvdata(phy);
+	struct dw_mipi_dsi *dmd = dsi->dmd;
 	int i, ret;
 
 	DRM_DEV_DEBUG(dsi->dev, "lanes %d - data_rate_mbps %u\n",
@@ -1273,15 +1253,15 @@ static int dw_mipi_dsi_dphy_power_on(struct phy *phy)
 	 * Configure hsfreqrange according to frequency values
 	 * Set clock lane and hsfreqrange by lane0(test code 0x44)
 	 */
-	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_CLK, 0);
-	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
+	dw_mipi_dsi_phy_write(dmd, HS_RX_CONTROL_OF_LANE_CLK, 0);
+	dw_mipi_dsi_phy_write(dmd, HS_RX_CONTROL_OF_LANE_0,
 			      HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
-	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_1, 0);
-	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_2, 0);
-	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_3, 0);
+	dw_mipi_dsi_phy_write(dmd, HS_RX_CONTROL_OF_LANE_1, 0);
+	dw_mipi_dsi_phy_write(dmd, HS_RX_CONTROL_OF_LANE_2, 0);
+	dw_mipi_dsi_phy_write(dmd, HS_RX_CONTROL_OF_LANE_3, 0);
 
 	/* Normal operation */
-	dw_mipi_dsi_phy_write(dsi, 0x0, 0);
+	dw_mipi_dsi_phy_write(dmd, 0x0, 0);
 
 	clk_disable_unprepare(dsi->phy_cfg_clk);
 	clk_disable_unprepare(dsi->grf_clk);
diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h
index 65d5e68065e3d..16fa3ffd434f1 100644
--- a/include/drm/bridge/dw_mipi_dsi.h
+++ b/include/drm/bridge/dw_mipi_dsi.h
@@ -85,4 +85,7 @@ void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi);
 void dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave);
 struct drm_bridge *dw_mipi_dsi_get_bridge(struct dw_mipi_dsi *dsi);
 
+/* PHY configuration */
+void dw_mipi_dsi_phy_write(struct dw_mipi_dsi *dsi, u8 addr, u8 data);
+
 #endif /* __DW_MIPI_DSI__ */

-- 
2.56.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] drm/bridge: add TH1520 DesignWare MIPI DSI host controller
  2026-10-30  7:47 [PATCH 0/3] drm/bridge: add glue driver for T-Head TH1520 DW MIPI DSI Icenowy Zheng
  2026-10-30  7:47 ` [PATCH 1/3] dt-bindings: display: bridge: document TH1520 MIPI DSI controller Icenowy Zheng
  2026-10-30  7:47 ` [PATCH 2/3] drm/bridge: dw-mipi-dsi: add PHY write function Icenowy Zheng
@ 2026-10-30  7:47 ` Icenowy Zheng
  2026-10-31  2:04   ` kernel test robot
  2 siblings, 1 reply; 5+ messages in thread
From: Icenowy Zheng @ 2026-10-30  7:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sandy Huang,
	Heiko Stübner, Andy Yan
  Cc: dri-devel, devicetree, linux-kernel, linux-rockchip,
	linux-arm-kernel, linux-riscv, Icneowy Zheng, Han Gao,
	Icenowy Zheng

The T-Head TH1520 SoC contains a Synopsys DesignWare MIPI DSI host
controller with an internal DesignWare MIPI D-PHY.

Add a glue driver configuring clocks and PHY parameters for it.

Signed-off-by: Icenowy Zheng <zhengxingda@iscas.ac.cn>
---
 drivers/gpu/drm/bridge/Kconfig              |  10 +
 drivers/gpu/drm/bridge/Makefile             |   1 +
 drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c | 530 ++++++++++++++++++++++++++++
 3 files changed, 541 insertions(+)

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 4a57d49b4c6d3..b005623ba26bf 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -375,6 +375,16 @@ config DRM_THEAD_TH1520_DW_HDMI
 	  Choose this to enable support for the internal HDMI bridge found
 	  on the T-Head TH1520 SoC.
 
+config DRM_THEAD_TH1520_DW_MIPI_DSI
+	tristate "T-Head TH1520 DesignWare MIPI DSI bridge"
+	depends on OF
+	depends on COMMON_CLK
+	depends on ARCH_THEAD || COMPILE_TEST
+	select DRM_DW_MIPI_DSI
+	help
+	  Choose this to enable support for the internal MIPI DSI bridge
+	  found on the T-Head TH1520 SoC.
+
 config DRM_TOSHIBA_TC358762
 	tristate "TC358762 DSI/DPI bridge"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 15cc821d85b7e..5af871ba5ce77 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_DRM_SII9234) += sii9234.o
 obj-$(CONFIG_DRM_SIMPLE_BRIDGE) += simple-bridge.o
 obj-$(CONFIG_DRM_SOLOMON_SSD2825) += ssd2825.o
 obj-$(CONFIG_DRM_THEAD_TH1520_DW_HDMI) += th1520-dw-hdmi.o
+obj-$(CONFIG_DRM_THEAD_TH1520_DW_MIPI_DSI) += th1520-dw-mipi-dsi.o
 obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o
 obj-$(CONFIG_DRM_TOSHIBA_TC358762) += tc358762.o
 obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o
diff --git a/drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c b/drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c
new file mode 100644
index 0000000000000..e5c7c5d6dcc71
--- /dev/null
+++ b/drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c
@@ -0,0 +1,530 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 Institute of Software, Chinese Academy of Sciences (ISCAS)
+ *
+ * Author:
+ *   Icenowy Zheng <zhengxingda@iscas.ac.cn>
+ *
+ * Based on dw_mipi_dsi-stm.c, which is:
+ *   Copyright (C) STMicroelectronics SA 2017
+ *
+ * Based on dw-mipi-dsi-rockchip.c, which is:
+ *   Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Based on vendor kernel phy-dw-mipi-dphy.c, which is:
+ *   Copyright (C) Alibaba Group Holding Limited.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/bridge/dw_mipi_dsi.h>
+#include <drm/drm_mipi_dsi.h>
+
+/* DPHY registers */
+
+#define PLL_DELAY_LP_TX_START_LP11	0x02
+#define TXDINDLYTIME_9_2		GENMASK(7,  0)
+
+#define PLL_FSM_CNTRL			0x03
+
+#define PLL_PROP_CHARGE_PUMP_CTRL	0x0e
+#define PLL_PROP_CNTRL			GENMASK(5,  0)
+
+#define PLL_INT_CHARGE_PUMP_CTRL	0x0f
+#define PLL_INT_CNTRL			GENMASK(5,  0)
+
+#define PLL_VCO_CTRL			0x12
+#define PLL_VCO_CNTRL_OVR_EN		BIT(6)
+#define PLL_VCO_CNTRL_OVR		GENMASK(5,  0)
+
+#define PLL_GMP_CTRL_DIGITAL_TEST	0x13
+#define PLL_TESTLOCK			BIT(7)
+#define PLL_GMP_CNTRL			GENMASK(5,  4)
+#define TSTPLLDIG			GENMASK(3,  1)
+#define TSTPLLDIG_LOCK			(0x0 << 1)
+#define TSTPLLDIG_REFCLK		(0x1 << 1)
+#define TSTPLLDIG_FBCLK			(0x2 << 1)
+#define TSTPLLDIG_INT_CLKIN		(0x3 << 1)
+#define TSTPLLDIG_LOCK_FROM_DETECTOR	(0x4 << 1)
+#define TSTPLLDIG_OUTPUT		(0x5 << 1)
+#define TSTPLLDIG_BUF_VCOCLK		(0x6 << 1)
+#define TSTPLLDIG_UPDATEPLL		(0x7 << 1)
+
+#define PLL_N_DIV_FSM_SIG		0x17
+#define PLL_N_OVR			GENMASK(3,  0)
+
+#define PLL_M_DIV			0x18
+#define PLL_M_OVR_4_0			GENMASK(4,  0)
+#define PLL_M_OVR_9_5			GENMASK(4,  0)
+
+#define PLL_N_AND_M_DIV_CTRL		0x19
+#define PLL_M_OVR_EN			BIT(5)
+#define PLL_N_OVR_EN			BIT(4)
+
+#define PLL_CHARGE_PUMP_BIAS_CTRL	0x1c
+#define PLL_CPBIAS_CNTRL		GENMASK(6,  0)
+
+#define PLL_ANALOG_PROGRAM_CONTROL	0x1f
+#define PLL_MPLL_PROG_5_0		GENMASK(5,  0)
+#define PLL_MPLL_PROG_11_6		GENMASK(5,  0)
+#define PLL_MPLL_PROG_16_12		GENMASK(4,  0)
+
+#define HS_FREQ_RANGE_OF_OPERATION	0x44
+#define HSFREQRANGE_OVR_EN		BIT(7)
+#define HSFREQRANGE_OVR			GENMASK(6,  0)
+#define HSFREQRANGE			HSFREQRANGE_OVR
+
+#define PG_LP_BIAS_LANE0		0x4a
+#define PRG_ON_LANE0			BIT(6)
+
+#define SR_FSM_OVR_CNTRL		0xa0
+#define SR_DDL_LOOP_CONF		0xa3
+
+/* syscon registers */
+
+#define MIPIDSI0_SYSREG			0x8
+#define MIPIDSI1_SYSREG			0xc
+#define MIPIDSI_HSFREQRANGE		GENMASK(9,  3)
+#define MIPIDSI_CFGCLKFREQRANGE		GENMASK(15, 10)
+#define MIPIDSI_CFGCLKFREQRANGE_DEF	(0x1c << 10)
+
+struct pll_hsfreqrange {
+	unsigned int max_mbps;
+	u8 hsfreqrange;
+};
+
+static const struct pll_hsfreqrange hsfreqrange_table[] = {
+	{ 80,  0x00 },
+	{ 90,  0x10 },
+	{ 100, 0x20 },
+	{ 110, 0x30 },
+	{ 120, 0x01 },
+	{ 130, 0x11 },
+	{ 140, 0x21 },
+	{ 150, 0x31 },
+	{ 160, 0x02 },
+	{ 170, 0x12 },
+	{ 180, 0x22 },
+	{ 190, 0x32 },
+	{ 205, 0x03 },
+	{ 220, 0x13 },
+	{ 235, 0x23 },
+	{ 250, 0x33 },
+	{ 275, 0x04 },
+	{ 300, 0x14 },
+	{ 325, 0x25 },
+	{ 350, 0x35 },
+	{ 400, 0x05 },
+	{ 450, 0x16 },
+	{ 500, 0x26 },
+	{ 550, 0x37 },
+	{ 600, 0x07 },
+	{ 650, 0x18 },
+	{ 700, 0x28 },
+	{ 750, 0x39 },
+	{ 800, 0x09 },
+	{ 850, 0x19 },
+	{ 900, 0x29 },
+	{ 950, 0x3A },
+	{ 1000, 0x0A },
+	{ 1050, 0x1A },
+	{ 1100, 0x2A },
+	{ 1150, 0x3B },
+	{ 1200, 0x0B },
+	{ 1250, 0x1B },
+	{ 1300, 0x2B },
+	{ 1350, 0x3C },
+	{ 1400, 0x0C },
+	{ 1450, 0x1C },
+	{ 1500, 0x2C },
+	{ 1550, 0x3D },
+	{ 1600, 0x0D },
+	{ 1650, 0x1D },
+	{ 1700, 0x2E },
+	{ 1750, 0x3E },
+	{ 1800, 0x0E },
+	{ 1850, 0x1E },
+	{ 1900, 0x2F },
+	{ 1950, 0x3F },
+	{ 2000, 0x0F },
+	{ 2050, 0x40 },
+	{ 2100, 0x41 },
+	{ 2150, 0x42 },
+	{ 2200, 0x43 },
+	{ 2250, 0x44 },
+	{ 2300, 0x45 },
+	{ 2350, 0x46 },
+	{ 2400, 0x47 },
+	{ 2450, 0x48 },
+	{ 2500, 0x49 },
+};
+
+struct hstt {
+	unsigned int max_mbps;
+	struct dw_mipi_dsi_dphy_timing timing;
+};
+
+#define HSTT(_max_mbps, _c_lp2hs, _c_hs2lp, _d_lp2hs, _d_hs2lp)	\
+{					\
+	.max_mbps = _max_mbps,		\
+	.timing = {			\
+		.clk_lp2hs = _c_lp2hs,	\
+		.clk_hs2lp = _c_hs2lp,	\
+		.data_lp2hs = _d_lp2hs,	\
+		.data_hs2lp = _d_hs2lp,	\
+	}				\
+}
+
+static struct hstt hstt_table[] = {
+	HSTT(80, 21, 17, 15, 10),
+	HSTT(90, 23, 17, 16, 10),
+	HSTT(100, 22, 17, 16, 10),
+	HSTT(110, 25, 18, 17, 11),
+	HSTT(120, 26, 20, 18, 11),
+	HSTT(130, 27, 19, 19, 11),
+	HSTT(140, 27, 19, 19, 11),
+	HSTT(150, 28, 20, 20, 12),
+	HSTT(160, 30, 21, 22, 13),
+	HSTT(170, 30, 21, 23, 13),
+	HSTT(180, 31, 21, 23, 13),
+	HSTT(190, 32, 22, 24, 13),
+	HSTT(205, 35, 22, 25, 13),
+	HSTT(220, 37, 26, 27, 15),
+	HSTT(235, 38, 28, 27, 16),
+	HSTT(250, 41, 29, 30, 17),
+	HSTT(275, 43, 29, 32, 18),
+	HSTT(300, 45, 32, 35, 19),
+	HSTT(325, 48, 33, 36, 18),
+	HSTT(350, 51, 35, 40, 20),
+	HSTT(400, 59, 37, 44, 21),
+	HSTT(450, 65, 40, 49, 23),
+	HSTT(500, 71, 41, 54, 24),
+	HSTT(550, 77, 44, 57, 26),
+	HSTT(600, 82, 46, 64, 27),
+	HSTT(650, 87, 48, 67, 28),
+	HSTT(700, 94, 52, 71, 29),
+	HSTT(750, 99, 52, 75, 31),
+	HSTT(800, 105, 55, 82, 32),
+	HSTT(850, 110, 58, 85, 32),
+	HSTT(900, 115, 58, 88, 35),
+	HSTT(950, 120, 62, 93, 36),
+	HSTT(1000, 128, 63, 99, 38),
+	HSTT(1050, 132, 65, 102, 38),
+	HSTT(1100, 138, 67, 106, 39),
+	HSTT(1150, 146, 69, 112, 42),
+	HSTT(1200, 151, 71, 117, 43),
+	HSTT(1250, 153, 74, 120, 45),
+	HSTT(1300, 160, 73, 124, 46),
+	HSTT(1350, 165, 76, 130, 47),
+	HSTT(1400, 172, 78, 134, 49),
+	HSTT(1450, 177, 80, 138, 49),
+	HSTT(1500, 183, 81, 143, 52),
+	HSTT(1550, 191, 84, 147, 52),
+	HSTT(1600, 194, 85, 152, 52),
+	HSTT(1650, 201, 86, 155, 53),
+	HSTT(1700, 208, 88, 161, 53),
+	HSTT(1750, 212, 89, 165, 53),
+	HSTT(1800, 220, 90, 171, 54),
+	HSTT(1850, 223, 92, 175, 54),
+	HSTT(1900, 231, 91, 180, 55),
+	HSTT(1950, 236, 95, 185, 56),
+	HSTT(2000, 243, 97, 190, 56),
+	HSTT(2050, 248, 99, 194, 58),
+	HSTT(2100, 252, 100, 199, 59),
+	HSTT(2150, 259, 102, 204, 61),
+	HSTT(2200, 266, 105, 210, 62),
+	HSTT(2250, 269, 109, 213, 63),
+	HSTT(2300, 272, 109, 217, 65),
+	HSTT(2350, 281, 112, 225, 66),
+	HSTT(2400, 283, 115, 226, 66),
+	HSTT(2450, 282, 115, 226, 67),
+	HSTT(2500, 281, 118, 227, 67),
+};
+
+struct dsi_chip_data {
+	u64 reg;
+
+	u32 sysreg;
+};
+
+struct th1520_dw_mipi_dsi {
+	struct device *dev;
+
+	struct dw_mipi_dsi *dmd;
+	struct dw_mipi_dsi_plat_data pdata;
+	const struct dsi_chip_data *cdata;
+
+	struct regmap *syscon;
+	struct clk *clk_pix;
+	struct clk *clk_ref;
+	struct clk *clk_cfg;
+
+	unsigned int lane_mbps;
+	u8 hsfreqrange;
+};
+
+static int dsi_phy_init(void *priv_data)
+{
+	struct th1520_dw_mipi_dsi *dsi = priv_data;
+	u32 val;
+
+	val = FIELD_PREP(MIPIDSI_HSFREQRANGE, dsi->hsfreqrange) |
+	      MIPIDSI_CFGCLKFREQRANGE_DEF;
+
+	regmap_update_bits(dsi->syscon, dsi->cdata->sysreg,
+			   MIPIDSI_HSFREQRANGE | MIPIDSI_CFGCLKFREQRANGE, val);
+
+	/* disable slew rate calibration */
+	dw_mipi_dsi_phy_write(dsi->dmd, SR_DDL_LOOP_CONF, 0);
+	dw_mipi_dsi_phy_write(dsi->dmd, SR_FSM_OVR_CNTRL, 1);
+
+	/* configure prg_on_lane0 */
+	dw_mipi_dsi_phy_write(dsi->dmd, PG_LP_BIAS_LANE0, PRG_ON_LANE0);
+
+	/* configure PLL charge pump */
+	if (dsi->lane_mbps >= 1150)
+		dw_mipi_dsi_phy_write(dsi->dmd, PLL_PROP_CHARGE_PUMP_CTRL, 0xE);
+	else
+		dw_mipi_dsi_phy_write(dsi->dmd, PLL_PROP_CHARGE_PUMP_CTRL, 0x8);
+	dw_mipi_dsi_phy_write(dsi->dmd, PLL_CHARGE_PUMP_BIAS_CTRL, 0x10);
+
+	return 0;
+}
+
+static void dsi_phy_power_on(void *priv_data)
+{
+	struct th1520_dw_mipi_dsi *dsi = priv_data;
+
+	clk_prepare_enable(dsi->clk_pix);
+}
+
+static void dsi_phy_power_off(void *priv_data)
+{
+	struct th1520_dw_mipi_dsi *dsi = priv_data;
+
+	clk_disable_unprepare(dsi->clk_pix);
+}
+
+static unsigned int
+calculate_lane_mbps(const struct drm_display_mode *mode,
+		    unsigned long mode_flags,
+		    u32 lanes, u32 format)
+{
+	int bpp = mipi_dsi_pixel_format_to_bpp(format);
+	union phy_configure_opts phy_opts;
+
+	/*
+	 * FIXME: the extra bandwidth headroom logic mimics what the Rockchip
+	 * driver does, and test shows that it's necessary for the hardware
+	 * to work with the mainline dw-mipi-dsi common code.
+	 */
+	phy_mipi_dphy_get_default_config(mode->clock * 1000 * 10 / 8,
+					 bpp, lanes,
+					 &phy_opts.mipi_dphy);
+
+	return DIV_ROUND_UP(phy_opts.mipi_dphy.hs_clk_rate, USEC_PER_SEC);
+}
+
+static int
+dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
+		  unsigned long mode_flags, u32 lanes, u32 format,
+		  unsigned int *lane_mbps)
+{
+	struct th1520_dw_mipi_dsi *dsi = priv_data;
+	int i;
+
+	*lane_mbps = calculate_lane_mbps(mode, mode_flags, lanes, format);
+
+	for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++)
+		if (*lane_mbps <= hsfreqrange_table[i].max_mbps)
+			break;
+
+	if (i == ARRAY_SIZE(hsfreqrange_table))
+		return -EINVAL;
+
+	*lane_mbps = hsfreqrange_table[i].max_mbps;
+	dsi->lane_mbps = *lane_mbps;
+	dsi->hsfreqrange = hsfreqrange_table[i].hsfreqrange;
+
+	return 0;
+}
+
+static int
+dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
+		   struct dw_mipi_dsi_dphy_timing *timing)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hstt_table); i++)
+		if (lane_mbps <= hstt_table[i].max_mbps)
+			break;
+
+	if (i == ARRAY_SIZE(hstt_table))
+		return -EINVAL;
+
+	*timing = hstt_table[i].timing;
+
+	return 0;
+}
+
+static const struct dw_mipi_dsi_phy_ops th1520_dw_mipi_dsi_phy_ops = {
+	.init = dsi_phy_init,
+	.power_on = dsi_phy_power_on,
+	.power_off = dsi_phy_power_off,
+	.get_lane_mbps = dsi_get_lane_mbps,
+	.get_timing = dsi_phy_get_timing,
+};
+
+static enum drm_mode_status
+dsi_mode_valid(void *priv_data, const struct drm_display_mode *mode,
+	       unsigned long mode_flags, u32 lanes, u32 format)
+{
+	unsigned int lane_mbps, max_mbps;
+
+	lane_mbps = calculate_lane_mbps(mode, mode_flags, lanes, format);
+	max_mbps = hsfreqrange_table[ARRAY_SIZE(hsfreqrange_table) - 1].max_mbps;
+
+	if (lane_mbps > max_mbps)
+		return MODE_NOCLOCK;
+
+	return MODE_OK;
+}
+
+static struct dsi_chip_data th1520_chip_data[] = {
+	{
+		.reg = 0xffef500000,
+		.sysreg = MIPIDSI0_SYSREG,
+
+		/*
+		 * TODO: The user manual shows a mux register for DSI0 but the
+		 * vendor driver doesn't touch it either.
+		 */
+	},
+	{
+		.reg = 0xffef510000,
+		.sysreg = MIPIDSI1_SYSREG,
+	},
+	{ /* sentinel */ },
+};
+
+static int th1520_dw_mipi_dsi_probe(struct platform_device *pdev)
+{
+	const struct dsi_chip_data *cdata;
+	struct device *dev = &pdev->dev;
+	struct th1520_dw_mipi_dsi *dsi;
+	struct resource *res;
+	void __iomem *base;
+	int i, ret;
+
+	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+	if (!dsi)
+		return -ENOMEM;
+
+	dsi->dev = dev;
+
+	dsi->syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
+	if (IS_ERR(dsi->syscon)) {
+		ret = PTR_ERR(dsi->syscon);
+		dev_err_probe(dev, ret, "Unable to get system controller regmap\n");
+		return ret;
+	}
+
+	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(base)) {
+		dev_err_probe(dev, ret, "Unable to get DSI registers\n");
+		return PTR_ERR(base);
+	}
+
+	cdata = of_device_get_match_data(dev);
+	i = 0;
+	while (cdata[i].reg) {
+		if (cdata[i].reg == res->start) {
+			dsi->cdata = &cdata[i];
+			break;
+		}
+
+		i++;
+	}
+
+	if (!dsi->cdata) {
+		dev_err(dev, "Failed to find chip data for this controller\n");
+		return -EINVAL;
+	}
+
+	dsi->clk_ref = devm_clk_get_enabled(dev, "ref");
+	if (IS_ERR(dsi->clk_ref)) {
+		ret = PTR_ERR(dsi->clk_ref);
+		dev_err_probe(dev, ret, "Unable to get PHY reference clock\n");
+		return ret;
+	}
+
+	dsi->clk_cfg = devm_clk_get_enabled(dev, "phy_cfg");
+	if (IS_ERR(dsi->clk_cfg)) {
+		ret = PTR_ERR(dsi->clk_cfg);
+		dev_err_probe(dev, ret, "Unable to get PHY configuration clock\n");
+		return ret;
+	}
+
+	dsi->clk_pix = devm_clk_get(dev, "pixel");
+	if (IS_ERR(dsi->clk_pix)) {
+		ret = PTR_ERR(dsi->clk_pix);
+		dev_err_probe(dev, ret, "Unable to get PHY pixel clock\n");
+		return ret;
+	}
+
+	dsi->pdata.base = base;
+	dsi->pdata.priv_data = dsi;
+	dsi->pdata.max_data_lanes = 4;
+	dsi->pdata.phy_ops = &th1520_dw_mipi_dsi_phy_ops;
+	dsi->pdata.mode_valid = dsi_mode_valid;
+
+	platform_set_drvdata(pdev, dsi);
+
+	dsi->dmd = dw_mipi_dsi_probe(pdev, &dsi->pdata);
+	if (IS_ERR(dsi->dmd)) {
+		ret = PTR_ERR(dsi->dmd);
+		dev_err_probe(dev, ret, "Failed to initialize mipi dsi host\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void th1520_dw_mipi_dsi_remove(struct platform_device *pdev)
+{
+	struct th1520_dw_mipi_dsi *dsi = platform_get_drvdata(pdev);
+
+	dw_mipi_dsi_remove(dsi->dmd);
+}
+
+static const struct of_device_id th1520_dw_mipi_dsi_dt_ids[] = {
+	{ .compatible = "thead,th1520-dw-mipi-dsi", .data = &th1520_chip_data },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, th1520_dw_mipi_dsi_dt_ids);
+
+static struct platform_driver th1520_dw_mipi_dsi_driver = {
+	.probe		= th1520_dw_mipi_dsi_probe,
+	.remove		= th1520_dw_mipi_dsi_remove,
+	.driver		= {
+		.of_match_table = th1520_dw_mipi_dsi_dt_ids,
+		.name	= "th1520-dw-mipi-dsi",
+	},
+};
+
+module_platform_driver(th1520_dw_mipi_dsi_driver);
+
+MODULE_AUTHOR("Icenowy Zheng <zhengxingda@iscas.ac.cn>");
+MODULE_DESCRIPTION("T-Head TH1520 MIPI DSI host controller driver");
+MODULE_LICENSE("GPL");

-- 
2.56.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 3/3] drm/bridge: add TH1520 DesignWare MIPI DSI host controller
  2026-10-30  7:47 ` [PATCH 3/3] drm/bridge: add TH1520 DesignWare MIPI DSI host controller Icenowy Zheng
@ 2026-10-31  2:04   ` kernel test robot
  0 siblings, 0 replies; 5+ messages in thread
From: kernel test robot @ 2026-10-31  2:04 UTC (permalink / raw)
  To: Icenowy Zheng, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sandy Huang, Heiko Stübner, Andy Yan
  Cc: llvm, oe-kbuild-all, dri-devel, devicetree, linux-kernel,
	linux-rockchip, linux-arm-kernel, linux-riscv, Icneowy Zheng,
	Han Gao, Icenowy Zheng

Hi Icenowy,

kernel test robot noticed the following build warnings:

[auto build test WARNING on c03c1a14507dfaf8b856c2608f9ac216021fc222]

url:    https://github.com/intel-lab-lkp/linux/commits/Icenowy-Zheng/dt-bindings-display-bridge-document-TH1520-MIPI-DSI-controller/20261030-154749
base:   c03c1a14507dfaf8b856c2608f9ac216021fc222
patch link:    https://lore.kernel.org/r/20261030-th1520-dw-mipi-dsi-v1-3-753f34fd304f%40iscas.ac.cn
patch subject: [PATCH 3/3] drm/bridge: add TH1520 DesignWare MIPI DSI host controller
config: arm64-randconfig-1001-20261031 (https://download.01.org/0day-ci/archive/20261031/202610311004.6oZFiXBi-lkp@intel.com/config)
compiler: clang version 24.0.0git (https://github.com/llvm/llvm-project c2ea4440d4b64c148de4fdfca1fc2c437a0701e4)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261031/202610311004.6oZFiXBi-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202610311004.6oZFiXBi-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c:445:22: warning: variable 'ret' is uninitialized when used here [-Wuninitialized]
     445 |                 dev_err_probe(dev, ret, "Unable to get DSI registers\n");
         |                                    ^~~
   drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c:428:12: note: initialize the variable 'ret' to silence this warning
     428 |         int i, ret;
         |                   ^
         |                    = 0
   1 warning generated.


vim +/ret +445 drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c

   420	
   421	static int th1520_dw_mipi_dsi_probe(struct platform_device *pdev)
   422	{
   423		const struct dsi_chip_data *cdata;
   424		struct device *dev = &pdev->dev;
   425		struct th1520_dw_mipi_dsi *dsi;
   426		struct resource *res;
   427		void __iomem *base;
   428		int i, ret;
   429	
   430		dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
   431		if (!dsi)
   432			return -ENOMEM;
   433	
   434		dsi->dev = dev;
   435	
   436		dsi->syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
   437		if (IS_ERR(dsi->syscon)) {
   438			ret = PTR_ERR(dsi->syscon);
   439			dev_err_probe(dev, ret, "Unable to get system controller regmap\n");
   440			return ret;
   441		}
   442	
   443		base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
   444		if (IS_ERR(base)) {
 > 445			dev_err_probe(dev, ret, "Unable to get DSI registers\n");
   446			return PTR_ERR(base);
   447		}
   448	
   449		cdata = of_device_get_match_data(dev);
   450		i = 0;
   451		while (cdata[i].reg) {
   452			if (cdata[i].reg == res->start) {
   453				dsi->cdata = &cdata[i];
   454				break;
   455			}
   456	
   457			i++;
   458		}
   459	
   460		if (!dsi->cdata) {
   461			dev_err(dev, "Failed to find chip data for this controller\n");
   462			return -EINVAL;
   463		}
   464	
   465		dsi->clk_ref = devm_clk_get_enabled(dev, "ref");
   466		if (IS_ERR(dsi->clk_ref)) {
   467			ret = PTR_ERR(dsi->clk_ref);
   468			dev_err_probe(dev, ret, "Unable to get PHY reference clock\n");
   469			return ret;
   470		}
   471	
   472		dsi->clk_cfg = devm_clk_get_enabled(dev, "phy_cfg");
   473		if (IS_ERR(dsi->clk_cfg)) {
   474			ret = PTR_ERR(dsi->clk_cfg);
   475			dev_err_probe(dev, ret, "Unable to get PHY configuration clock\n");
   476			return ret;
   477		}
   478	
   479		dsi->clk_pix = devm_clk_get(dev, "pixel");
   480		if (IS_ERR(dsi->clk_pix)) {
   481			ret = PTR_ERR(dsi->clk_pix);
   482			dev_err_probe(dev, ret, "Unable to get PHY pixel clock\n");
   483			return ret;
   484		}
   485	
   486		dsi->pdata.base = base;
   487		dsi->pdata.priv_data = dsi;
   488		dsi->pdata.max_data_lanes = 4;
   489		dsi->pdata.phy_ops = &th1520_dw_mipi_dsi_phy_ops;
   490		dsi->pdata.mode_valid = dsi_mode_valid;
   491	
   492		platform_set_drvdata(pdev, dsi);
   493	
   494		dsi->dmd = dw_mipi_dsi_probe(pdev, &dsi->pdata);
   495		if (IS_ERR(dsi->dmd)) {
   496			ret = PTR_ERR(dsi->dmd);
   497			dev_err_probe(dev, ret, "Failed to initialize mipi dsi host\n");
   498			return ret;
   499		}
   500	
   501		return 0;
   502	}
   503	

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-10-31  2:05 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-30  7:47 [PATCH 0/3] drm/bridge: add glue driver for T-Head TH1520 DW MIPI DSI Icenowy Zheng
2026-10-30  7:47 ` [PATCH 1/3] dt-bindings: display: bridge: document TH1520 MIPI DSI controller Icenowy Zheng
2026-10-30  7:47 ` [PATCH 2/3] drm/bridge: dw-mipi-dsi: add PHY write function Icenowy Zheng
2026-10-30  7:47 ` [PATCH 3/3] drm/bridge: add TH1520 DesignWare MIPI DSI host controller Icenowy Zheng
2026-10-31  2:04   ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox