linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/7] Renesas V4H DSI & DP output support
@ 2022-11-23  6:59 Tomi Valkeinen
  2022-11-23  6:59 ` [PATCH v2 1/7] dt-bindings: display: renesas,du: Provide bindings for r8a779g0 Tomi Valkeinen
                   ` (7 more replies)
  0 siblings, 8 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-23  6:59 UTC (permalink / raw)
  To: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
	Jernej Skrabec, Tomi Valkeinen

From: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>

Hi,

These add support for DSI on V4H SoC (r8a779g0) and DP for Whitehawk
board.

Changes in v2:
- A few cosmetic changes
- Increase vspd address range in dts to 0x7000
- Arrange nodes in dts by the block address
- Use gen = 4 for r8a779g0 du
- Drop the CLOCKSET1 hack patch

The CLOCKSET1 patch is apparently not needed to get the DSI & DP
working. Which is baffling, as I'm quite sure it was needed. There are a
few possible explanations: 1) it was never needed and I was just messing
things up, 2) it was needed, but some of my later improvements made it
unnecessary, 3) Whitehawk board firmware was updated in the middle of
the development of this series, possibly the firmware made the patch
unnecessary.

 Tomi

Tomi Valkeinen (7):
  dt-bindings: display: renesas,du: Provide bindings for r8a779g0
  dt-bindings: display: bridge: renesas,dsi-csi2-tx: Add r8a779g0
  clk: renesas: r8a779g0: Add display related clocks
  arm64: dts: renesas: r8a779g0: Add display related nodes
  arm64: dts: renesas: white-hawk-cpu: Add DP output support
  drm: rcar-du: Add r8a779g0 support
  drm: rcar-du: dsi: Add r8A779g0 support

 .../display/bridge/renesas,dsi-csi2-tx.yaml   |   3 +-
 .../bindings/display/renesas,du.yaml          |   2 +
 .../dts/renesas/r8a779g0-white-hawk-cpu.dtsi  |  94 ++++
 arch/arm64/boot/dts/renesas/r8a779g0.dtsi     | 130 +++++
 drivers/clk/renesas/r8a779g0-cpg-mssr.c       |  14 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.c         |  22 +
 drivers/gpu/drm/rcar-du/rcar_du_group.c       |   2 +-
 drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c       | 484 ++++++++++++++----
 drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h  |   6 +-
 9 files changed, 649 insertions(+), 108 deletions(-)

-- 
2.34.1


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

* [PATCH v2 1/7] dt-bindings: display: renesas,du: Provide bindings for r8a779g0
  2022-11-23  6:59 [PATCH v2 0/7] Renesas V4H DSI & DP output support Tomi Valkeinen
@ 2022-11-23  6:59 ` Tomi Valkeinen
  2022-11-23  6:59 ` [PATCH v2 2/7] dt-bindings: display: bridge: renesas,dsi-csi2-tx: Add r8a779g0 Tomi Valkeinen
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-23  6:59 UTC (permalink / raw)
  To: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
	Jernej Skrabec, Tomi Valkeinen, Krzysztof Kozlowski

Extend the Renesas DU display bindings to support the r8a779g0 V4H.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 Documentation/devicetree/bindings/display/renesas,du.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/renesas,du.yaml b/Documentation/devicetree/bindings/display/renesas,du.yaml
index b3e588022082..d4830f52c512 100644
--- a/Documentation/devicetree/bindings/display/renesas,du.yaml
+++ b/Documentation/devicetree/bindings/display/renesas,du.yaml
@@ -40,6 +40,7 @@ properties:
       - renesas,du-r8a77990 # for R-Car E3 compatible DU
       - renesas,du-r8a77995 # for R-Car D3 compatible DU
       - renesas,du-r8a779a0 # for R-Car V3U compatible DU
+      - renesas,du-r8a779g0 # for R-Car V4H compatible DU
 
   reg:
     maxItems: 1
@@ -762,6 +763,7 @@ allOf:
           contains:
             enum:
               - renesas,du-r8a779a0
+              - renesas,du-r8a779g0
     then:
       properties:
         clocks:
-- 
2.34.1


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

* [PATCH v2 2/7] dt-bindings: display: bridge: renesas,dsi-csi2-tx: Add r8a779g0
  2022-11-23  6:59 [PATCH v2 0/7] Renesas V4H DSI & DP output support Tomi Valkeinen
  2022-11-23  6:59 ` [PATCH v2 1/7] dt-bindings: display: renesas,du: Provide bindings for r8a779g0 Tomi Valkeinen
@ 2022-11-23  6:59 ` Tomi Valkeinen
  2022-11-23  6:59 ` [PATCH v2 3/7] clk: renesas: r8a779g0: Add display related clocks Tomi Valkeinen
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-23  6:59 UTC (permalink / raw)
  To: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
	Jernej Skrabec, Tomi Valkeinen, Krzysztof Kozlowski

Extend the Renesas DSI display bindings to support the r8a779g0 V4H.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 .../bindings/display/bridge/renesas,dsi-csi2-tx.yaml           | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml b/Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml
index afeeb967393d..d33026f85e19 100644
--- a/Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml
@@ -11,13 +11,14 @@ maintainers:
 
 description: |
   This binding describes the MIPI DSI/CSI-2 encoder embedded in the Renesas
-  R-Car V3U SoC. The encoder can operate in either DSI or CSI-2 mode, with up
+  R-Car Gen4 SoCs. The encoder can operate in either DSI or CSI-2 mode, with up
   to four data lanes.
 
 properties:
   compatible:
     enum:
       - renesas,r8a779a0-dsi-csi2-tx    # for V3U
+      - renesas,r8a779g0-dsi-csi2-tx    # for V4H
 
   reg:
     maxItems: 1
-- 
2.34.1


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

* [PATCH v2 3/7] clk: renesas: r8a779g0: Add display related clocks
  2022-11-23  6:59 [PATCH v2 0/7] Renesas V4H DSI & DP output support Tomi Valkeinen
  2022-11-23  6:59 ` [PATCH v2 1/7] dt-bindings: display: renesas,du: Provide bindings for r8a779g0 Tomi Valkeinen
  2022-11-23  6:59 ` [PATCH v2 2/7] dt-bindings: display: bridge: renesas,dsi-csi2-tx: Add r8a779g0 Tomi Valkeinen
@ 2022-11-23  6:59 ` Tomi Valkeinen
  2022-11-30 19:18   ` Geert Uytterhoeven
  2022-11-23  6:59 ` [PATCH v2 4/7] arm64: dts: renesas: r8a779g0: Add display related nodes Tomi Valkeinen
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-23  6:59 UTC (permalink / raw)
  To: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
	Jernej Skrabec, Tomi Valkeinen

Add clocks related to display which are needed to get the DSI output
working.

Extracted from Renesas BSP tree.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/clk/renesas/r8a779g0-cpg-mssr.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c
index c6337a408e5e..6937f1aee677 100644
--- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c
@@ -145,6 +145,8 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = {
 	DEF_FIXED("viobusd2",	R8A779G0_CLK_VIOBUSD2,	CLK_VIO,	2, 1),
 	DEF_FIXED("vcbus",	R8A779G0_CLK_VCBUS,	CLK_VC,		1, 1),
 	DEF_FIXED("vcbusd2",	R8A779G0_CLK_VCBUSD2,	CLK_VC,		2, 1),
+	DEF_FIXED("dsiref",	R8A779G0_CLK_DSIREF,	CLK_PLL5_DIV4,	48, 1),
+	DEF_DIV6P1("dsiext",	R8A779G0_CLK_DSIEXT,	CLK_PLL5_DIV4,	0x884),
 
 	DEF_GEN4_SDH("sd0h",	R8A779G0_CLK_SD0H,	CLK_SDSRC,	   0x870),
 	DEF_GEN4_SD("sd0",	R8A779G0_CLK_SD0,	R8A779G0_CLK_SD0H, 0x870),
@@ -161,6 +163,14 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
 	DEF_MOD("avb0",		211,	R8A779G0_CLK_S0D4_HSC),
 	DEF_MOD("avb1",		212,	R8A779G0_CLK_S0D4_HSC),
 	DEF_MOD("avb2",		213,	R8A779G0_CLK_S0D4_HSC),
+
+	DEF_MOD("dis0",			411,	R8A779G0_CLK_S0D3),
+	DEF_MOD("dsitxlink0",		415,	R8A779G0_CLK_DSIREF),
+	DEF_MOD("dsitxlink1",		416,	R8A779G0_CLK_DSIREF),
+
+	DEF_MOD("fcpvd0",		508,	R8A779G0_CLK_S0D3),
+	DEF_MOD("fcpvd1",		509,	R8A779G0_CLK_S0D3),
+
 	DEF_MOD("hscif0",	514,	R8A779G0_CLK_SASYNCPERD1),
 	DEF_MOD("hscif1",	515,	R8A779G0_CLK_SASYNCPERD1),
 	DEF_MOD("hscif2",	516,	R8A779G0_CLK_SASYNCPERD1),
@@ -193,6 +203,10 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
 	DEF_MOD("tmu3",		716,	R8A779G0_CLK_SASYNCPERD2),
 	DEF_MOD("tmu4",		717,	R8A779G0_CLK_SASYNCPERD2),
 	DEF_MOD("tpu0",		718,	R8A779G0_CLK_SASYNCPERD4),
+
+	DEF_MOD("vspd0",		830,	R8A779G0_CLK_S0D1_VIO),
+	DEF_MOD("vspd1",		831,	R8A779G0_CLK_S0D1_VIO),
+
 	DEF_MOD("wdt1:wdt0",	907,	R8A779G0_CLK_R),
 	DEF_MOD("cmt0",		910,	R8A779G0_CLK_R),
 	DEF_MOD("cmt1",		911,	R8A779G0_CLK_R),
-- 
2.34.1


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

* [PATCH v2 4/7] arm64: dts: renesas: r8a779g0: Add display related nodes
  2022-11-23  6:59 [PATCH v2 0/7] Renesas V4H DSI & DP output support Tomi Valkeinen
                   ` (2 preceding siblings ...)
  2022-11-23  6:59 ` [PATCH v2 3/7] clk: renesas: r8a779g0: Add display related clocks Tomi Valkeinen
@ 2022-11-23  6:59 ` Tomi Valkeinen
  2022-12-01  9:20   ` Geert Uytterhoeven
  2022-11-23  6:59 ` [PATCH v2 5/7] arm64: dts: renesas: white-hawk-cpu: Add DP output support Tomi Valkeinen
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-23  6:59 UTC (permalink / raw)
  To: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
	Jernej Skrabec, Tomi Valkeinen

Add DT nodes for components needed to get the DSI output working:
- FCPv
- VSPd
- DU
- DSI

Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 arch/arm64/boot/dts/renesas/r8a779g0.dtsi | 130 ++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
index 45d8d927ad26..4577208963b3 100644
--- a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi
@@ -1203,6 +1203,136 @@ gic: interrupt-controller@f1000000 {
 				      (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
 		};
 
+		fcpvd0: fcp@fea10000 {
+			compatible = "renesas,fcpv";
+			reg = <0 0xfea10000 0 0x200>;
+			clocks = <&cpg CPG_MOD 508>;
+			power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+			resets = <&cpg 508>;
+		};
+
+		fcpvd1: fcp@fea11000 {
+			compatible = "renesas,fcpv";
+			reg = <0 0xfea11000 0 0x200>;
+			clocks = <&cpg CPG_MOD 509>;
+			power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+			resets = <&cpg 509>;
+		};
+
+		vspd0: vsp@fea20000 {
+			compatible = "renesas,vsp2";
+			reg = <0 0xfea20000 0 0x7000>;
+			interrupts = <GIC_SPI 546 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 830>;
+			power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+			resets = <&cpg 830>;
+
+			renesas,fcp = <&fcpvd0>;
+		};
+
+		vspd1: vsp@fea28000 {
+			compatible = "renesas,vsp2";
+			reg = <0 0xfea28000 0 0x7000>;
+			interrupts = <GIC_SPI 551 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 831>;
+			power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+			resets = <&cpg 831>;
+
+			renesas,fcp = <&fcpvd1>;
+		};
+
+		du: display@feb00000 {
+			compatible = "renesas,du-r8a779g0";
+			reg = <0 0xfeb00000 0 0x40000>;
+			interrupts = <GIC_SPI 523 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 524 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 411>;
+			clock-names = "du.0";
+			power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+			resets = <&cpg 411>;
+			reset-names = "du.0";
+			renesas,vsps = <&vspd0 0>, <&vspd1 0>;
+
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					du_out_dsi0: endpoint {
+						remote-endpoint = <&dsi0_in>;
+					};
+				};
+
+				port@1 {
+					reg = <1>;
+					du_out_dsi1: endpoint {
+						remote-endpoint = <&dsi1_in>;
+					};
+				};
+			};
+		};
+
+		dsi0: dsi-encoder@fed80000 {
+			compatible = "renesas,r8a779g0-dsi-csi2-tx";
+			reg = <0 0xfed80000 0 0x10000>;
+			power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+			clocks = <&cpg CPG_MOD 415>,
+				 <&cpg CPG_CORE R8A779G0_CLK_DSIEXT>,
+				 <&cpg CPG_CORE R8A779G0_CLK_DSIREF>;
+			clock-names = "fck", "dsi", "pll";
+			resets = <&cpg 415>;
+
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					dsi0_in: endpoint {
+						remote-endpoint = <&du_out_dsi0>;
+					};
+				};
+
+				port@1 {
+					reg = <1>;
+				};
+			};
+		};
+
+		dsi1: dsi-encoder@fed90000 {
+			compatible = "renesas,r8a779g0-dsi-csi2-tx";
+			reg = <0 0xfed90000 0 0x10000>;
+			power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+			clocks = <&cpg CPG_MOD 416>,
+				 <&cpg CPG_CORE R8A779G0_CLK_DSIEXT>,
+				 <&cpg CPG_CORE R8A779G0_CLK_DSIREF>;
+			clock-names = "fck", "dsi", "pll";
+			resets = <&cpg 416>;
+
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					dsi1_in: endpoint {
+						remote-endpoint = <&du_out_dsi1>;
+					};
+				};
+
+				port@1 {
+					reg = <1>;
+				};
+			};
+		};
+
 		prr: chipid@fff00044 {
 			compatible = "renesas,prr";
 			reg = <0 0xfff00044 0 4>;
-- 
2.34.1


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

* [PATCH v2 5/7] arm64: dts: renesas: white-hawk-cpu: Add DP output support
  2022-11-23  6:59 [PATCH v2 0/7] Renesas V4H DSI & DP output support Tomi Valkeinen
                   ` (3 preceding siblings ...)
  2022-11-23  6:59 ` [PATCH v2 4/7] arm64: dts: renesas: r8a779g0: Add display related nodes Tomi Valkeinen
@ 2022-11-23  6:59 ` Tomi Valkeinen
  2022-12-01 10:03   ` Geert Uytterhoeven
  2022-11-23  6:59 ` [PATCH v2 6/7] drm: rcar-du: Add r8a779g0 support Tomi Valkeinen
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-23  6:59 UTC (permalink / raw)
  To: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
	Jernej Skrabec, Tomi Valkeinen

Add DT nodes needed for the mini DP connector. The DP is driven by
sn65dsi86, which in turn gets the pixel data from the SoC via DSI.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 .../dts/renesas/r8a779g0-white-hawk-cpu.dtsi  | 94 +++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi b/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi
index c10740aee9f6..8aab859aac7a 100644
--- a/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi
@@ -97,6 +97,15 @@ memory@600000000 {
 		reg = <0x6 0x00000000 0x1 0x00000000>;
 	};
 
+	reg_1p2v: regulator-1p2v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.2V";
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
 	reg_1p8v: regulator-1p8v {
 		compatible = "regulator-fixed";
 		regulator-name = "fixed-1.8V";
@@ -114,6 +123,24 @@ reg_3p3v: regulator-3p3v {
 		regulator-boot-on;
 		regulator-always-on;
 	};
+
+	mini-dp-con {
+		compatible = "dp-connector";
+		label = "CN5";
+		type = "mini";
+
+		port {
+			mini_dp_con_in: endpoint {
+				remote-endpoint = <&sn65dsi86_out>;
+			};
+		};
+	};
+
+	sn65dsi86_refclk: clk-x6 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <38400000>;
+	};
 };
 
 &avb0 {
@@ -134,6 +161,23 @@ phy0: ethernet-phy@0 {
 	};
 };
 
+&dsi0 {
+	status = "okay";
+
+	ports {
+		port@1 {
+			dsi0_out: endpoint {
+				remote-endpoint = <&sn65dsi86_in>;
+				data-lanes = <1 2 3 4>;
+			};
+		};
+	};
+};
+
+&du {
+	status = "okay";
+};
+
 &extal_clk {
 	clock-frequency = <16666666>;
 };
@@ -172,6 +216,51 @@ eeprom@50 {
 	};
 };
 
+&i2c1 {
+	pinctrl-0 = <&i2c1_pins>;
+	pinctrl-names = "default";
+
+	status = "okay";
+	clock-frequency = <400000>;
+
+	bridge@2c {
+		compatible = "ti,sn65dsi86";
+		reg = <0x2c>;
+
+		clocks = <&sn65dsi86_refclk>;
+		clock-names = "refclk";
+
+		interrupt-parent = <&intc_ex>;
+		interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+
+		enable-gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
+
+		vccio-supply = <&reg_1p8v>;
+		vpll-supply = <&reg_1p8v>;
+		vcca-supply = <&reg_1p2v>;
+		vcc-supply = <&reg_1p2v>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				sn65dsi86_in: endpoint {
+					remote-endpoint = <&dsi0_out>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				sn65dsi86_out: endpoint {
+					remote-endpoint = <&mini_dp_con_in>;
+				};
+			};
+		};
+	};
+};
+
 &mmc0 {
 	pinctrl-0 = <&mmc_pins>;
 	pinctrl-1 = <&mmc_pins>;
@@ -221,6 +310,11 @@ i2c0_pins: i2c0 {
 		function = "i2c0";
 	};
 
+	i2c1_pins: i2c1 {
+		groups = "i2c1";
+		function = "i2c1";
+	};
+
 	keys_pins: keys {
 		pins = "GP_5_0", "GP_5_1", "GP_5_2";
 		bias-pull-up;
-- 
2.34.1


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

* [PATCH v2 6/7] drm: rcar-du: Add r8a779g0 support
  2022-11-23  6:59 [PATCH v2 0/7] Renesas V4H DSI & DP output support Tomi Valkeinen
                   ` (4 preceding siblings ...)
  2022-11-23  6:59 ` [PATCH v2 5/7] arm64: dts: renesas: white-hawk-cpu: Add DP output support Tomi Valkeinen
@ 2022-11-23  6:59 ` Tomi Valkeinen
  2022-11-23  6:59 ` [PATCH v2 7/7] drm: rcar-du: dsi: " Tomi Valkeinen
  2022-11-29  1:58 ` [PATCH v2 0/7] Renesas V4H DSI & DP output support Laurent Pinchart
  7 siblings, 0 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-23  6:59 UTC (permalink / raw)
  To: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
	Jernej Skrabec, Tomi Valkeinen

Add support for DU on r8a779g0, which is identical to DU on r8a779a0.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_drv.c   | 22 ++++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_group.c |  2 +-
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index d003e8d9e7a2..46c60a2d710d 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -524,6 +524,27 @@ static const struct rcar_du_device_info rcar_du_r8a779a0_info = {
 	.dsi_clk_mask =  BIT(1) | BIT(0),
 };
 
+static const struct rcar_du_device_info rcar_du_r8a779g0_info = {
+	.gen = 4,
+	.features = RCAR_DU_FEATURE_CRTC_IRQ
+		  | RCAR_DU_FEATURE_VSP1_SOURCE
+		  | RCAR_DU_FEATURE_NO_BLENDING,
+	.channels_mask = BIT(1) | BIT(0),
+	.routes = {
+		/* R8A779G0 has two MIPI DSI outputs. */
+		[RCAR_DU_OUTPUT_DSI0] = {
+			.possible_crtcs = BIT(0),
+			.port = 0,
+		},
+		[RCAR_DU_OUTPUT_DSI1] = {
+			.possible_crtcs = BIT(1),
+			.port = 1,
+		},
+	},
+	.num_rpf = 5,
+	.dsi_clk_mask =  BIT(1) | BIT(0),
+};
+
 static const struct of_device_id rcar_du_of_table[] = {
 	{ .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info },
 	{ .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
@@ -549,6 +570,7 @@ static const struct of_device_id rcar_du_of_table[] = {
 	{ .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
 	{ .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
 	{ .compatible = "renesas,du-r8a779a0", .data = &rcar_du_r8a779a0_info },
+	{ .compatible = "renesas,du-r8a779g0", .data = &rcar_du_r8a779g0_info },
 	{ }
 };
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
index 1fe8581577ed..6da01760ede5 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
@@ -107,7 +107,7 @@ static void rcar_du_group_setup_didsr(struct rcar_du_group *rgrp)
 		 */
 		rcrtc = rcdu->crtcs;
 		num_crtcs = rcdu->num_crtcs;
-	} else if (rcdu->info->gen == 3 && rgrp->num_crtcs > 1) {
+	} else if (rcdu->info->gen >= 3 && rgrp->num_crtcs > 1) {
 		/*
 		 * On Gen3 dot clocks are setup through per-group registers,
 		 * only available when the group has two channels.
-- 
2.34.1


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

* [PATCH v2 7/7] drm: rcar-du: dsi: Add r8a779g0 support
  2022-11-23  6:59 [PATCH v2 0/7] Renesas V4H DSI & DP output support Tomi Valkeinen
                   ` (5 preceding siblings ...)
  2022-11-23  6:59 ` [PATCH v2 6/7] drm: rcar-du: Add r8a779g0 support Tomi Valkeinen
@ 2022-11-23  6:59 ` Tomi Valkeinen
  2022-11-29  1:49   ` Laurent Pinchart
  2022-11-29 13:41   ` [PATCH v3 7/7] drm: rcar-du: dsi: Add r8A779g0 support Tomi Valkeinen
  2022-11-29  1:58 ` [PATCH v2 0/7] Renesas V4H DSI & DP output support Laurent Pinchart
  7 siblings, 2 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-23  6:59 UTC (permalink / raw)
  To: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
	Jernej Skrabec, Tomi Valkeinen

Add DSI support for r8a779g0. The main differences to r8a779a0 are in
the PLL and PHTW setups.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
---
 drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c      | 484 +++++++++++++++----
 drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h |   6 +-
 2 files changed, 384 insertions(+), 106 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
index a7f2b7f66a17..723c35726c38 100644
--- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
+++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
@@ -9,6 +9,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -28,6 +29,20 @@
 #include "rcar_mipi_dsi.h"
 #include "rcar_mipi_dsi_regs.h"
 
+#define MHZ(v) ((v) * 1000000u)
+
+enum rcar_mipi_dsi_hw_model {
+	RCAR_DSI_R8A779A0,
+	RCAR_DSI_R8A779G0,
+};
+
+struct rcar_mipi_dsi_device_info {
+	enum rcar_mipi_dsi_hw_model model;
+	const struct dsi_clk_config *clk_cfg;
+	u8 clockset2_m_offset;
+	u8 clockset2_n_offset;
+};
+
 struct rcar_mipi_dsi {
 	struct device *dev;
 	const struct rcar_mipi_dsi_device_info *info;
@@ -50,6 +65,17 @@ struct rcar_mipi_dsi {
 	unsigned int lanes;
 };
 
+struct dsi_setup_info {
+	unsigned long hsfreq;
+	u16 hsfreqrange;
+
+	unsigned long fout;
+	u16 m;
+	u16 n;
+	u16 vclk_divider;
+	const struct dsi_clk_config *clkset;
+};
+
 static inline struct rcar_mipi_dsi *
 bridge_to_rcar_mipi_dsi(struct drm_bridge *bridge)
 {
@@ -62,22 +88,6 @@ host_to_rcar_mipi_dsi(struct mipi_dsi_host *host)
 	return container_of(host, struct rcar_mipi_dsi, host);
 }
 
-static const u32 phtw[] = {
-	0x01020114, 0x01600115, /* General testing */
-	0x01030116, 0x0102011d, /* General testing */
-	0x011101a4, 0x018601a4, /* 1Gbps testing */
-	0x014201a0, 0x010001a3, /* 1Gbps testing */
-	0x0101011f,		/* 1Gbps testing */
-};
-
-static const u32 phtw2[] = {
-	0x010c0130, 0x010c0140, /* General testing */
-	0x010c0150, 0x010c0180, /* General testing */
-	0x010c0190,
-	0x010a0160, 0x010a0170,
-	0x01800164, 0x01800174,	/* 1Gbps testing */
-};
-
 static const u32 hsfreqrange_table[][2] = {
 	{ 80000000U,   0x00 }, { 90000000U,   0x10 }, { 100000000U,  0x20 },
 	{ 110000000U,  0x30 }, { 120000000U,  0x01 }, { 130000000U,  0x11 },
@@ -103,24 +113,53 @@ static const u32 hsfreqrange_table[][2] = {
 	{ /* sentinel */ },
 };
 
-struct vco_cntrl_value {
+struct dsi_clk_config {
 	u32 min_freq;
 	u32 max_freq;
-	u16 value;
+	u8 vco_cntrl;
+	u8 cpbias_cntrl;
+	u8 gmp_cntrl;
+	u8 int_cntrl;
+	u8 prop_cntrl;
 };
 
-static const struct vco_cntrl_value vco_cntrl_table[] = {
-	{ .min_freq = 40000000U,   .max_freq = 55000000U,   .value = 0x3f },
-	{ .min_freq = 52500000U,   .max_freq = 80000000U,   .value = 0x39 },
-	{ .min_freq = 80000000U,   .max_freq = 110000000U,  .value = 0x2f },
-	{ .min_freq = 105000000U,  .max_freq = 160000000U,  .value = 0x29 },
-	{ .min_freq = 160000000U,  .max_freq = 220000000U,  .value = 0x1f },
-	{ .min_freq = 210000000U,  .max_freq = 320000000U,  .value = 0x19 },
-	{ .min_freq = 320000000U,  .max_freq = 440000000U,  .value = 0x0f },
-	{ .min_freq = 420000000U,  .max_freq = 660000000U,  .value = 0x09 },
-	{ .min_freq = 630000000U,  .max_freq = 1149000000U, .value = 0x03 },
-	{ .min_freq = 1100000000U, .max_freq = 1152000000U, .value = 0x01 },
-	{ .min_freq = 1150000000U, .max_freq = 1250000000U, .value = 0x01 },
+static const struct dsi_clk_config dsi_clk_cfg_r8a779a0[] = {
+	{   40000000u,   55000000u, 0x3f, 0x10, 0x01, 0x00, 0x0b },
+	{   52500000u,   80000000u, 0x39, 0x10, 0x01, 0x00, 0x0b },
+	{   80000000u,  110000000u, 0x2f, 0x10, 0x01, 0x00, 0x0b },
+	{  105000000u,  160000000u, 0x29, 0x10, 0x01, 0x00, 0x0b },
+	{  160000000u,  220000000u, 0x1f, 0x10, 0x01, 0x00, 0x0b },
+	{  210000000u,  320000000u, 0x19, 0x10, 0x01, 0x00, 0x0b },
+	{  320000000u,  440000000u, 0x0f, 0x10, 0x01, 0x00, 0x0b },
+	{  420000000u,  660000000u, 0x09, 0x10, 0x01, 0x00, 0x0b },
+	{  630000000u, 1149000000u, 0x03, 0x10, 0x01, 0x00, 0x0b },
+	{ 1100000000u, 1152000000u, 0x01, 0x10, 0x01, 0x00, 0x0b },
+	{ 1150000000u, 1250000000u, 0x01, 0x10, 0x01, 0x00, 0x0c },
+	{ /* sentinel */ },
+};
+
+static const struct dsi_clk_config dsi_clk_cfg_r8a779g0[] = {
+	{   40000000u,   45310000u, 0x2b, 0x00, 0x00, 0x08, 0x0a },
+	{   45310000u,   54660000u, 0x28, 0x00, 0x00, 0x08, 0x0a },
+	{   54660000u,   62500000u, 0x28, 0x00, 0x00, 0x08, 0x0a },
+	{   62500000u,   75000000u, 0x27, 0x00, 0x00, 0x08, 0x0a },
+	{   75000000u,   90630000u, 0x23, 0x00, 0x00, 0x08, 0x0a },
+	{   90630000u,  109370000u, 0x20, 0x00, 0x00, 0x08, 0x0a },
+	{  109370000u,  125000000u, 0x20, 0x00, 0x00, 0x08, 0x0a },
+	{  125000000u,  150000000u, 0x1f, 0x00, 0x00, 0x08, 0x0a },
+	{  150000000u,  181250000u, 0x1b, 0x00, 0x00, 0x08, 0x0a },
+	{  181250000u,  218750000u, 0x18, 0x00, 0x00, 0x08, 0x0a },
+	{  218750000u,  250000000u, 0x18, 0x00, 0x00, 0x08, 0x0a },
+	{  250000000u,  300000000u, 0x17, 0x00, 0x00, 0x08, 0x0a },
+	{  300000000u,  362500000u, 0x13, 0x00, 0x00, 0x08, 0x0a },
+	{  362500000u,  455480000u, 0x10, 0x00, 0x00, 0x08, 0x0a },
+	{  455480000u,  500000000u, 0x10, 0x00, 0x00, 0x08, 0x0a },
+	{  500000000u,  600000000u, 0x0f, 0x00, 0x00, 0x08, 0x0a },
+	{  600000000u,  725000000u, 0x0b, 0x00, 0x00, 0x08, 0x0a },
+	{  725000000u,  875000000u, 0x08, 0x00, 0x00, 0x08, 0x0a },
+	{  875000000u, 1000000000u, 0x08, 0x00, 0x00, 0x08, 0x0a },
+	{ 1000000000u, 1200000000u, 0x07, 0x00, 0x00, 0x08, 0x0a },
+	{ 1200000000u, 1250000000u, 0x03, 0x00, 0x00, 0x08, 0x0a },
 	{ /* sentinel */ },
 };
 
@@ -144,7 +183,7 @@ static void rcar_mipi_dsi_set(struct rcar_mipi_dsi *dsi, u32 reg, u32 set)
 	rcar_mipi_dsi_write(dsi, reg, rcar_mipi_dsi_read(dsi, reg) | set);
 }
 
-static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
+static int rcar_mipi_dsi_write_phtw(struct rcar_mipi_dsi *dsi, u32 phtw)
 {
 	u32 status;
 	int ret;
@@ -163,32 +202,231 @@ static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
 	return ret;
 }
 
+static int rcar_mipi_dsi_write_phtw_arr(struct rcar_mipi_dsi *dsi,
+					const u32 *phtw, unsigned int size)
+{
+	for (unsigned int i = 0; i < size; i++) {
+		int ret = rcar_mipi_dsi_write_phtw(dsi, phtw[i]);
+
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+#define WRITE_PHTW(...)                                               \
+	({                                                            \
+		static const u32 phtw[] = { __VA_ARGS__ };            \
+		int ret;                                              \
+		ret = rcar_mipi_dsi_write_phtw_arr(dsi, phtw,         \
+						   ARRAY_SIZE(phtw)); \
+		ret;                                                  \
+	})
+
+static int rcar_mipi_dsi_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
+{
+	return WRITE_PHTW(0x01020114, 0x01600115, 0x01030116, 0x0102011d,
+			  0x011101a4, 0x018601a4, 0x014201a0, 0x010001a3,
+			  0x0101011f);
+}
+
+static int rcar_mipi_dsi_post_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
+{
+	return WRITE_PHTW(0x010c0130, 0x010c0140, 0x010c0150, 0x010c0180,
+			  0x010c0190, 0x010a0160, 0x010a0170, 0x01800164,
+			  0x01800174);
+}
+
+static int rcar_mipi_dsi_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
+				       const struct dsi_setup_info *setup_info)
+{
+	int ret;
+
+	if (setup_info->hsfreq < MHZ(450)) {
+		ret = WRITE_PHTW(0x01010100, 0x011b01ac);
+		if (ret)
+			return ret;
+	}
+
+	ret = WRITE_PHTW(0x01010100, 0x01030173, 0x01000174, 0x01500175,
+			 0x01030176, 0x01040166, 0x010201ad);
+	if (ret)
+		return ret;
+
+	if (setup_info->hsfreq <= MHZ(1000))
+		ret = WRITE_PHTW(0x01020100, 0x01910170, 0x01020171,
+				 0x01110172);
+	else if (setup_info->hsfreq <= MHZ(1500))
+		ret = WRITE_PHTW(0x01020100, 0x01980170, 0x01030171,
+				 0x01100172);
+	else if (setup_info->hsfreq <= MHZ(2500))
+		ret = WRITE_PHTW(0x01020100, 0x0144016b, 0x01000172);
+	else
+		return -EINVAL;
+
+	if (ret)
+		return ret;
+
+	if (dsi->lanes <= 1) {
+		ret = WRITE_PHTW(0x01070100, 0x010e010b);
+		if (ret)
+			return ret;
+	}
+
+	if (dsi->lanes <= 2) {
+		ret = WRITE_PHTW(0x01090100, 0x010e010b);
+		if (ret)
+			return ret;
+	}
+
+	if (dsi->lanes <= 3) {
+		ret = WRITE_PHTW(0x010b0100, 0x010e010b);
+		if (ret)
+			return ret;
+	}
+
+	if (setup_info->hsfreq <= MHZ(1500)) {
+		ret = WRITE_PHTW(0x01010100, 0x01c0016e);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int
+rcar_mipi_dsi_post_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
+				 const struct dsi_setup_info *setup_info)
+{
+	u32 status;
+	int ret;
+
+	if (setup_info->hsfreq <= MHZ(1500)) {
+		WRITE_PHTW(0x01020100, 0x00000180);
+
+		ret = read_poll_timeout(rcar_mipi_dsi_read, status,
+					status & PHTR_TEST, 2000, 10000, false,
+					dsi, PHTR);
+		if (ret < 0) {
+			dev_err(dsi->dev, "failed to test PHTR\n");
+			return ret;
+		}
+
+		WRITE_PHTW(0x01010100, 0x0100016e);
+	}
+
+	return 0;
+}
+
 /* -----------------------------------------------------------------------------
  * Hardware Setup
  */
 
-struct dsi_setup_info {
-	unsigned long fout;
-	u16 vco_cntrl;
-	u16 prop_cntrl;
-	u16 hsfreqrange;
-	u16 div;
-	unsigned int m;
-	unsigned int n;
-};
+static void rcar_mipi_dsi_pll_calc_r8a779a0(struct rcar_mipi_dsi *dsi,
+					    struct clk *clk,
+					    unsigned long fout_target,
+					    struct dsi_setup_info *setup_info)
+{
+	unsigned int best_err = -1;
+	unsigned long fin;
+
+	fin = clk_get_rate(clk);
+
+	for (unsigned int n = 3; n <= 8; n++) {
+		unsigned long fpfd;
+
+		fpfd = fin / n;
+
+		if (fpfd < MHZ(2) || fpfd > MHZ(8))
+			continue;
+
+		for (unsigned int m = 64; m <= 625; m++) {
+			unsigned int err;
+			u64 fout;
+
+			fout = (u64)fpfd * m;
+
+			if (fout < MHZ(320) || fout > MHZ(1250))
+				continue;
+
+			fout = div64_u64(fout, setup_info->vclk_divider);
+
+			if (fout < setup_info->clkset->min_freq ||
+			    fout > setup_info->clkset->max_freq)
+				continue;
+
+			err = abs((long)(fout - fout_target) * 10000 /
+				  (long)fout_target);
+
+			if (err < best_err) {
+				setup_info->m = m;
+				setup_info->n = n;
+				setup_info->fout = (unsigned long)fout;
+				best_err = err;
+
+				if (err == 0)
+					return;
+			}
+		}
+	}
+}
+
+static void rcar_mipi_dsi_pll_calc_r8a779g0(struct rcar_mipi_dsi *dsi,
+					    struct clk *clk,
+					    unsigned long fout_target,
+					    struct dsi_setup_info *setup_info)
+{
+	unsigned int best_err = -1;
+	unsigned long fin;
+
+	fin = clk_get_rate(clk);
+
+	for (unsigned int n = 1; n <= 8; n++) {
+		unsigned long fpfd;
+
+		fpfd = fin / n;
+
+		if (fpfd < MHZ(8) || fpfd > MHZ(24))
+			continue;
+
+		for (unsigned int m = 167; m <= 1000; m++) {
+			unsigned int err;
+			u64 fout;
+
+			fout = div64_u64((u64)fpfd * m, 2);
+
+			if (fout < MHZ(2000) || fout > MHZ(4000))
+				continue;
+
+			fout = div64_u64(fout, setup_info->vclk_divider);
+
+			if (fout < setup_info->clkset->min_freq ||
+			    fout > setup_info->clkset->max_freq)
+				continue;
+
+			err = abs((long)(fout - fout_target) * 10000 /
+				  (long)fout_target);
+			if (err < best_err) {
+				setup_info->m = m;
+				setup_info->n = n;
+				setup_info->fout = (unsigned long)fout;
+				best_err = err;
+
+				if (err == 0)
+					return;
+			}
+		}
+	}
+}
 
 static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
 					  struct clk *clk, unsigned long target,
 					  struct dsi_setup_info *setup_info)
 {
 
-	const struct vco_cntrl_value *vco_cntrl;
+	const struct dsi_clk_config *clkset;
 	unsigned long fout_target;
-	unsigned long fin, fout;
-	unsigned long hsfreq;
-	unsigned int best_err = -1;
-	unsigned int divider;
-	unsigned int n;
 	unsigned int i;
 	unsigned int err;
 
@@ -198,70 +436,53 @@ static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
 	 */
 	fout_target = target * mipi_dsi_pixel_format_to_bpp(dsi->format)
 		    / (2 * dsi->lanes);
-	if (fout_target < 40000000 || fout_target > 1250000000)
+	if (fout_target < MHZ(40) || fout_target > MHZ(1250))
 		return;
 
 	/* Find vco_cntrl */
-	for (vco_cntrl = vco_cntrl_table; vco_cntrl->min_freq != 0; vco_cntrl++) {
-		if (fout_target > vco_cntrl->min_freq &&
-		    fout_target <= vco_cntrl->max_freq) {
-			setup_info->vco_cntrl = vco_cntrl->value;
-			if (fout_target >= 1150000000)
-				setup_info->prop_cntrl = 0x0c;
-			else
-				setup_info->prop_cntrl = 0x0b;
+	for (clkset = dsi->info->clk_cfg; clkset->min_freq != 0; clkset++) {
+		if (fout_target > clkset->min_freq &&
+		    fout_target <= clkset->max_freq) {
+			setup_info->clkset = clkset;
 			break;
 		}
 	}
 
-	/* Add divider */
-	setup_info->div = (setup_info->vco_cntrl & 0x30) >> 4;
+	switch (dsi->info->model) {
+	case RCAR_DSI_R8A779A0:
+		setup_info->vclk_divider = 1 << ((clkset->vco_cntrl >> 4) & 0x3);
+		rcar_mipi_dsi_pll_calc_r8a779a0(dsi, clk, fout_target, setup_info);
+		break;
+
+	case RCAR_DSI_R8A779G0:
+		setup_info->vclk_divider = 1 << (((clkset->vco_cntrl >> 3) & 0x7) + 1);
+		rcar_mipi_dsi_pll_calc_r8a779g0(dsi, clk, fout_target, setup_info);
+		break;
+
+	default:
+		return;
+	}
 
 	/* Find hsfreqrange */
-	hsfreq = fout_target * 2;
+	setup_info->hsfreq = setup_info->fout * 2;
 	for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++) {
-		if (hsfreqrange_table[i][0] >= hsfreq) {
+		if (hsfreqrange_table[i][0] >= setup_info->hsfreq) {
 			setup_info->hsfreqrange = hsfreqrange_table[i][1];
 			break;
 		}
 	}
 
-	/*
-	 * Calculate n and m for PLL clock
-	 * Following the HW manual the ranges of n and m are
-	 * n = [3-8] and m = [64-625]
-	 */
-	fin = clk_get_rate(clk);
-	divider = 1 << setup_info->div;
-	for (n = 3; n < 9; n++) {
-		unsigned long fpfd;
-		unsigned int m;
-
-		fpfd = fin / n;
-
-		for (m = 64; m < 626; m++) {
-			fout = fpfd * m / divider;
-			err = abs((long)(fout - fout_target) * 10000 /
-				  (long)fout_target);
-			if (err < best_err) {
-				setup_info->m = m - 2;
-				setup_info->n = n - 1;
-				setup_info->fout = fout;
-				best_err = err;
-				if (err == 0)
-					goto done;
-			}
-		}
-	}
+	err = abs((long)(setup_info->fout - fout_target) * 10000 / (long)fout_target);
 
-done:
 	dev_dbg(dsi->dev,
-		"%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/DIV %u/%u/%u\n",
-		clk, fin, setup_info->fout, fout_target, best_err / 100,
-		best_err % 100, setup_info->m, setup_info->n, setup_info->div);
+		"Fout = %u * %lu / (2 * %u * %u) = %lu (target %lu Hz, error %d.%02u%%)\n",
+		setup_info->m, clk_get_rate(clk), setup_info->n, setup_info->vclk_divider,
+		setup_info->fout, fout_target,
+		err / 100, err % 100);
+
 	dev_dbg(dsi->dev,
 		"vco_cntrl = 0x%x\tprop_cntrl = 0x%x\thsfreqrange = 0x%x\n",
-		setup_info->vco_cntrl, setup_info->prop_cntrl,
+		clkset->vco_cntrl, clkset->prop_cntrl,
 		setup_info->hsfreqrange);
 }
 
@@ -324,7 +545,7 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 {
 	struct dsi_setup_info setup_info = {};
 	unsigned int timeout;
-	int ret, i;
+	int ret;
 	int dsi_format;
 	u32 phy_setup;
 	u32 clockset2, clockset3;
@@ -360,10 +581,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 	phy_setup |= PHYSETUP_HSFREQRANGE(setup_info.hsfreqrange);
 	rcar_mipi_dsi_write(dsi, PHYSETUP, phy_setup);
 
-	for (i = 0; i < ARRAY_SIZE(phtw); i++) {
-		ret = rcar_mipi_dsi_phtw_test(dsi, phtw[i]);
+	switch (dsi->info->model) {
+	case RCAR_DSI_R8A779A0:
+		ret = rcar_mipi_dsi_init_phtw_v3u(dsi);
+		if (ret < 0)
+			return ret;
+		break;
+
+	case RCAR_DSI_R8A779G0:
+		ret = rcar_mipi_dsi_init_phtw_v4h(dsi, &setup_info);
 		if (ret < 0)
 			return ret;
+		break;
+
+	default:
+		return -ENODEV;
 	}
 
 	/* PLL Clock Setting */
@@ -371,12 +603,13 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 	rcar_mipi_dsi_set(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
 	rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
 
-	clockset2 = CLOCKSET2_M(setup_info.m) | CLOCKSET2_N(setup_info.n)
-		  | CLOCKSET2_VCO_CNTRL(setup_info.vco_cntrl);
-	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.prop_cntrl)
-		  | CLOCKSET3_INT_CNTRL(0)
-		  | CLOCKSET3_CPBIAS_CNTRL(0x10)
-		  | CLOCKSET3_GMP_CNTRL(1);
+	clockset2 = CLOCKSET2_M(setup_info.m - dsi->info->clockset2_m_offset)
+		  | CLOCKSET2_N(setup_info.n - dsi->info->clockset2_n_offset)
+		  | CLOCKSET2_VCO_CNTRL(setup_info.clkset->vco_cntrl);
+	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.clkset->prop_cntrl)
+		  | CLOCKSET3_INT_CNTRL(setup_info.clkset->int_cntrl)
+		  | CLOCKSET3_CPBIAS_CNTRL(setup_info.clkset->cpbias_cntrl)
+		  | CLOCKSET3_GMP_CNTRL(setup_info.clkset->gmp_cntrl);
 	rcar_mipi_dsi_write(dsi, CLOCKSET2, clockset2);
 	rcar_mipi_dsi_write(dsi, CLOCKSET3, clockset3);
 
@@ -407,10 +640,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 		return -ETIMEDOUT;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(phtw2); i++) {
-		ret = rcar_mipi_dsi_phtw_test(dsi, phtw2[i]);
+	switch (dsi->info->model) {
+	case RCAR_DSI_R8A779A0:
+		ret = rcar_mipi_dsi_post_init_phtw_v3u(dsi);
 		if (ret < 0)
 			return ret;
+		break;
+
+	case RCAR_DSI_R8A779G0:
+		ret = rcar_mipi_dsi_post_init_phtw_v4h(dsi, &setup_info);
+		if (ret < 0)
+			return ret;
+		break;
+
+	default:
+		return -ENODEV;
 	}
 
 	/* Enable DOT clock */
@@ -427,8 +671,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 		dev_warn(dsi->dev, "unsupported format");
 		return -EINVAL;
 	}
-	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_DIV(setup_info.div)
-		|  VCLKSET_LANE(dsi->lanes - 1);
+
+	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_LANE(dsi->lanes - 1);
+
+	switch (dsi->info->model) {
+	case RCAR_DSI_R8A779A0:
+		vclkset |= VCLKSET_DIV_R8A779A0(__ffs(setup_info.vclk_divider));
+		break;
+
+	case RCAR_DSI_R8A779G0:
+		vclkset |= VCLKSET_DIV_R8A779G0(__ffs(setup_info.vclk_divider) - 1);
+		break;
+
+	default:
+		return -ENODEV;
+	}
 
 	rcar_mipi_dsi_write(dsi, VCLKSET, vclkset);
 
@@ -841,8 +1098,25 @@ static int rcar_mipi_dsi_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct rcar_mipi_dsi_device_info r8a779a0_data = {
+	.model = RCAR_DSI_R8A779A0,
+	.clk_cfg = dsi_clk_cfg_r8a779a0,
+	.clockset2_m_offset = 2,
+	.clockset2_n_offset = 1,
+
+};
+
+static const struct rcar_mipi_dsi_device_info r8a779g0_data = {
+	.model = RCAR_DSI_R8A779G0,
+	.clk_cfg = dsi_clk_cfg_r8a779g0,
+	.clockset2_m_offset = 0,
+	.clockset2_n_offset = 1,
+
+};
+
 static const struct of_device_id rcar_mipi_dsi_of_table[] = {
-	{ .compatible = "renesas,r8a779a0-dsi-csi2-tx" },
+	{ .compatible = "renesas,r8a779a0-dsi-csi2-tx", .data = &r8a779a0_data },
+	{ .compatible = "renesas,r8a779g0-dsi-csi2-tx", .data = &r8a779g0_data },
 	{ }
 };
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
index 2eaca54636f3..608851340acf 100644
--- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
@@ -122,7 +122,8 @@
 #define VCLKSET_CKEN			(1 << 16)
 #define VCLKSET_COLOR_RGB		(0 << 8)
 #define VCLKSET_COLOR_YCC		(1 << 8)
-#define VCLKSET_DIV(x)			(((x) & 0x3) << 4)
+#define VCLKSET_DIV_R8A779A0(x)		(((x) & 0x3) << 4)
+#define VCLKSET_DIV_R8A779G0(x)		(((x) & 0x7) << 4)
 #define VCLKSET_BPP_16			(0 << 2)
 #define VCLKSET_BPP_18			(1 << 2)
 #define VCLKSET_BPP_18L			(2 << 2)
@@ -166,6 +167,9 @@
 #define PHTW_CWEN			(1 << 8)
 #define PHTW_TESTDIN_CODE(x)		(((x) & 0xff) << 0)
 
+#define PHTR				0x1038
+#define PHTR_TEST			(1 << 16)
+
 #define PHTC				0x103c
 #define PHTC_TESTCLR			(1 << 0)
 
-- 
2.34.1


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

* Re: [PATCH v2 7/7] drm: rcar-du: dsi: Add r8a779g0 support
  2022-11-23  6:59 ` [PATCH v2 7/7] drm: rcar-du: dsi: " Tomi Valkeinen
@ 2022-11-29  1:49   ` Laurent Pinchart
  2022-11-29 11:30     ` Tomi Valkeinen
  2022-11-29 12:59     ` Tomi Valkeinen
  2022-11-29 13:41   ` [PATCH v3 7/7] drm: rcar-du: dsi: Add r8A779g0 support Tomi Valkeinen
  1 sibling, 2 replies; 25+ messages in thread
From: Laurent Pinchart @ 2022-11-29  1:49 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Kieran Bingham, Rob Herring, Krzysztof Kozlowski,
	Geert Uytterhoeven, Magnus Damm, dri-devel, linux-renesas-soc,
	devicetree, linux-kernel, Andrzej Hajda, Neil Armstrong,
	Robert Foss, Jonas Karlman, Jernej Skrabec

Hi Tomi,

Thank you for the patch.

On Wed, Nov 23, 2022 at 08:59:46AM +0200, Tomi Valkeinen wrote:
> Add DSI support for r8a779g0. The main differences to r8a779a0 are in
> the PLL and PHTW setups.
> 
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> ---
>  drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c      | 484 +++++++++++++++----
>  drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h |   6 +-
>  2 files changed, 384 insertions(+), 106 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> index a7f2b7f66a17..723c35726c38 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> @@ -9,6 +9,7 @@
>  #include <linux/delay.h>
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
> +#include <linux/math64.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/of_device.h>
> @@ -28,6 +29,20 @@
>  #include "rcar_mipi_dsi.h"
>  #include "rcar_mipi_dsi_regs.h"
>  
> +#define MHZ(v) ((v) * 1000000u)

Isn't the U suffix usually spelled in uppercase ? Same below.

> +
> +enum rcar_mipi_dsi_hw_model {
> +	RCAR_DSI_R8A779A0,
> +	RCAR_DSI_R8A779G0,
> +};
> +
> +struct rcar_mipi_dsi_device_info {
> +	enum rcar_mipi_dsi_hw_model model;
> +	const struct dsi_clk_config *clk_cfg;
> +	u8 clockset2_m_offset;
> +	u8 clockset2_n_offset;
> +};
> +
>  struct rcar_mipi_dsi {
>  	struct device *dev;
>  	const struct rcar_mipi_dsi_device_info *info;
> @@ -50,6 +65,17 @@ struct rcar_mipi_dsi {
>  	unsigned int lanes;
>  };
>  
> +struct dsi_setup_info {
> +	unsigned long hsfreq;
> +	u16 hsfreqrange;
> +
> +	unsigned long fout;
> +	u16 m;
> +	u16 n;
> +	u16 vclk_divider;
> +	const struct dsi_clk_config *clkset;
> +};
> +
>  static inline struct rcar_mipi_dsi *
>  bridge_to_rcar_mipi_dsi(struct drm_bridge *bridge)
>  {
> @@ -62,22 +88,6 @@ host_to_rcar_mipi_dsi(struct mipi_dsi_host *host)
>  	return container_of(host, struct rcar_mipi_dsi, host);
>  }
>  
> -static const u32 phtw[] = {
> -	0x01020114, 0x01600115, /* General testing */
> -	0x01030116, 0x0102011d, /* General testing */
> -	0x011101a4, 0x018601a4, /* 1Gbps testing */
> -	0x014201a0, 0x010001a3, /* 1Gbps testing */
> -	0x0101011f,		/* 1Gbps testing */
> -};
> -
> -static const u32 phtw2[] = {
> -	0x010c0130, 0x010c0140, /* General testing */
> -	0x010c0150, 0x010c0180, /* General testing */
> -	0x010c0190,
> -	0x010a0160, 0x010a0170,
> -	0x01800164, 0x01800174,	/* 1Gbps testing */
> -};
> -
>  static const u32 hsfreqrange_table[][2] = {
>  	{ 80000000U,   0x00 }, { 90000000U,   0x10 }, { 100000000U,  0x20 },
>  	{ 110000000U,  0x30 }, { 120000000U,  0x01 }, { 130000000U,  0x11 },
> @@ -103,24 +113,53 @@ static const u32 hsfreqrange_table[][2] = {
>  	{ /* sentinel */ },
>  };
>  
> -struct vco_cntrl_value {
> +struct dsi_clk_config {
>  	u32 min_freq;
>  	u32 max_freq;
> -	u16 value;
> +	u8 vco_cntrl;
> +	u8 cpbias_cntrl;
> +	u8 gmp_cntrl;
> +	u8 int_cntrl;
> +	u8 prop_cntrl;
>  };
>  
> -static const struct vco_cntrl_value vco_cntrl_table[] = {
> -	{ .min_freq = 40000000U,   .max_freq = 55000000U,   .value = 0x3f },
> -	{ .min_freq = 52500000U,   .max_freq = 80000000U,   .value = 0x39 },
> -	{ .min_freq = 80000000U,   .max_freq = 110000000U,  .value = 0x2f },
> -	{ .min_freq = 105000000U,  .max_freq = 160000000U,  .value = 0x29 },
> -	{ .min_freq = 160000000U,  .max_freq = 220000000U,  .value = 0x1f },
> -	{ .min_freq = 210000000U,  .max_freq = 320000000U,  .value = 0x19 },
> -	{ .min_freq = 320000000U,  .max_freq = 440000000U,  .value = 0x0f },
> -	{ .min_freq = 420000000U,  .max_freq = 660000000U,  .value = 0x09 },
> -	{ .min_freq = 630000000U,  .max_freq = 1149000000U, .value = 0x03 },
> -	{ .min_freq = 1100000000U, .max_freq = 1152000000U, .value = 0x01 },
> -	{ .min_freq = 1150000000U, .max_freq = 1250000000U, .value = 0x01 },
> +static const struct dsi_clk_config dsi_clk_cfg_r8a779a0[] = {
> +	{   40000000u,   55000000u, 0x3f, 0x10, 0x01, 0x00, 0x0b },
> +	{   52500000u,   80000000u, 0x39, 0x10, 0x01, 0x00, 0x0b },

Would MHZ(52.5) do the right thing ? If so, I'd use the macro through
those tables.

> +	{   80000000u,  110000000u, 0x2f, 0x10, 0x01, 0x00, 0x0b },
> +	{  105000000u,  160000000u, 0x29, 0x10, 0x01, 0x00, 0x0b },
> +	{  160000000u,  220000000u, 0x1f, 0x10, 0x01, 0x00, 0x0b },
> +	{  210000000u,  320000000u, 0x19, 0x10, 0x01, 0x00, 0x0b },
> +	{  320000000u,  440000000u, 0x0f, 0x10, 0x01, 0x00, 0x0b },
> +	{  420000000u,  660000000u, 0x09, 0x10, 0x01, 0x00, 0x0b },
> +	{  630000000u, 1149000000u, 0x03, 0x10, 0x01, 0x00, 0x0b },
> +	{ 1100000000u, 1152000000u, 0x01, 0x10, 0x01, 0x00, 0x0b },
> +	{ 1150000000u, 1250000000u, 0x01, 0x10, 0x01, 0x00, 0x0c },
> +	{ /* sentinel */ },
> +};
> +
> +static const struct dsi_clk_config dsi_clk_cfg_r8a779g0[] = {
> +	{   40000000u,   45310000u, 0x2b, 0x00, 0x00, 0x08, 0x0a },
> +	{   45310000u,   54660000u, 0x28, 0x00, 0x00, 0x08, 0x0a },
> +	{   54660000u,   62500000u, 0x28, 0x00, 0x00, 0x08, 0x0a },
> +	{   62500000u,   75000000u, 0x27, 0x00, 0x00, 0x08, 0x0a },
> +	{   75000000u,   90630000u, 0x23, 0x00, 0x00, 0x08, 0x0a },
> +	{   90630000u,  109370000u, 0x20, 0x00, 0x00, 0x08, 0x0a },
> +	{  109370000u,  125000000u, 0x20, 0x00, 0x00, 0x08, 0x0a },
> +	{  125000000u,  150000000u, 0x1f, 0x00, 0x00, 0x08, 0x0a },
> +	{  150000000u,  181250000u, 0x1b, 0x00, 0x00, 0x08, 0x0a },
> +	{  181250000u,  218750000u, 0x18, 0x00, 0x00, 0x08, 0x0a },
> +	{  218750000u,  250000000u, 0x18, 0x00, 0x00, 0x08, 0x0a },
> +	{  250000000u,  300000000u, 0x17, 0x00, 0x00, 0x08, 0x0a },
> +	{  300000000u,  362500000u, 0x13, 0x00, 0x00, 0x08, 0x0a },
> +	{  362500000u,  455480000u, 0x10, 0x00, 0x00, 0x08, 0x0a },
> +	{  455480000u,  500000000u, 0x10, 0x00, 0x00, 0x08, 0x0a },
> +	{  500000000u,  600000000u, 0x0f, 0x00, 0x00, 0x08, 0x0a },
> +	{  600000000u,  725000000u, 0x0b, 0x00, 0x00, 0x08, 0x0a },
> +	{  725000000u,  875000000u, 0x08, 0x00, 0x00, 0x08, 0x0a },
> +	{  875000000u, 1000000000u, 0x08, 0x00, 0x00, 0x08, 0x0a },
> +	{ 1000000000u, 1200000000u, 0x07, 0x00, 0x00, 0x08, 0x0a },
> +	{ 1200000000u, 1250000000u, 0x03, 0x00, 0x00, 0x08, 0x0a },
>  	{ /* sentinel */ },
>  };
>  
> @@ -144,7 +183,7 @@ static void rcar_mipi_dsi_set(struct rcar_mipi_dsi *dsi, u32 reg, u32 set)
>  	rcar_mipi_dsi_write(dsi, reg, rcar_mipi_dsi_read(dsi, reg) | set);
>  }
>  
> -static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
> +static int rcar_mipi_dsi_write_phtw(struct rcar_mipi_dsi *dsi, u32 phtw)
>  {
>  	u32 status;
>  	int ret;
> @@ -163,32 +202,231 @@ static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
>  	return ret;
>  }
>  
> +static int rcar_mipi_dsi_write_phtw_arr(struct rcar_mipi_dsi *dsi,
> +					const u32 *phtw, unsigned int size)
> +{
> +	for (unsigned int i = 0; i < size; i++) {
> +		int ret = rcar_mipi_dsi_write_phtw(dsi, phtw[i]);
> +
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +#define WRITE_PHTW(...)                                               \
> +	({                                                            \
> +		static const u32 phtw[] = { __VA_ARGS__ };            \
> +		int ret;                                              \
> +		ret = rcar_mipi_dsi_write_phtw_arr(dsi, phtw,         \
> +						   ARRAY_SIZE(phtw)); \
> +		ret;                                                  \
> +	})
> +
> +static int rcar_mipi_dsi_init_phtw_v3u(struct rcar_mipi_dsi *dsi)

You're mixing the R8A779* names and the short names. I'd use one of the
two and stick to it, probably the short name (up to you).

> +{
> +	return WRITE_PHTW(0x01020114, 0x01600115, 0x01030116, 0x0102011d,
> +			  0x011101a4, 0x018601a4, 0x014201a0, 0x010001a3,
> +			  0x0101011f);
> +}
> +
> +static int rcar_mipi_dsi_post_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
> +{
> +	return WRITE_PHTW(0x010c0130, 0x010c0140, 0x010c0150, 0x010c0180,
> +			  0x010c0190, 0x010a0160, 0x010a0170, 0x01800164,
> +			  0x01800174);
> +}
> +
> +static int rcar_mipi_dsi_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
> +				       const struct dsi_setup_info *setup_info)
> +{
> +	int ret;
> +
> +	if (setup_info->hsfreq < MHZ(450)) {
> +		ret = WRITE_PHTW(0x01010100, 0x011b01ac);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = WRITE_PHTW(0x01010100, 0x01030173, 0x01000174, 0x01500175,
> +			 0x01030176, 0x01040166, 0x010201ad);
> +	if (ret)
> +		return ret;
> +
> +	if (setup_info->hsfreq <= MHZ(1000))
> +		ret = WRITE_PHTW(0x01020100, 0x01910170, 0x01020171,
> +				 0x01110172);
> +	else if (setup_info->hsfreq <= MHZ(1500))
> +		ret = WRITE_PHTW(0x01020100, 0x01980170, 0x01030171,
> +				 0x01100172);
> +	else if (setup_info->hsfreq <= MHZ(2500))
> +		ret = WRITE_PHTW(0x01020100, 0x0144016b, 0x01000172);
> +	else
> +		return -EINVAL;
> +
> +	if (ret)
> +		return ret;
> +
> +	if (dsi->lanes <= 1) {
> +		ret = WRITE_PHTW(0x01070100, 0x010e010b);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (dsi->lanes <= 2) {
> +		ret = WRITE_PHTW(0x01090100, 0x010e010b);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (dsi->lanes <= 3) {
> +		ret = WRITE_PHTW(0x010b0100, 0x010e010b);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (setup_info->hsfreq <= MHZ(1500)) {
> +		ret = WRITE_PHTW(0x01010100, 0x01c0016e);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +rcar_mipi_dsi_post_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
> +				 const struct dsi_setup_info *setup_info)
> +{
> +	u32 status;
> +	int ret;
> +
> +	if (setup_info->hsfreq <= MHZ(1500)) {
> +		WRITE_PHTW(0x01020100, 0x00000180);
> +
> +		ret = read_poll_timeout(rcar_mipi_dsi_read, status,
> +					status & PHTR_TEST, 2000, 10000, false,
> +					dsi, PHTR);
> +		if (ret < 0) {
> +			dev_err(dsi->dev, "failed to test PHTR\n");
> +			return ret;
> +		}
> +
> +		WRITE_PHTW(0x01010100, 0x0100016e);
> +	}
> +
> +	return 0;
> +}
> +
>  /* -----------------------------------------------------------------------------
>   * Hardware Setup
>   */
>  
> -struct dsi_setup_info {
> -	unsigned long fout;
> -	u16 vco_cntrl;
> -	u16 prop_cntrl;
> -	u16 hsfreqrange;
> -	u16 div;
> -	unsigned int m;
> -	unsigned int n;
> -};
> +static void rcar_mipi_dsi_pll_calc_r8a779a0(struct rcar_mipi_dsi *dsi,
> +					    struct clk *clk,
> +					    unsigned long fout_target,
> +					    struct dsi_setup_info *setup_info)
> +{
> +	unsigned int best_err = -1;
> +	unsigned long fin;
> +
> +	fin = clk_get_rate(clk);
> +
> +	for (unsigned int n = 3; n <= 8; n++) {
> +		unsigned long fpfd;
> +
> +		fpfd = fin / n;
> +
> +		if (fpfd < MHZ(2) || fpfd > MHZ(8))
> +			continue;
> +
> +		for (unsigned int m = 64; m <= 625; m++) {
> +			unsigned int err;
> +			u64 fout;
> +
> +			fout = (u64)fpfd * m;
> +
> +			if (fout < MHZ(320) || fout > MHZ(1250))
> +				continue;
> +
> +			fout = div64_u64(fout, setup_info->vclk_divider);
> +
> +			if (fout < setup_info->clkset->min_freq ||
> +			    fout > setup_info->clkset->max_freq)
> +				continue;
> +
> +			err = abs((long)(fout - fout_target) * 10000 /
> +				  (long)fout_target);
> +
> +			if (err < best_err) {
> +				setup_info->m = m;
> +				setup_info->n = n;
> +				setup_info->fout = (unsigned long)fout;
> +				best_err = err;
> +
> +				if (err == 0)
> +					return;
> +			}
> +		}
> +	}
> +}
> +
> +static void rcar_mipi_dsi_pll_calc_r8a779g0(struct rcar_mipi_dsi *dsi,
> +					    struct clk *clk,
> +					    unsigned long fout_target,
> +					    struct dsi_setup_info *setup_info)
> +{
> +	unsigned int best_err = -1;
> +	unsigned long fin;
> +
> +	fin = clk_get_rate(clk);

This could move to the caller.

> +
> +	for (unsigned int n = 1; n <= 8; n++) {
> +		unsigned long fpfd;
> +
> +		fpfd = fin / n;
> +
> +		if (fpfd < MHZ(8) || fpfd > MHZ(24))
> +			continue;
> +
> +		for (unsigned int m = 167; m <= 1000; m++) {
> +			unsigned int err;
> +			u64 fout;
> +
> +			fout = div64_u64((u64)fpfd * m, 2);
> +
> +			if (fout < MHZ(2000) || fout > MHZ(4000))
> +				continue;
> +
> +			fout = div64_u64(fout, setup_info->vclk_divider);
> +
> +			if (fout < setup_info->clkset->min_freq ||
> +			    fout > setup_info->clkset->max_freq)
> +				continue;
> +
> +			err = abs((long)(fout - fout_target) * 10000 /
> +				  (long)fout_target);

Add a blank line here, or remove it from the previous function.

> +			if (err < best_err) {
> +				setup_info->m = m;
> +				setup_info->n = n;
> +				setup_info->fout = (unsigned long)fout;
> +				best_err = err;
> +
> +				if (err == 0)
> +					return;
> +			}
> +		}
> +	}
> +}

This function could be parameterized, up to you.

>  
>  static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
>  					  struct clk *clk, unsigned long target,
>  					  struct dsi_setup_info *setup_info)
>  {
>  
> -	const struct vco_cntrl_value *vco_cntrl;
> +	const struct dsi_clk_config *clkset;
>  	unsigned long fout_target;
> -	unsigned long fin, fout;
> -	unsigned long hsfreq;
> -	unsigned int best_err = -1;
> -	unsigned int divider;
> -	unsigned int n;
>  	unsigned int i;
>  	unsigned int err;
>  
> @@ -198,70 +436,53 @@ static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
>  	 */
>  	fout_target = target * mipi_dsi_pixel_format_to_bpp(dsi->format)
>  		    / (2 * dsi->lanes);
> -	if (fout_target < 40000000 || fout_target > 1250000000)
> +	if (fout_target < MHZ(40) || fout_target > MHZ(1250))
>  		return;
>  
>  	/* Find vco_cntrl */
> -	for (vco_cntrl = vco_cntrl_table; vco_cntrl->min_freq != 0; vco_cntrl++) {
> -		if (fout_target > vco_cntrl->min_freq &&
> -		    fout_target <= vco_cntrl->max_freq) {
> -			setup_info->vco_cntrl = vco_cntrl->value;
> -			if (fout_target >= 1150000000)
> -				setup_info->prop_cntrl = 0x0c;
> -			else
> -				setup_info->prop_cntrl = 0x0b;
> +	for (clkset = dsi->info->clk_cfg; clkset->min_freq != 0; clkset++) {
> +		if (fout_target > clkset->min_freq &&
> +		    fout_target <= clkset->max_freq) {
> +			setup_info->clkset = clkset;
>  			break;
>  		}
>  	}
>  
> -	/* Add divider */
> -	setup_info->div = (setup_info->vco_cntrl & 0x30) >> 4;
> +	switch (dsi->info->model) {
> +	case RCAR_DSI_R8A779A0:
> +		setup_info->vclk_divider = 1 << ((clkset->vco_cntrl >> 4) & 0x3);

If you stored (clkset->vco_cntrl >> 4) & 0x3 in setup_info->vclk_divider
you wouldn't have to use __ffs() in rcar_mipi_dsi_startup(). You could
also drop the - 1 there, which would allow dropping one of the
switch(dsi->info->model). You can store the real divider value in
setup_info separately for rcar_mipi_dsi_pll_calc_r8a779a0(), or pass it
to the function.

> +		rcar_mipi_dsi_pll_calc_r8a779a0(dsi, clk, fout_target, setup_info);
> +		break;
> +
> +	case RCAR_DSI_R8A779G0:
> +		setup_info->vclk_divider = 1 << (((clkset->vco_cntrl >> 3) & 0x7) + 1);
> +		rcar_mipi_dsi_pll_calc_r8a779g0(dsi, clk, fout_target, setup_info);
> +		break;
> +
> +	default:
> +		return;
> +	}
>  
>  	/* Find hsfreqrange */
> -	hsfreq = fout_target * 2;
> +	setup_info->hsfreq = setup_info->fout * 2;
>  	for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++) {
> -		if (hsfreqrange_table[i][0] >= hsfreq) {
> +		if (hsfreqrange_table[i][0] >= setup_info->hsfreq) {
>  			setup_info->hsfreqrange = hsfreqrange_table[i][1];
>  			break;
>  		}
>  	}
>  
> -	/*
> -	 * Calculate n and m for PLL clock
> -	 * Following the HW manual the ranges of n and m are
> -	 * n = [3-8] and m = [64-625]
> -	 */

I'd keep the comment in rcar_mipi_dsi_pll_calc_r8a779a0(), and add a
similar comment in rcar_mipi_dsi_pll_calc_r8a779g0().

> -	fin = clk_get_rate(clk);
> -	divider = 1 << setup_info->div;
> -	for (n = 3; n < 9; n++) {
> -		unsigned long fpfd;
> -		unsigned int m;
> -
> -		fpfd = fin / n;
> -
> -		for (m = 64; m < 626; m++) {
> -			fout = fpfd * m / divider;
> -			err = abs((long)(fout - fout_target) * 10000 /
> -				  (long)fout_target);
> -			if (err < best_err) {
> -				setup_info->m = m - 2;
> -				setup_info->n = n - 1;
> -				setup_info->fout = fout;
> -				best_err = err;
> -				if (err == 0)
> -					goto done;
> -			}
> -		}
> -	}
> +	err = abs((long)(setup_info->fout - fout_target) * 10000 / (long)fout_target);
>  
> -done:
>  	dev_dbg(dsi->dev,
> -		"%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/DIV %u/%u/%u\n",
> -		clk, fin, setup_info->fout, fout_target, best_err / 100,
> -		best_err % 100, setup_info->m, setup_info->n, setup_info->div);
> +		"Fout = %u * %lu / (2 * %u * %u) = %lu (target %lu Hz, error %d.%02u%%)\n",

Is the "2 *" valid on V3U too ?

> +		setup_info->m, clk_get_rate(clk), setup_info->n, setup_info->vclk_divider,

If you keep the clk_get_rate() call in this function you wouldn't have
to call it again here.

> +		setup_info->fout, fout_target,
> +		err / 100, err % 100);
> +
>  	dev_dbg(dsi->dev,
>  		"vco_cntrl = 0x%x\tprop_cntrl = 0x%x\thsfreqrange = 0x%x\n",
> -		setup_info->vco_cntrl, setup_info->prop_cntrl,
> +		clkset->vco_cntrl, clkset->prop_cntrl,
>  		setup_info->hsfreqrange);
>  }
>  
> @@ -324,7 +545,7 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>  {
>  	struct dsi_setup_info setup_info = {};
>  	unsigned int timeout;
> -	int ret, i;
> +	int ret;
>  	int dsi_format;
>  	u32 phy_setup;
>  	u32 clockset2, clockset3;
> @@ -360,10 +581,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>  	phy_setup |= PHYSETUP_HSFREQRANGE(setup_info.hsfreqrange);
>  	rcar_mipi_dsi_write(dsi, PHYSETUP, phy_setup);
>  
> -	for (i = 0; i < ARRAY_SIZE(phtw); i++) {
> -		ret = rcar_mipi_dsi_phtw_test(dsi, phtw[i]);
> +	switch (dsi->info->model) {
> +	case RCAR_DSI_R8A779A0:
> +		ret = rcar_mipi_dsi_init_phtw_v3u(dsi);
> +		if (ret < 0)
> +			return ret;
> +		break;
> +
> +	case RCAR_DSI_R8A779G0:
> +		ret = rcar_mipi_dsi_init_phtw_v4h(dsi, &setup_info);
>  		if (ret < 0)
>  			return ret;
> +		break;
> +
> +	default:
> +		return -ENODEV;

This can't happen. Same below.

>  	}
>  
>  	/* PLL Clock Setting */
> @@ -371,12 +603,13 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>  	rcar_mipi_dsi_set(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
>  	rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
>  
> -	clockset2 = CLOCKSET2_M(setup_info.m) | CLOCKSET2_N(setup_info.n)
> -		  | CLOCKSET2_VCO_CNTRL(setup_info.vco_cntrl);
> -	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.prop_cntrl)
> -		  | CLOCKSET3_INT_CNTRL(0)
> -		  | CLOCKSET3_CPBIAS_CNTRL(0x10)
> -		  | CLOCKSET3_GMP_CNTRL(1);
> +	clockset2 = CLOCKSET2_M(setup_info.m - dsi->info->clockset2_m_offset)
> +		  | CLOCKSET2_N(setup_info.n - dsi->info->clockset2_n_offset)
> +		  | CLOCKSET2_VCO_CNTRL(setup_info.clkset->vco_cntrl);
> +	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.clkset->prop_cntrl)
> +		  | CLOCKSET3_INT_CNTRL(setup_info.clkset->int_cntrl)
> +		  | CLOCKSET3_CPBIAS_CNTRL(setup_info.clkset->cpbias_cntrl)
> +		  | CLOCKSET3_GMP_CNTRL(setup_info.clkset->gmp_cntrl);
>  	rcar_mipi_dsi_write(dsi, CLOCKSET2, clockset2);
>  	rcar_mipi_dsi_write(dsi, CLOCKSET3, clockset3);
>  
> @@ -407,10 +640,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>  		return -ETIMEDOUT;
>  	}
>  
> -	for (i = 0; i < ARRAY_SIZE(phtw2); i++) {
> -		ret = rcar_mipi_dsi_phtw_test(dsi, phtw2[i]);
> +	switch (dsi->info->model) {
> +	case RCAR_DSI_R8A779A0:
> +		ret = rcar_mipi_dsi_post_init_phtw_v3u(dsi);
>  		if (ret < 0)
>  			return ret;
> +		break;
> +
> +	case RCAR_DSI_R8A779G0:
> +		ret = rcar_mipi_dsi_post_init_phtw_v4h(dsi, &setup_info);
> +		if (ret < 0)
> +			return ret;
> +		break;
> +
> +	default:
> +		return -ENODEV;
>  	}
>  
>  	/* Enable DOT clock */
> @@ -427,8 +671,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>  		dev_warn(dsi->dev, "unsupported format");
>  		return -EINVAL;
>  	}
> -	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_DIV(setup_info.div)
> -		|  VCLKSET_LANE(dsi->lanes - 1);
> +
> +	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_LANE(dsi->lanes - 1);
> +
> +	switch (dsi->info->model) {
> +	case RCAR_DSI_R8A779A0:
> +		vclkset |= VCLKSET_DIV_R8A779A0(__ffs(setup_info.vclk_divider));
> +		break;
> +
> +	case RCAR_DSI_R8A779G0:
> +		vclkset |= VCLKSET_DIV_R8A779G0(__ffs(setup_info.vclk_divider) - 1);
> +		break;
> +
> +	default:
> +		return -ENODEV;
> +	}
>  
>  	rcar_mipi_dsi_write(dsi, VCLKSET, vclkset);
>  
> @@ -841,8 +1098,25 @@ static int rcar_mipi_dsi_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static const struct rcar_mipi_dsi_device_info r8a779a0_data = {
> +	.model = RCAR_DSI_R8A779A0,
> +	.clk_cfg = dsi_clk_cfg_r8a779a0,
> +	.clockset2_m_offset = 2,
> +	.clockset2_n_offset = 1,
> +

Extra blank line.

> +};
> +
> +static const struct rcar_mipi_dsi_device_info r8a779g0_data = {
> +	.model = RCAR_DSI_R8A779G0,
> +	.clk_cfg = dsi_clk_cfg_r8a779g0,
> +	.clockset2_m_offset = 0,
> +	.clockset2_n_offset = 1,

You could possibly drop clockset2_n_offset as it's identical for the two
variants, and there's no indication it would be different in another
version of the IP core.

> +

Here too.

> +};
> +
>  static const struct of_device_id rcar_mipi_dsi_of_table[] = {
> -	{ .compatible = "renesas,r8a779a0-dsi-csi2-tx" },
> +	{ .compatible = "renesas,r8a779a0-dsi-csi2-tx", .data = &r8a779a0_data },
> +	{ .compatible = "renesas,r8a779g0-dsi-csi2-tx", .data = &r8a779g0_data },
>  	{ }
>  };
>  
> diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
> index 2eaca54636f3..608851340acf 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
> @@ -122,7 +122,8 @@
>  #define VCLKSET_CKEN			(1 << 16)
>  #define VCLKSET_COLOR_RGB		(0 << 8)
>  #define VCLKSET_COLOR_YCC		(1 << 8)
> -#define VCLKSET_DIV(x)			(((x) & 0x3) << 4)
> +#define VCLKSET_DIV_R8A779A0(x)		(((x) & 0x3) << 4)
> +#define VCLKSET_DIV_R8A779G0(x)		(((x) & 0x7) << 4)
>  #define VCLKSET_BPP_16			(0 << 2)
>  #define VCLKSET_BPP_18			(1 << 2)
>  #define VCLKSET_BPP_18L			(2 << 2)
> @@ -166,6 +167,9 @@
>  #define PHTW_CWEN			(1 << 8)
>  #define PHTW_TESTDIN_CODE(x)		(((x) & 0xff) << 0)
>  
> +#define PHTR				0x1038
> +#define PHTR_TEST			(1 << 16)
> +
>  #define PHTC				0x103c
>  #define PHTC_TESTCLR			(1 << 0)
>  

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 0/7] Renesas V4H DSI & DP output support
  2022-11-23  6:59 [PATCH v2 0/7] Renesas V4H DSI & DP output support Tomi Valkeinen
                   ` (6 preceding siblings ...)
  2022-11-23  6:59 ` [PATCH v2 7/7] drm: rcar-du: dsi: " Tomi Valkeinen
@ 2022-11-29  1:58 ` Laurent Pinchart
  7 siblings, 0 replies; 25+ messages in thread
From: Laurent Pinchart @ 2022-11-29  1:58 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Kieran Bingham, Rob Herring, Krzysztof Kozlowski,
	Geert Uytterhoeven, Magnus Damm, dri-devel, linux-renesas-soc,
	devicetree, linux-kernel, Andrzej Hajda, Neil Armstrong,
	Robert Foss, Jonas Karlman, Jernej Skrabec, Tomi Valkeinen

Hi Tomi,

On Wed, Nov 23, 2022 at 08:59:39AM +0200, Tomi Valkeinen wrote:
> From: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> 
> Hi,
> 
> These add support for DSI on V4H SoC (r8a779g0) and DP for Whitehawk
> board.
> 
> Changes in v2:
> - A few cosmetic changes
> - Increase vspd address range in dts to 0x7000
> - Arrange nodes in dts by the block address
> - Use gen = 4 for r8a779g0 du
> - Drop the CLOCKSET1 hack patch
> 
> The CLOCKSET1 patch is apparently not needed to get the DSI & DP
> working. Which is baffling, as I'm quite sure it was needed. There are a
> few possible explanations: 1) it was never needed and I was just messing
> things up, 2) it was needed, but some of my later improvements made it
> unnecessary, 3) Whitehawk board firmware was updated in the middle of
> the development of this series, possibly the firmware made the patch
> unnecessary.
> 
>  Tomi
> 
> Tomi Valkeinen (7):
>   dt-bindings: display: renesas,du: Provide bindings for r8a779g0
>   dt-bindings: display: bridge: renesas,dsi-csi2-tx: Add r8a779g0
>   clk: renesas: r8a779g0: Add display related clocks
>   arm64: dts: renesas: r8a779g0: Add display related nodes
>   arm64: dts: renesas: white-hawk-cpu: Add DP output support
>   drm: rcar-du: Add r8a779g0 support
>   drm: rcar-du: dsi: Add r8A779g0 support

I'll take patches 1/7, 2/7 and 6/7 in my tree already for v6.3. I expect
Geert to handle 3/7, 4/7 and 5/7. 7/7 needs a v3.

> 
>  .../display/bridge/renesas,dsi-csi2-tx.yaml   |   3 +-
>  .../bindings/display/renesas,du.yaml          |   2 +
>  .../dts/renesas/r8a779g0-white-hawk-cpu.dtsi  |  94 ++++
>  arch/arm64/boot/dts/renesas/r8a779g0.dtsi     | 130 +++++
>  drivers/clk/renesas/r8a779g0-cpg-mssr.c       |  14 +
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c         |  22 +
>  drivers/gpu/drm/rcar-du/rcar_du_group.c       |   2 +-
>  drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c       | 484 ++++++++++++++----
>  drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h  |   6 +-
>  9 files changed, 649 insertions(+), 108 deletions(-)
> 

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 7/7] drm: rcar-du: dsi: Add r8a779g0 support
  2022-11-29  1:49   ` Laurent Pinchart
@ 2022-11-29 11:30     ` Tomi Valkeinen
  2022-11-29 11:40       ` Biju Das
  2022-11-29 12:05       ` Laurent Pinchart
  2022-11-29 12:59     ` Tomi Valkeinen
  1 sibling, 2 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-29 11:30 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Kieran Bingham, Rob Herring, Krzysztof Kozlowski,
	Geert Uytterhoeven, Magnus Damm, dri-devel, linux-renesas-soc,
	devicetree, linux-kernel, Andrzej Hajda, Neil Armstrong,
	Robert Foss, Jonas Karlman, Jernej Skrabec

On 29/11/2022 03:49, Laurent Pinchart wrote:
> Hi Tomi,
> 
> Thank you for the patch.
> 
> On Wed, Nov 23, 2022 at 08:59:46AM +0200, Tomi Valkeinen wrote:
>> Add DSI support for r8a779g0. The main differences to r8a779a0 are in
>> the PLL and PHTW setups.
>>
>> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
>> ---
>>   drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c      | 484 +++++++++++++++----
>>   drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h |   6 +-
>>   2 files changed, 384 insertions(+), 106 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
>> index a7f2b7f66a17..723c35726c38 100644
>> --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
>> +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
>> @@ -9,6 +9,7 @@
>>   #include <linux/delay.h>
>>   #include <linux/io.h>
>>   #include <linux/iopoll.h>
>> +#include <linux/math64.h>
>>   #include <linux/module.h>
>>   #include <linux/of.h>
>>   #include <linux/of_device.h>
>> @@ -28,6 +29,20 @@
>>   #include "rcar_mipi_dsi.h"
>>   #include "rcar_mipi_dsi_regs.h"
>>   
>> +#define MHZ(v) ((v) * 1000000u)
> 
> Isn't the U suffix usually spelled in uppercase ? Same below.

I couldn't find any coding style guidelines on that. I like the lower 
case visually. The suffix stands out much clearer on 10000000u than on 
10000000U. But I can change it if you feel otherwise.

>> +
>> +enum rcar_mipi_dsi_hw_model {
>> +	RCAR_DSI_R8A779A0,
>> +	RCAR_DSI_R8A779G0,
>> +};
>> +
>> +struct rcar_mipi_dsi_device_info {
>> +	enum rcar_mipi_dsi_hw_model model;
>> +	const struct dsi_clk_config *clk_cfg;
>> +	u8 clockset2_m_offset;
>> +	u8 clockset2_n_offset;
>> +};
>> +
>>   struct rcar_mipi_dsi {
>>   	struct device *dev;
>>   	const struct rcar_mipi_dsi_device_info *info;
>> @@ -50,6 +65,17 @@ struct rcar_mipi_dsi {
>>   	unsigned int lanes;
>>   };
>>   
>> +struct dsi_setup_info {
>> +	unsigned long hsfreq;
>> +	u16 hsfreqrange;
>> +
>> +	unsigned long fout;
>> +	u16 m;
>> +	u16 n;
>> +	u16 vclk_divider;
>> +	const struct dsi_clk_config *clkset;
>> +};
>> +
>>   static inline struct rcar_mipi_dsi *
>>   bridge_to_rcar_mipi_dsi(struct drm_bridge *bridge)
>>   {
>> @@ -62,22 +88,6 @@ host_to_rcar_mipi_dsi(struct mipi_dsi_host *host)
>>   	return container_of(host, struct rcar_mipi_dsi, host);
>>   }
>>   
>> -static const u32 phtw[] = {
>> -	0x01020114, 0x01600115, /* General testing */
>> -	0x01030116, 0x0102011d, /* General testing */
>> -	0x011101a4, 0x018601a4, /* 1Gbps testing */
>> -	0x014201a0, 0x010001a3, /* 1Gbps testing */
>> -	0x0101011f,		/* 1Gbps testing */
>> -};
>> -
>> -static const u32 phtw2[] = {
>> -	0x010c0130, 0x010c0140, /* General testing */
>> -	0x010c0150, 0x010c0180, /* General testing */
>> -	0x010c0190,
>> -	0x010a0160, 0x010a0170,
>> -	0x01800164, 0x01800174,	/* 1Gbps testing */
>> -};
>> -
>>   static const u32 hsfreqrange_table[][2] = {
>>   	{ 80000000U,   0x00 }, { 90000000U,   0x10 }, { 100000000U,  0x20 },
>>   	{ 110000000U,  0x30 }, { 120000000U,  0x01 }, { 130000000U,  0x11 },
>> @@ -103,24 +113,53 @@ static const u32 hsfreqrange_table[][2] = {
>>   	{ /* sentinel */ },
>>   };
>>   
>> -struct vco_cntrl_value {
>> +struct dsi_clk_config {
>>   	u32 min_freq;
>>   	u32 max_freq;
>> -	u16 value;
>> +	u8 vco_cntrl;
>> +	u8 cpbias_cntrl;
>> +	u8 gmp_cntrl;
>> +	u8 int_cntrl;
>> +	u8 prop_cntrl;
>>   };
>>   
>> -static const struct vco_cntrl_value vco_cntrl_table[] = {
>> -	{ .min_freq = 40000000U,   .max_freq = 55000000U,   .value = 0x3f },
>> -	{ .min_freq = 52500000U,   .max_freq = 80000000U,   .value = 0x39 },
>> -	{ .min_freq = 80000000U,   .max_freq = 110000000U,  .value = 0x2f },
>> -	{ .min_freq = 105000000U,  .max_freq = 160000000U,  .value = 0x29 },
>> -	{ .min_freq = 160000000U,  .max_freq = 220000000U,  .value = 0x1f },
>> -	{ .min_freq = 210000000U,  .max_freq = 320000000U,  .value = 0x19 },
>> -	{ .min_freq = 320000000U,  .max_freq = 440000000U,  .value = 0x0f },
>> -	{ .min_freq = 420000000U,  .max_freq = 660000000U,  .value = 0x09 },
>> -	{ .min_freq = 630000000U,  .max_freq = 1149000000U, .value = 0x03 },
>> -	{ .min_freq = 1100000000U, .max_freq = 1152000000U, .value = 0x01 },
>> -	{ .min_freq = 1150000000U, .max_freq = 1250000000U, .value = 0x01 },
>> +static const struct dsi_clk_config dsi_clk_cfg_r8a779a0[] = {
>> +	{   40000000u,   55000000u, 0x3f, 0x10, 0x01, 0x00, 0x0b },
>> +	{   52500000u,   80000000u, 0x39, 0x10, 0x01, 0x00, 0x0b },
> 
> Would MHZ(52.5) do the right thing ? If so, I'd use the macro through
> those tables.

That's a great idea. It had never occurred to me that we can use floats 
in the kernel code, as long as we convert to ints when the preprocessor 
is done.

>> +	{   80000000u,  110000000u, 0x2f, 0x10, 0x01, 0x00, 0x0b },
>> +	{  105000000u,  160000000u, 0x29, 0x10, 0x01, 0x00, 0x0b },
>> +	{  160000000u,  220000000u, 0x1f, 0x10, 0x01, 0x00, 0x0b },
>> +	{  210000000u,  320000000u, 0x19, 0x10, 0x01, 0x00, 0x0b },
>> +	{  320000000u,  440000000u, 0x0f, 0x10, 0x01, 0x00, 0x0b },
>> +	{  420000000u,  660000000u, 0x09, 0x10, 0x01, 0x00, 0x0b },
>> +	{  630000000u, 1149000000u, 0x03, 0x10, 0x01, 0x00, 0x0b },
>> +	{ 1100000000u, 1152000000u, 0x01, 0x10, 0x01, 0x00, 0x0b },
>> +	{ 1150000000u, 1250000000u, 0x01, 0x10, 0x01, 0x00, 0x0c },
>> +	{ /* sentinel */ },
>> +};
>> +
>> +static const struct dsi_clk_config dsi_clk_cfg_r8a779g0[] = {
>> +	{   40000000u,   45310000u, 0x2b, 0x00, 0x00, 0x08, 0x0a },
>> +	{   45310000u,   54660000u, 0x28, 0x00, 0x00, 0x08, 0x0a },
>> +	{   54660000u,   62500000u, 0x28, 0x00, 0x00, 0x08, 0x0a },
>> +	{   62500000u,   75000000u, 0x27, 0x00, 0x00, 0x08, 0x0a },
>> +	{   75000000u,   90630000u, 0x23, 0x00, 0x00, 0x08, 0x0a },
>> +	{   90630000u,  109370000u, 0x20, 0x00, 0x00, 0x08, 0x0a },
>> +	{  109370000u,  125000000u, 0x20, 0x00, 0x00, 0x08, 0x0a },
>> +	{  125000000u,  150000000u, 0x1f, 0x00, 0x00, 0x08, 0x0a },
>> +	{  150000000u,  181250000u, 0x1b, 0x00, 0x00, 0x08, 0x0a },
>> +	{  181250000u,  218750000u, 0x18, 0x00, 0x00, 0x08, 0x0a },
>> +	{  218750000u,  250000000u, 0x18, 0x00, 0x00, 0x08, 0x0a },
>> +	{  250000000u,  300000000u, 0x17, 0x00, 0x00, 0x08, 0x0a },
>> +	{  300000000u,  362500000u, 0x13, 0x00, 0x00, 0x08, 0x0a },
>> +	{  362500000u,  455480000u, 0x10, 0x00, 0x00, 0x08, 0x0a },
>> +	{  455480000u,  500000000u, 0x10, 0x00, 0x00, 0x08, 0x0a },
>> +	{  500000000u,  600000000u, 0x0f, 0x00, 0x00, 0x08, 0x0a },
>> +	{  600000000u,  725000000u, 0x0b, 0x00, 0x00, 0x08, 0x0a },
>> +	{  725000000u,  875000000u, 0x08, 0x00, 0x00, 0x08, 0x0a },
>> +	{  875000000u, 1000000000u, 0x08, 0x00, 0x00, 0x08, 0x0a },
>> +	{ 1000000000u, 1200000000u, 0x07, 0x00, 0x00, 0x08, 0x0a },
>> +	{ 1200000000u, 1250000000u, 0x03, 0x00, 0x00, 0x08, 0x0a },
>>   	{ /* sentinel */ },
>>   };
>>   
>> @@ -144,7 +183,7 @@ static void rcar_mipi_dsi_set(struct rcar_mipi_dsi *dsi, u32 reg, u32 set)
>>   	rcar_mipi_dsi_write(dsi, reg, rcar_mipi_dsi_read(dsi, reg) | set);
>>   }
>>   
>> -static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
>> +static int rcar_mipi_dsi_write_phtw(struct rcar_mipi_dsi *dsi, u32 phtw)
>>   {
>>   	u32 status;
>>   	int ret;
>> @@ -163,32 +202,231 @@ static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
>>   	return ret;
>>   }
>>   
>> +static int rcar_mipi_dsi_write_phtw_arr(struct rcar_mipi_dsi *dsi,
>> +					const u32 *phtw, unsigned int size)
>> +{
>> +	for (unsigned int i = 0; i < size; i++) {
>> +		int ret = rcar_mipi_dsi_write_phtw(dsi, phtw[i]);
>> +
>> +		if (ret < 0)
>> +			return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +#define WRITE_PHTW(...)                                               \
>> +	({                                                            \
>> +		static const u32 phtw[] = { __VA_ARGS__ };            \
>> +		int ret;                                              \
>> +		ret = rcar_mipi_dsi_write_phtw_arr(dsi, phtw,         \
>> +						   ARRAY_SIZE(phtw)); \
>> +		ret;                                                  \
>> +	})
>> +
>> +static int rcar_mipi_dsi_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
> 
> You're mixing the R8A779* names and the short names. I'd use one of the
> two and stick to it, probably the short name (up to you).

Hmm that's true. The short names are easier to distinguish visually, so 
I'll use those.

>> +{
>> +	return WRITE_PHTW(0x01020114, 0x01600115, 0x01030116, 0x0102011d,
>> +			  0x011101a4, 0x018601a4, 0x014201a0, 0x010001a3,
>> +			  0x0101011f);
>> +}
>> +
>> +static int rcar_mipi_dsi_post_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
>> +{
>> +	return WRITE_PHTW(0x010c0130, 0x010c0140, 0x010c0150, 0x010c0180,
>> +			  0x010c0190, 0x010a0160, 0x010a0170, 0x01800164,
>> +			  0x01800174);
>> +}
>> +
>> +static int rcar_mipi_dsi_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
>> +				       const struct dsi_setup_info *setup_info)
>> +{
>> +	int ret;
>> +
>> +	if (setup_info->hsfreq < MHZ(450)) {
>> +		ret = WRITE_PHTW(0x01010100, 0x011b01ac);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	ret = WRITE_PHTW(0x01010100, 0x01030173, 0x01000174, 0x01500175,
>> +			 0x01030176, 0x01040166, 0x010201ad);
>> +	if (ret)
>> +		return ret;
>> +
>> +	if (setup_info->hsfreq <= MHZ(1000))
>> +		ret = WRITE_PHTW(0x01020100, 0x01910170, 0x01020171,
>> +				 0x01110172);
>> +	else if (setup_info->hsfreq <= MHZ(1500))
>> +		ret = WRITE_PHTW(0x01020100, 0x01980170, 0x01030171,
>> +				 0x01100172);
>> +	else if (setup_info->hsfreq <= MHZ(2500))
>> +		ret = WRITE_PHTW(0x01020100, 0x0144016b, 0x01000172);
>> +	else
>> +		return -EINVAL;
>> +
>> +	if (ret)
>> +		return ret;
>> +
>> +	if (dsi->lanes <= 1) {
>> +		ret = WRITE_PHTW(0x01070100, 0x010e010b);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	if (dsi->lanes <= 2) {
>> +		ret = WRITE_PHTW(0x01090100, 0x010e010b);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	if (dsi->lanes <= 3) {
>> +		ret = WRITE_PHTW(0x010b0100, 0x010e010b);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	if (setup_info->hsfreq <= MHZ(1500)) {
>> +		ret = WRITE_PHTW(0x01010100, 0x01c0016e);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int
>> +rcar_mipi_dsi_post_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
>> +				 const struct dsi_setup_info *setup_info)
>> +{
>> +	u32 status;
>> +	int ret;
>> +
>> +	if (setup_info->hsfreq <= MHZ(1500)) {
>> +		WRITE_PHTW(0x01020100, 0x00000180);
>> +
>> +		ret = read_poll_timeout(rcar_mipi_dsi_read, status,
>> +					status & PHTR_TEST, 2000, 10000, false,
>> +					dsi, PHTR);
>> +		if (ret < 0) {
>> +			dev_err(dsi->dev, "failed to test PHTR\n");
>> +			return ret;
>> +		}
>> +
>> +		WRITE_PHTW(0x01010100, 0x0100016e);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>>   /* -----------------------------------------------------------------------------
>>    * Hardware Setup
>>    */
>>   
>> -struct dsi_setup_info {
>> -	unsigned long fout;
>> -	u16 vco_cntrl;
>> -	u16 prop_cntrl;
>> -	u16 hsfreqrange;
>> -	u16 div;
>> -	unsigned int m;
>> -	unsigned int n;
>> -};
>> +static void rcar_mipi_dsi_pll_calc_r8a779a0(struct rcar_mipi_dsi *dsi,
>> +					    struct clk *clk,
>> +					    unsigned long fout_target,
>> +					    struct dsi_setup_info *setup_info)
>> +{
>> +	unsigned int best_err = -1;
>> +	unsigned long fin;
>> +
>> +	fin = clk_get_rate(clk);
>> +
>> +	for (unsigned int n = 3; n <= 8; n++) {
>> +		unsigned long fpfd;
>> +
>> +		fpfd = fin / n;
>> +
>> +		if (fpfd < MHZ(2) || fpfd > MHZ(8))
>> +			continue;
>> +
>> +		for (unsigned int m = 64; m <= 625; m++) {
>> +			unsigned int err;
>> +			u64 fout;
>> +
>> +			fout = (u64)fpfd * m;
>> +
>> +			if (fout < MHZ(320) || fout > MHZ(1250))
>> +				continue;
>> +
>> +			fout = div64_u64(fout, setup_info->vclk_divider);
>> +
>> +			if (fout < setup_info->clkset->min_freq ||
>> +			    fout > setup_info->clkset->max_freq)
>> +				continue;
>> +
>> +			err = abs((long)(fout - fout_target) * 10000 /
>> +				  (long)fout_target);
>> +
>> +			if (err < best_err) {
>> +				setup_info->m = m;
>> +				setup_info->n = n;
>> +				setup_info->fout = (unsigned long)fout;
>> +				best_err = err;
>> +
>> +				if (err == 0)
>> +					return;
>> +			}
>> +		}
>> +	}
>> +}
>> +
>> +static void rcar_mipi_dsi_pll_calc_r8a779g0(struct rcar_mipi_dsi *dsi,
>> +					    struct clk *clk,
>> +					    unsigned long fout_target,
>> +					    struct dsi_setup_info *setup_info)
>> +{
>> +	unsigned int best_err = -1;
>> +	unsigned long fin;
>> +
>> +	fin = clk_get_rate(clk);
> 
> This could move to the caller.

Ok.

>> +
>> +	for (unsigned int n = 1; n <= 8; n++) {
>> +		unsigned long fpfd;
>> +
>> +		fpfd = fin / n;
>> +
>> +		if (fpfd < MHZ(8) || fpfd > MHZ(24))
>> +			continue;
>> +
>> +		for (unsigned int m = 167; m <= 1000; m++) {
>> +			unsigned int err;
>> +			u64 fout;
>> +
>> +			fout = div64_u64((u64)fpfd * m, 2);
>> +
>> +			if (fout < MHZ(2000) || fout > MHZ(4000))
>> +				continue;
>> +
>> +			fout = div64_u64(fout, setup_info->vclk_divider);
>> +
>> +			if (fout < setup_info->clkset->min_freq ||
>> +			    fout > setup_info->clkset->max_freq)
>> +				continue;
>> +
>> +			err = abs((long)(fout - fout_target) * 10000 /
>> +				  (long)fout_target);
> 
> Add a blank line here, or remove it from the previous function.

Ok.

>> +			if (err < best_err) {
>> +				setup_info->m = m;
>> +				setup_info->n = n;
>> +				setup_info->fout = (unsigned long)fout;
>> +				best_err = err;
>> +
>> +				if (err == 0)
>> +					return;
>> +			}
>> +		}
>> +	}
>> +}
> 
> This function could be parameterized, up to you.

I thought about it, but it would somewhat obfuscate the code. Now it's 
easier to look at the HW docs and read the function. If we get more PLL 
versions, then I think we'll have to create a parametrized version...

>>   
>>   static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
>>   					  struct clk *clk, unsigned long target,
>>   					  struct dsi_setup_info *setup_info)
>>   {
>>   
>> -	const struct vco_cntrl_value *vco_cntrl;
>> +	const struct dsi_clk_config *clkset;
>>   	unsigned long fout_target;
>> -	unsigned long fin, fout;
>> -	unsigned long hsfreq;
>> -	unsigned int best_err = -1;
>> -	unsigned int divider;
>> -	unsigned int n;
>>   	unsigned int i;
>>   	unsigned int err;
>>   
>> @@ -198,70 +436,53 @@ static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
>>   	 */
>>   	fout_target = target * mipi_dsi_pixel_format_to_bpp(dsi->format)
>>   		    / (2 * dsi->lanes);
>> -	if (fout_target < 40000000 || fout_target > 1250000000)
>> +	if (fout_target < MHZ(40) || fout_target > MHZ(1250))
>>   		return;
>>   
>>   	/* Find vco_cntrl */
>> -	for (vco_cntrl = vco_cntrl_table; vco_cntrl->min_freq != 0; vco_cntrl++) {
>> -		if (fout_target > vco_cntrl->min_freq &&
>> -		    fout_target <= vco_cntrl->max_freq) {
>> -			setup_info->vco_cntrl = vco_cntrl->value;
>> -			if (fout_target >= 1150000000)
>> -				setup_info->prop_cntrl = 0x0c;
>> -			else
>> -				setup_info->prop_cntrl = 0x0b;
>> +	for (clkset = dsi->info->clk_cfg; clkset->min_freq != 0; clkset++) {
>> +		if (fout_target > clkset->min_freq &&
>> +		    fout_target <= clkset->max_freq) {
>> +			setup_info->clkset = clkset;
>>   			break;
>>   		}
>>   	}
>>   
>> -	/* Add divider */
>> -	setup_info->div = (setup_info->vco_cntrl & 0x30) >> 4;
>> +	switch (dsi->info->model) {
>> +	case RCAR_DSI_R8A779A0:
>> +		setup_info->vclk_divider = 1 << ((clkset->vco_cntrl >> 4) & 0x3);
> 
> If you stored (clkset->vco_cntrl >> 4) & 0x3 in setup_info->vclk_divider
> you wouldn't have to use __ffs() in rcar_mipi_dsi_startup(). You could
> also drop the - 1 there, which would allow dropping one of the
> switch(dsi->info->model). You can store the real divider value in
> setup_info separately for rcar_mipi_dsi_pll_calc_r8a779a0(), or pass it
> to the function.
> 
>> +		rcar_mipi_dsi_pll_calc_r8a779a0(dsi, clk, fout_target, setup_info);
>> +		break;
>> +
>> +	case RCAR_DSI_R8A779G0:
>> +		setup_info->vclk_divider = 1 << (((clkset->vco_cntrl >> 3) & 0x7) + 1);
>> +		rcar_mipi_dsi_pll_calc_r8a779g0(dsi, clk, fout_target, setup_info);
>> +		break;
>> +
>> +	default:
>> +		return;
>> +	}
>>   
>>   	/* Find hsfreqrange */
>> -	hsfreq = fout_target * 2;
>> +	setup_info->hsfreq = setup_info->fout * 2;
>>   	for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++) {
>> -		if (hsfreqrange_table[i][0] >= hsfreq) {
>> +		if (hsfreqrange_table[i][0] >= setup_info->hsfreq) {
>>   			setup_info->hsfreqrange = hsfreqrange_table[i][1];
>>   			break;
>>   		}
>>   	}
>>   
>> -	/*
>> -	 * Calculate n and m for PLL clock
>> -	 * Following the HW manual the ranges of n and m are
>> -	 * n = [3-8] and m = [64-625]
>> -	 */
> 
> I'd keep the comment in rcar_mipi_dsi_pll_calc_r8a779a0(), and add a
> similar comment in rcar_mipi_dsi_pll_calc_r8a779g0().

Well, I dropped the comment as it's just pointing the obvious: we are 
calculating PLL config, and the n and m ranges are easily visible in the 
code below. I can add them if you think they are useful.

>> -	fin = clk_get_rate(clk);
>> -	divider = 1 << setup_info->div;
>> -	for (n = 3; n < 9; n++) {
>> -		unsigned long fpfd;
>> -		unsigned int m;
>> -
>> -		fpfd = fin / n;
>> -
>> -		for (m = 64; m < 626; m++) {
>> -			fout = fpfd * m / divider;
>> -			err = abs((long)(fout - fout_target) * 10000 /
>> -				  (long)fout_target);
>> -			if (err < best_err) {
>> -				setup_info->m = m - 2;
>> -				setup_info->n = n - 1;
>> -				setup_info->fout = fout;
>> -				best_err = err;
>> -				if (err == 0)
>> -					goto done;
>> -			}
>> -		}
>> -	}
>> +	err = abs((long)(setup_info->fout - fout_target) * 10000 / (long)fout_target);
>>   
>> -done:
>>   	dev_dbg(dsi->dev,
>> -		"%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/DIV %u/%u/%u\n",
>> -		clk, fin, setup_info->fout, fout_target, best_err / 100,
>> -		best_err % 100, setup_info->m, setup_info->n, setup_info->div);
>> +		"Fout = %u * %lu / (2 * %u * %u) = %lu (target %lu Hz, error %d.%02u%%)\n",
> 
> Is the "2 *" valid on V3U too ?

Good catch. It is not.

>> +		setup_info->m, clk_get_rate(clk), setup_info->n, setup_info->vclk_divider,
> 
> If you keep the clk_get_rate() call in this function you wouldn't have
> to call it again here.

Yep.

>> +		setup_info->fout, fout_target,
>> +		err / 100, err % 100);
>> +
>>   	dev_dbg(dsi->dev,
>>   		"vco_cntrl = 0x%x\tprop_cntrl = 0x%x\thsfreqrange = 0x%x\n",
>> -		setup_info->vco_cntrl, setup_info->prop_cntrl,
>> +		clkset->vco_cntrl, clkset->prop_cntrl,
>>   		setup_info->hsfreqrange);
>>   }
>>   
>> @@ -324,7 +545,7 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>>   {
>>   	struct dsi_setup_info setup_info = {};
>>   	unsigned int timeout;
>> -	int ret, i;
>> +	int ret;
>>   	int dsi_format;
>>   	u32 phy_setup;
>>   	u32 clockset2, clockset3;
>> @@ -360,10 +581,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>>   	phy_setup |= PHYSETUP_HSFREQRANGE(setup_info.hsfreqrange);
>>   	rcar_mipi_dsi_write(dsi, PHYSETUP, phy_setup);
>>   
>> -	for (i = 0; i < ARRAY_SIZE(phtw); i++) {
>> -		ret = rcar_mipi_dsi_phtw_test(dsi, phtw[i]);
>> +	switch (dsi->info->model) {
>> +	case RCAR_DSI_R8A779A0:
>> +		ret = rcar_mipi_dsi_init_phtw_v3u(dsi);
>> +		if (ret < 0)
>> +			return ret;
>> +		break;
>> +
>> +	case RCAR_DSI_R8A779G0:
>> +		ret = rcar_mipi_dsi_init_phtw_v4h(dsi, &setup_info);
>>   		if (ret < 0)
>>   			return ret;
>> +		break;
>> +
>> +	default:
>> +		return -ENODEV;
> 
> This can't happen. Same below.

I thought the compiler would warn about it, but at least mine doesn't, 
so I'll drop the default cases.

>>   	}
>>   
>>   	/* PLL Clock Setting */
>> @@ -371,12 +603,13 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>>   	rcar_mipi_dsi_set(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
>>   	rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
>>   
>> -	clockset2 = CLOCKSET2_M(setup_info.m) | CLOCKSET2_N(setup_info.n)
>> -		  | CLOCKSET2_VCO_CNTRL(setup_info.vco_cntrl);
>> -	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.prop_cntrl)
>> -		  | CLOCKSET3_INT_CNTRL(0)
>> -		  | CLOCKSET3_CPBIAS_CNTRL(0x10)
>> -		  | CLOCKSET3_GMP_CNTRL(1);
>> +	clockset2 = CLOCKSET2_M(setup_info.m - dsi->info->clockset2_m_offset)
>> +		  | CLOCKSET2_N(setup_info.n - dsi->info->clockset2_n_offset)
>> +		  | CLOCKSET2_VCO_CNTRL(setup_info.clkset->vco_cntrl);
>> +	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.clkset->prop_cntrl)
>> +		  | CLOCKSET3_INT_CNTRL(setup_info.clkset->int_cntrl)
>> +		  | CLOCKSET3_CPBIAS_CNTRL(setup_info.clkset->cpbias_cntrl)
>> +		  | CLOCKSET3_GMP_CNTRL(setup_info.clkset->gmp_cntrl);
>>   	rcar_mipi_dsi_write(dsi, CLOCKSET2, clockset2);
>>   	rcar_mipi_dsi_write(dsi, CLOCKSET3, clockset3);
>>   
>> @@ -407,10 +640,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>>   		return -ETIMEDOUT;
>>   	}
>>   
>> -	for (i = 0; i < ARRAY_SIZE(phtw2); i++) {
>> -		ret = rcar_mipi_dsi_phtw_test(dsi, phtw2[i]);
>> +	switch (dsi->info->model) {
>> +	case RCAR_DSI_R8A779A0:
>> +		ret = rcar_mipi_dsi_post_init_phtw_v3u(dsi);
>>   		if (ret < 0)
>>   			return ret;
>> +		break;
>> +
>> +	case RCAR_DSI_R8A779G0:
>> +		ret = rcar_mipi_dsi_post_init_phtw_v4h(dsi, &setup_info);
>> +		if (ret < 0)
>> +			return ret;
>> +		break;
>> +
>> +	default:
>> +		return -ENODEV;
>>   	}
>>   
>>   	/* Enable DOT clock */
>> @@ -427,8 +671,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>>   		dev_warn(dsi->dev, "unsupported format");
>>   		return -EINVAL;
>>   	}
>> -	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_DIV(setup_info.div)
>> -		|  VCLKSET_LANE(dsi->lanes - 1);
>> +
>> +	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_LANE(dsi->lanes - 1);
>> +
>> +	switch (dsi->info->model) {
>> +	case RCAR_DSI_R8A779A0:
>> +		vclkset |= VCLKSET_DIV_R8A779A0(__ffs(setup_info.vclk_divider));
>> +		break;
>> +
>> +	case RCAR_DSI_R8A779G0:
>> +		vclkset |= VCLKSET_DIV_R8A779G0(__ffs(setup_info.vclk_divider) - 1);
>> +		break;
>> +
>> +	default:
>> +		return -ENODEV;
>> +	}
>>   
>>   	rcar_mipi_dsi_write(dsi, VCLKSET, vclkset);
>>   
>> @@ -841,8 +1098,25 @@ static int rcar_mipi_dsi_remove(struct platform_device *pdev)
>>   	return 0;
>>   }
>>   
>> +static const struct rcar_mipi_dsi_device_info r8a779a0_data = {
>> +	.model = RCAR_DSI_R8A779A0,
>> +	.clk_cfg = dsi_clk_cfg_r8a779a0,
>> +	.clockset2_m_offset = 2,
>> +	.clockset2_n_offset = 1,
>> +
> 
> Extra blank line.

Yep.

> 
>> +};
>> +
>> +static const struct rcar_mipi_dsi_device_info r8a779g0_data = {
>> +	.model = RCAR_DSI_R8A779G0,
>> +	.clk_cfg = dsi_clk_cfg_r8a779g0,
>> +	.clockset2_m_offset = 0,
>> +	.clockset2_n_offset = 1,
> 
> You could possibly drop clockset2_n_offset as it's identical for the two
> variants, and there's no indication it would be different in another
> version of the IP core.

Yep, I think that's fine.

  Tomi


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

* RE: [PATCH v2 7/7] drm: rcar-du: dsi: Add r8a779g0 support
  2022-11-29 11:30     ` Tomi Valkeinen
@ 2022-11-29 11:40       ` Biju Das
  2022-11-29 11:49         ` Geert Uytterhoeven
  2022-11-29 12:05       ` Laurent Pinchart
  1 sibling, 1 reply; 25+ messages in thread
From: Biju Das @ 2022-11-29 11:40 UTC (permalink / raw)
  To: Tomi Valkeinen, Laurent Pinchart
  Cc: Kieran Bingham, Rob Herring, Krzysztof Kozlowski,
	Geert Uytterhoeven, Magnus Damm, dri-devel, linux-renesas-soc,
	devicetree, linux-kernel, Andrzej Hajda, Neil Armstrong,
	Robert Foss, Jonas Karlman, Jernej Skrabec



> -----Original Message-----
> From: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> Sent: 29 November 2022 11:30
> To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Cc: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>; Rob
> Herring <robh+dt@kernel.org>; Krzysztof Kozlowski
> <krzysztof.kozlowski+dt@linaro.org>; Geert Uytterhoeven
> <geert+renesas@glider.be>; Magnus Damm <magnus.damm@gmail.com>; dri-
> devel@lists.freedesktop.org; linux-renesas-soc@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; Andrzej Hajda
> <andrzej.hajda@intel.com>; Neil Armstrong <neil.armstrong@linaro.org>;
> Robert Foss <robert.foss@linaro.org>; Jonas Karlman <jonas@kwiboo.se>;
> Jernej Skrabec <jernej.skrabec@gmail.com>
> Subject: Re: [PATCH v2 7/7] drm: rcar-du: dsi: Add r8a779g0 support
> 
> On 29/11/2022 03:49, Laurent Pinchart wrote:
> > Hi Tomi,
> >
> > Thank you for the patch.
> >
> > On Wed, Nov 23, 2022 at 08:59:46AM +0200, Tomi Valkeinen wrote:
> >> Add DSI support for r8a779g0. The main differences to r8a779a0 are in
> >> the PLL and PHTW setups.
> >>
> >> Signed-off-by: Tomi Valkeinen
> >> <tomi.valkeinen+renesas@ideasonboard.com>
> >> ---
> >>   drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c      | 484 +++++++++++++++-
> ---
> >>   drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h |   6 +-
> >>   2 files changed, 384 insertions(+), 106 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> >> b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> >> index a7f2b7f66a17..723c35726c38 100644
> >> --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> >> +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> >> @@ -9,6 +9,7 @@
> >>   #include <linux/delay.h>
> >>   #include <linux/io.h>
> >>   #include <linux/iopoll.h>
> >> +#include <linux/math64.h>
> >>   #include <linux/module.h>
> >>   #include <linux/of.h>
> >>   #include <linux/of_device.h>
> >> @@ -28,6 +29,20 @@
> >>   #include "rcar_mipi_dsi.h"
> >>   #include "rcar_mipi_dsi_regs.h"
> >>
> >> +#define MHZ(v) ((v) * 1000000u)
> >
> > Isn't the U suffix usually spelled in uppercase ? Same below.
> 
> I couldn't find any coding style guidelines on that. I like the lower
> case visually. The suffix stands out much clearer on 10000000u than on
> 10000000U. But I can change it if you feel otherwise.

https://elixir.bootlin.com/linux/v6.1-rc7/source/include/linux/units.h#L11

Maybe you could add MHZ here??

Cheers,
Biju

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

* Re: [PATCH v2 7/7] drm: rcar-du: dsi: Add r8a779g0 support
  2022-11-29 11:40       ` Biju Das
@ 2022-11-29 11:49         ` Geert Uytterhoeven
  0 siblings, 0 replies; 25+ messages in thread
From: Geert Uytterhoeven @ 2022-11-29 11:49 UTC (permalink / raw)
  To: Biju Das
  Cc: Tomi Valkeinen, Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel, Andrzej Hajda,
	Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec

Hi Biju,

On Tue, Nov 29, 2022 at 12:40 PM Biju Das <biju.das.jz@bp.renesas.com> wrote:
> > From: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> > On 29/11/2022 03:49, Laurent Pinchart wrote:
> > > On Wed, Nov 23, 2022 at 08:59:46AM +0200, Tomi Valkeinen wrote:
> > >> Add DSI support for r8a779g0. The main differences to r8a779a0 are in
> > >> the PLL and PHTW setups.
> > >>
> > >> Signed-off-by: Tomi Valkeinen
> > >> <tomi.valkeinen+renesas@ideasonboard.com>

> > >> --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> > >> +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> > >> @@ -9,6 +9,7 @@
> > >>   #include <linux/delay.h>
> > >>   #include <linux/io.h>
> > >>   #include <linux/iopoll.h>
> > >> +#include <linux/math64.h>
> > >>   #include <linux/module.h>
> > >>   #include <linux/of.h>
> > >>   #include <linux/of_device.h>
> > >> @@ -28,6 +29,20 @@
> > >>   #include "rcar_mipi_dsi.h"
> > >>   #include "rcar_mipi_dsi_regs.h"
> > >>
> > >> +#define MHZ(v) ((v) * 1000000u)
> > >
> > > Isn't the U suffix usually spelled in uppercase ? Same below.
> >
> > I couldn't find any coding style guidelines on that. I like the lower
> > case visually. The suffix stands out much clearer on 10000000u than on
> > 10000000U. But I can change it if you feel otherwise.
>
> https://elixir.bootlin.com/linux/v6.1-rc7/source/include/linux/units.h#L11
>
> Maybe you could add MHZ here??

Or use the existing MEGA? The metric system is soooo nice! ;-)

BTW, looks like the people adding definitions like

    #define MICROHZ_PER_HZ 1000000UL
    #define MILLIHZ_PER_HZ 1000UL

    #define MILLIWATT_PER_WATT 1000UL
    #define MICROWATT_PER_MILLIWATT 1000UL
    #define MICROWATT_PER_WATT 1000000UL

didn't grasp the full power...

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 7/7] drm: rcar-du: dsi: Add r8a779g0 support
  2022-11-29 11:30     ` Tomi Valkeinen
  2022-11-29 11:40       ` Biju Das
@ 2022-11-29 12:05       ` Laurent Pinchart
  1 sibling, 0 replies; 25+ messages in thread
From: Laurent Pinchart @ 2022-11-29 12:05 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Kieran Bingham, Rob Herring, Krzysztof Kozlowski,
	Geert Uytterhoeven, Magnus Damm, dri-devel, linux-renesas-soc,
	devicetree, linux-kernel, Andrzej Hajda, Neil Armstrong,
	Robert Foss, Jonas Karlman, Jernej Skrabec

Hi Tomi,

On Tue, Nov 29, 2022 at 01:30:04PM +0200, Tomi Valkeinen wrote:
> On 29/11/2022 03:49, Laurent Pinchart wrote:
> > On Wed, Nov 23, 2022 at 08:59:46AM +0200, Tomi Valkeinen wrote:
> >> Add DSI support for r8a779g0. The main differences to r8a779a0 are in
> >> the PLL and PHTW setups.
> >>
> >> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> >> ---
> >>   drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c      | 484 +++++++++++++++----
> >>   drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h |   6 +-
> >>   2 files changed, 384 insertions(+), 106 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> >> index a7f2b7f66a17..723c35726c38 100644
> >> --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> >> +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> >> @@ -9,6 +9,7 @@
> >>   #include <linux/delay.h>
> >>   #include <linux/io.h>
> >>   #include <linux/iopoll.h>
> >> +#include <linux/math64.h>
> >>   #include <linux/module.h>
> >>   #include <linux/of.h>
> >>   #include <linux/of_device.h>
> >> @@ -28,6 +29,20 @@
> >>   #include "rcar_mipi_dsi.h"
> >>   #include "rcar_mipi_dsi_regs.h"
> >>   
> >> +#define MHZ(v) ((v) * 1000000u)
> > 
> > Isn't the U suffix usually spelled in uppercase ? Same below.
> 
> I couldn't find any coding style guidelines on that. I like the lower 
> case visually. The suffix stands out much clearer on 10000000u than on 
> 10000000U. But I can change it if you feel otherwise.

The driver uses U already and I like consistency. You can change all of
them to u if you want :-)

> >> +
> >> +enum rcar_mipi_dsi_hw_model {
> >> +	RCAR_DSI_R8A779A0,
> >> +	RCAR_DSI_R8A779G0,
> >> +};
> >> +
> >> +struct rcar_mipi_dsi_device_info {
> >> +	enum rcar_mipi_dsi_hw_model model;
> >> +	const struct dsi_clk_config *clk_cfg;
> >> +	u8 clockset2_m_offset;
> >> +	u8 clockset2_n_offset;
> >> +};
> >> +
> >>   struct rcar_mipi_dsi {
> >>   	struct device *dev;
> >>   	const struct rcar_mipi_dsi_device_info *info;
> >> @@ -50,6 +65,17 @@ struct rcar_mipi_dsi {
> >>   	unsigned int lanes;
> >>   };
> >>   
> >> +struct dsi_setup_info {
> >> +	unsigned long hsfreq;
> >> +	u16 hsfreqrange;
> >> +
> >> +	unsigned long fout;
> >> +	u16 m;
> >> +	u16 n;
> >> +	u16 vclk_divider;
> >> +	const struct dsi_clk_config *clkset;
> >> +};
> >> +
> >>   static inline struct rcar_mipi_dsi *
> >>   bridge_to_rcar_mipi_dsi(struct drm_bridge *bridge)
> >>   {
> >> @@ -62,22 +88,6 @@ host_to_rcar_mipi_dsi(struct mipi_dsi_host *host)
> >>   	return container_of(host, struct rcar_mipi_dsi, host);
> >>   }
> >>   
> >> -static const u32 phtw[] = {
> >> -	0x01020114, 0x01600115, /* General testing */
> >> -	0x01030116, 0x0102011d, /* General testing */
> >> -	0x011101a4, 0x018601a4, /* 1Gbps testing */
> >> -	0x014201a0, 0x010001a3, /* 1Gbps testing */
> >> -	0x0101011f,		/* 1Gbps testing */
> >> -};
> >> -
> >> -static const u32 phtw2[] = {
> >> -	0x010c0130, 0x010c0140, /* General testing */
> >> -	0x010c0150, 0x010c0180, /* General testing */
> >> -	0x010c0190,
> >> -	0x010a0160, 0x010a0170,
> >> -	0x01800164, 0x01800174,	/* 1Gbps testing */
> >> -};
> >> -
> >>   static const u32 hsfreqrange_table[][2] = {
> >>   	{ 80000000U,   0x00 }, { 90000000U,   0x10 }, { 100000000U,  0x20 },
> >>   	{ 110000000U,  0x30 }, { 120000000U,  0x01 }, { 130000000U,  0x11 },
> >> @@ -103,24 +113,53 @@ static const u32 hsfreqrange_table[][2] = {
> >>   	{ /* sentinel */ },
> >>   };
> >>   
> >> -struct vco_cntrl_value {
> >> +struct dsi_clk_config {
> >>   	u32 min_freq;
> >>   	u32 max_freq;
> >> -	u16 value;
> >> +	u8 vco_cntrl;
> >> +	u8 cpbias_cntrl;
> >> +	u8 gmp_cntrl;
> >> +	u8 int_cntrl;
> >> +	u8 prop_cntrl;
> >>   };
> >>   
> >> -static const struct vco_cntrl_value vco_cntrl_table[] = {
> >> -	{ .min_freq = 40000000U,   .max_freq = 55000000U,   .value = 0x3f },
> >> -	{ .min_freq = 52500000U,   .max_freq = 80000000U,   .value = 0x39 },
> >> -	{ .min_freq = 80000000U,   .max_freq = 110000000U,  .value = 0x2f },
> >> -	{ .min_freq = 105000000U,  .max_freq = 160000000U,  .value = 0x29 },
> >> -	{ .min_freq = 160000000U,  .max_freq = 220000000U,  .value = 0x1f },
> >> -	{ .min_freq = 210000000U,  .max_freq = 320000000U,  .value = 0x19 },
> >> -	{ .min_freq = 320000000U,  .max_freq = 440000000U,  .value = 0x0f },
> >> -	{ .min_freq = 420000000U,  .max_freq = 660000000U,  .value = 0x09 },
> >> -	{ .min_freq = 630000000U,  .max_freq = 1149000000U, .value = 0x03 },
> >> -	{ .min_freq = 1100000000U, .max_freq = 1152000000U, .value = 0x01 },
> >> -	{ .min_freq = 1150000000U, .max_freq = 1250000000U, .value = 0x01 },
> >> +static const struct dsi_clk_config dsi_clk_cfg_r8a779a0[] = {
> >> +	{   40000000u,   55000000u, 0x3f, 0x10, 0x01, 0x00, 0x0b },
> >> +	{   52500000u,   80000000u, 0x39, 0x10, 0x01, 0x00, 0x0b },
> > 
> > Would MHZ(52.5) do the right thing ? If so, I'd use the macro through
> > those tables.
> 
> That's a great idea. It had never occurred to me that we can use floats 
> in the kernel code, as long as we convert to ints when the preprocessor 
> is done.
> 
> >> +	{   80000000u,  110000000u, 0x2f, 0x10, 0x01, 0x00, 0x0b },
> >> +	{  105000000u,  160000000u, 0x29, 0x10, 0x01, 0x00, 0x0b },
> >> +	{  160000000u,  220000000u, 0x1f, 0x10, 0x01, 0x00, 0x0b },
> >> +	{  210000000u,  320000000u, 0x19, 0x10, 0x01, 0x00, 0x0b },
> >> +	{  320000000u,  440000000u, 0x0f, 0x10, 0x01, 0x00, 0x0b },
> >> +	{  420000000u,  660000000u, 0x09, 0x10, 0x01, 0x00, 0x0b },
> >> +	{  630000000u, 1149000000u, 0x03, 0x10, 0x01, 0x00, 0x0b },
> >> +	{ 1100000000u, 1152000000u, 0x01, 0x10, 0x01, 0x00, 0x0b },
> >> +	{ 1150000000u, 1250000000u, 0x01, 0x10, 0x01, 0x00, 0x0c },
> >> +	{ /* sentinel */ },
> >> +};
> >> +
> >> +static const struct dsi_clk_config dsi_clk_cfg_r8a779g0[] = {
> >> +	{   40000000u,   45310000u, 0x2b, 0x00, 0x00, 0x08, 0x0a },
> >> +	{   45310000u,   54660000u, 0x28, 0x00, 0x00, 0x08, 0x0a },
> >> +	{   54660000u,   62500000u, 0x28, 0x00, 0x00, 0x08, 0x0a },
> >> +	{   62500000u,   75000000u, 0x27, 0x00, 0x00, 0x08, 0x0a },
> >> +	{   75000000u,   90630000u, 0x23, 0x00, 0x00, 0x08, 0x0a },
> >> +	{   90630000u,  109370000u, 0x20, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  109370000u,  125000000u, 0x20, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  125000000u,  150000000u, 0x1f, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  150000000u,  181250000u, 0x1b, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  181250000u,  218750000u, 0x18, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  218750000u,  250000000u, 0x18, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  250000000u,  300000000u, 0x17, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  300000000u,  362500000u, 0x13, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  362500000u,  455480000u, 0x10, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  455480000u,  500000000u, 0x10, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  500000000u,  600000000u, 0x0f, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  600000000u,  725000000u, 0x0b, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  725000000u,  875000000u, 0x08, 0x00, 0x00, 0x08, 0x0a },
> >> +	{  875000000u, 1000000000u, 0x08, 0x00, 0x00, 0x08, 0x0a },
> >> +	{ 1000000000u, 1200000000u, 0x07, 0x00, 0x00, 0x08, 0x0a },
> >> +	{ 1200000000u, 1250000000u, 0x03, 0x00, 0x00, 0x08, 0x0a },
> >>   	{ /* sentinel */ },
> >>   };
> >>   
> >> @@ -144,7 +183,7 @@ static void rcar_mipi_dsi_set(struct rcar_mipi_dsi *dsi, u32 reg, u32 set)
> >>   	rcar_mipi_dsi_write(dsi, reg, rcar_mipi_dsi_read(dsi, reg) | set);
> >>   }
> >>   
> >> -static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
> >> +static int rcar_mipi_dsi_write_phtw(struct rcar_mipi_dsi *dsi, u32 phtw)
> >>   {
> >>   	u32 status;
> >>   	int ret;
> >> @@ -163,32 +202,231 @@ static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
> >>   	return ret;
> >>   }
> >>   
> >> +static int rcar_mipi_dsi_write_phtw_arr(struct rcar_mipi_dsi *dsi,
> >> +					const u32 *phtw, unsigned int size)
> >> +{
> >> +	for (unsigned int i = 0; i < size; i++) {
> >> +		int ret = rcar_mipi_dsi_write_phtw(dsi, phtw[i]);
> >> +
> >> +		if (ret < 0)
> >> +			return ret;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +#define WRITE_PHTW(...)                                               \
> >> +	({                                                            \
> >> +		static const u32 phtw[] = { __VA_ARGS__ };            \
> >> +		int ret;                                              \
> >> +		ret = rcar_mipi_dsi_write_phtw_arr(dsi, phtw,         \
> >> +						   ARRAY_SIZE(phtw)); \
> >> +		ret;                                                  \
> >> +	})
> >> +
> >> +static int rcar_mipi_dsi_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
> > 
> > You're mixing the R8A779* names and the short names. I'd use one of the
> > two and stick to it, probably the short name (up to you).
> 
> Hmm that's true. The short names are easier to distinguish visually, so 
> I'll use those.
> 
> >> +{
> >> +	return WRITE_PHTW(0x01020114, 0x01600115, 0x01030116, 0x0102011d,
> >> +			  0x011101a4, 0x018601a4, 0x014201a0, 0x010001a3,
> >> +			  0x0101011f);
> >> +}
> >> +
> >> +static int rcar_mipi_dsi_post_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
> >> +{
> >> +	return WRITE_PHTW(0x010c0130, 0x010c0140, 0x010c0150, 0x010c0180,
> >> +			  0x010c0190, 0x010a0160, 0x010a0170, 0x01800164,
> >> +			  0x01800174);
> >> +}
> >> +
> >> +static int rcar_mipi_dsi_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
> >> +				       const struct dsi_setup_info *setup_info)
> >> +{
> >> +	int ret;
> >> +
> >> +	if (setup_info->hsfreq < MHZ(450)) {
> >> +		ret = WRITE_PHTW(0x01010100, 0x011b01ac);
> >> +		if (ret)
> >> +			return ret;
> >> +	}
> >> +
> >> +	ret = WRITE_PHTW(0x01010100, 0x01030173, 0x01000174, 0x01500175,
> >> +			 0x01030176, 0x01040166, 0x010201ad);
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	if (setup_info->hsfreq <= MHZ(1000))
> >> +		ret = WRITE_PHTW(0x01020100, 0x01910170, 0x01020171,
> >> +				 0x01110172);
> >> +	else if (setup_info->hsfreq <= MHZ(1500))
> >> +		ret = WRITE_PHTW(0x01020100, 0x01980170, 0x01030171,
> >> +				 0x01100172);
> >> +	else if (setup_info->hsfreq <= MHZ(2500))
> >> +		ret = WRITE_PHTW(0x01020100, 0x0144016b, 0x01000172);
> >> +	else
> >> +		return -EINVAL;
> >> +
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	if (dsi->lanes <= 1) {
> >> +		ret = WRITE_PHTW(0x01070100, 0x010e010b);
> >> +		if (ret)
> >> +			return ret;
> >> +	}
> >> +
> >> +	if (dsi->lanes <= 2) {
> >> +		ret = WRITE_PHTW(0x01090100, 0x010e010b);
> >> +		if (ret)
> >> +			return ret;
> >> +	}
> >> +
> >> +	if (dsi->lanes <= 3) {
> >> +		ret = WRITE_PHTW(0x010b0100, 0x010e010b);
> >> +		if (ret)
> >> +			return ret;
> >> +	}
> >> +
> >> +	if (setup_info->hsfreq <= MHZ(1500)) {
> >> +		ret = WRITE_PHTW(0x01010100, 0x01c0016e);
> >> +		if (ret)
> >> +			return ret;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int
> >> +rcar_mipi_dsi_post_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
> >> +				 const struct dsi_setup_info *setup_info)
> >> +{
> >> +	u32 status;
> >> +	int ret;
> >> +
> >> +	if (setup_info->hsfreq <= MHZ(1500)) {
> >> +		WRITE_PHTW(0x01020100, 0x00000180);
> >> +
> >> +		ret = read_poll_timeout(rcar_mipi_dsi_read, status,
> >> +					status & PHTR_TEST, 2000, 10000, false,
> >> +					dsi, PHTR);
> >> +		if (ret < 0) {
> >> +			dev_err(dsi->dev, "failed to test PHTR\n");
> >> +			return ret;
> >> +		}
> >> +
> >> +		WRITE_PHTW(0x01010100, 0x0100016e);
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >>   /* -----------------------------------------------------------------------------
> >>    * Hardware Setup
> >>    */
> >>   
> >> -struct dsi_setup_info {
> >> -	unsigned long fout;
> >> -	u16 vco_cntrl;
> >> -	u16 prop_cntrl;
> >> -	u16 hsfreqrange;
> >> -	u16 div;
> >> -	unsigned int m;
> >> -	unsigned int n;
> >> -};
> >> +static void rcar_mipi_dsi_pll_calc_r8a779a0(struct rcar_mipi_dsi *dsi,
> >> +					    struct clk *clk,
> >> +					    unsigned long fout_target,
> >> +					    struct dsi_setup_info *setup_info)
> >> +{
> >> +	unsigned int best_err = -1;
> >> +	unsigned long fin;
> >> +
> >> +	fin = clk_get_rate(clk);
> >> +
> >> +	for (unsigned int n = 3; n <= 8; n++) {
> >> +		unsigned long fpfd;
> >> +
> >> +		fpfd = fin / n;
> >> +
> >> +		if (fpfd < MHZ(2) || fpfd > MHZ(8))
> >> +			continue;
> >> +
> >> +		for (unsigned int m = 64; m <= 625; m++) {
> >> +			unsigned int err;
> >> +			u64 fout;
> >> +
> >> +			fout = (u64)fpfd * m;
> >> +
> >> +			if (fout < MHZ(320) || fout > MHZ(1250))
> >> +				continue;
> >> +
> >> +			fout = div64_u64(fout, setup_info->vclk_divider);
> >> +
> >> +			if (fout < setup_info->clkset->min_freq ||
> >> +			    fout > setup_info->clkset->max_freq)
> >> +				continue;
> >> +
> >> +			err = abs((long)(fout - fout_target) * 10000 /
> >> +				  (long)fout_target);
> >> +
> >> +			if (err < best_err) {
> >> +				setup_info->m = m;
> >> +				setup_info->n = n;
> >> +				setup_info->fout = (unsigned long)fout;
> >> +				best_err = err;
> >> +
> >> +				if (err == 0)
> >> +					return;
> >> +			}
> >> +		}
> >> +	}
> >> +}
> >> +
> >> +static void rcar_mipi_dsi_pll_calc_r8a779g0(struct rcar_mipi_dsi *dsi,
> >> +					    struct clk *clk,
> >> +					    unsigned long fout_target,
> >> +					    struct dsi_setup_info *setup_info)
> >> +{
> >> +	unsigned int best_err = -1;
> >> +	unsigned long fin;
> >> +
> >> +	fin = clk_get_rate(clk);
> > 
> > This could move to the caller.
> 
> Ok.
> 
> >> +
> >> +	for (unsigned int n = 1; n <= 8; n++) {
> >> +		unsigned long fpfd;
> >> +
> >> +		fpfd = fin / n;
> >> +
> >> +		if (fpfd < MHZ(8) || fpfd > MHZ(24))
> >> +			continue;
> >> +
> >> +		for (unsigned int m = 167; m <= 1000; m++) {
> >> +			unsigned int err;
> >> +			u64 fout;
> >> +
> >> +			fout = div64_u64((u64)fpfd * m, 2);
> >> +
> >> +			if (fout < MHZ(2000) || fout > MHZ(4000))
> >> +				continue;
> >> +
> >> +			fout = div64_u64(fout, setup_info->vclk_divider);
> >> +
> >> +			if (fout < setup_info->clkset->min_freq ||
> >> +			    fout > setup_info->clkset->max_freq)
> >> +				continue;
> >> +
> >> +			err = abs((long)(fout - fout_target) * 10000 /
> >> +				  (long)fout_target);
> > 
> > Add a blank line here, or remove it from the previous function.
> 
> Ok.
> 
> >> +			if (err < best_err) {
> >> +				setup_info->m = m;
> >> +				setup_info->n = n;
> >> +				setup_info->fout = (unsigned long)fout;
> >> +				best_err = err;
> >> +
> >> +				if (err == 0)
> >> +					return;
> >> +			}
> >> +		}
> >> +	}
> >> +}
> > 
> > This function could be parameterized, up to you.
> 
> I thought about it, but it would somewhat obfuscate the code. Now it's 
> easier to look at the HW docs and read the function. If we get more PLL 
> versions, then I think we'll have to create a parametrized version...
> 
> >>   
> >>   static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
> >>   					  struct clk *clk, unsigned long target,
> >>   					  struct dsi_setup_info *setup_info)
> >>   {
> >>   
> >> -	const struct vco_cntrl_value *vco_cntrl;
> >> +	const struct dsi_clk_config *clkset;
> >>   	unsigned long fout_target;
> >> -	unsigned long fin, fout;
> >> -	unsigned long hsfreq;
> >> -	unsigned int best_err = -1;
> >> -	unsigned int divider;
> >> -	unsigned int n;
> >>   	unsigned int i;
> >>   	unsigned int err;
> >>   
> >> @@ -198,70 +436,53 @@ static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
> >>   	 */
> >>   	fout_target = target * mipi_dsi_pixel_format_to_bpp(dsi->format)
> >>   		    / (2 * dsi->lanes);
> >> -	if (fout_target < 40000000 || fout_target > 1250000000)
> >> +	if (fout_target < MHZ(40) || fout_target > MHZ(1250))
> >>   		return;
> >>   
> >>   	/* Find vco_cntrl */
> >> -	for (vco_cntrl = vco_cntrl_table; vco_cntrl->min_freq != 0; vco_cntrl++) {
> >> -		if (fout_target > vco_cntrl->min_freq &&
> >> -		    fout_target <= vco_cntrl->max_freq) {
> >> -			setup_info->vco_cntrl = vco_cntrl->value;
> >> -			if (fout_target >= 1150000000)
> >> -				setup_info->prop_cntrl = 0x0c;
> >> -			else
> >> -				setup_info->prop_cntrl = 0x0b;
> >> +	for (clkset = dsi->info->clk_cfg; clkset->min_freq != 0; clkset++) {
> >> +		if (fout_target > clkset->min_freq &&
> >> +		    fout_target <= clkset->max_freq) {
> >> +			setup_info->clkset = clkset;
> >>   			break;
> >>   		}
> >>   	}
> >>   
> >> -	/* Add divider */
> >> -	setup_info->div = (setup_info->vco_cntrl & 0x30) >> 4;
> >> +	switch (dsi->info->model) {
> >> +	case RCAR_DSI_R8A779A0:
> >> +		setup_info->vclk_divider = 1 << ((clkset->vco_cntrl >> 4) & 0x3);
> > 
> > If you stored (clkset->vco_cntrl >> 4) & 0x3 in setup_info->vclk_divider
> > you wouldn't have to use __ffs() in rcar_mipi_dsi_startup(). You could
> > also drop the - 1 there, which would allow dropping one of the
> > switch(dsi->info->model). You can store the real divider value in
> > setup_info separately for rcar_mipi_dsi_pll_calc_r8a779a0(), or pass it
> > to the function.
> > 
> >> +		rcar_mipi_dsi_pll_calc_r8a779a0(dsi, clk, fout_target, setup_info);
> >> +		break;
> >> +
> >> +	case RCAR_DSI_R8A779G0:
> >> +		setup_info->vclk_divider = 1 << (((clkset->vco_cntrl >> 3) & 0x7) + 1);
> >> +		rcar_mipi_dsi_pll_calc_r8a779g0(dsi, clk, fout_target, setup_info);
> >> +		break;
> >> +
> >> +	default:
> >> +		return;
> >> +	}
> >>   
> >>   	/* Find hsfreqrange */
> >> -	hsfreq = fout_target * 2;
> >> +	setup_info->hsfreq = setup_info->fout * 2;
> >>   	for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++) {
> >> -		if (hsfreqrange_table[i][0] >= hsfreq) {
> >> +		if (hsfreqrange_table[i][0] >= setup_info->hsfreq) {
> >>   			setup_info->hsfreqrange = hsfreqrange_table[i][1];
> >>   			break;
> >>   		}
> >>   	}
> >>   
> >> -	/*
> >> -	 * Calculate n and m for PLL clock
> >> -	 * Following the HW manual the ranges of n and m are
> >> -	 * n = [3-8] and m = [64-625]
> >> -	 */
> > 
> > I'd keep the comment in rcar_mipi_dsi_pll_calc_r8a779a0(), and add a
> > similar comment in rcar_mipi_dsi_pll_calc_r8a779g0().
> 
> Well, I dropped the comment as it's just pointing the obvious: we are 
> calculating PLL config, and the n and m ranges are easily visible in the 
> code below. I can add them if you think they are useful.

Up to you.

> >> -	fin = clk_get_rate(clk);
> >> -	divider = 1 << setup_info->div;
> >> -	for (n = 3; n < 9; n++) {
> >> -		unsigned long fpfd;
> >> -		unsigned int m;
> >> -
> >> -		fpfd = fin / n;
> >> -
> >> -		for (m = 64; m < 626; m++) {
> >> -			fout = fpfd * m / divider;
> >> -			err = abs((long)(fout - fout_target) * 10000 /
> >> -				  (long)fout_target);
> >> -			if (err < best_err) {
> >> -				setup_info->m = m - 2;
> >> -				setup_info->n = n - 1;
> >> -				setup_info->fout = fout;
> >> -				best_err = err;
> >> -				if (err == 0)
> >> -					goto done;
> >> -			}
> >> -		}
> >> -	}
> >> +	err = abs((long)(setup_info->fout - fout_target) * 10000 / (long)fout_target);
> >>   
> >> -done:
> >>   	dev_dbg(dsi->dev,
> >> -		"%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/DIV %u/%u/%u\n",
> >> -		clk, fin, setup_info->fout, fout_target, best_err / 100,
> >> -		best_err % 100, setup_info->m, setup_info->n, setup_info->div);
> >> +		"Fout = %u * %lu / (2 * %u * %u) = %lu (target %lu Hz, error %d.%02u%%)\n",
> > 
> > Is the "2 *" valid on V3U too ?
> 
> Good catch. It is not.
> 
> >> +		setup_info->m, clk_get_rate(clk), setup_info->n, setup_info->vclk_divider,
> > 
> > If you keep the clk_get_rate() call in this function you wouldn't have
> > to call it again here.
> 
> Yep.
> 
> >> +		setup_info->fout, fout_target,
> >> +		err / 100, err % 100);
> >> +
> >>   	dev_dbg(dsi->dev,
> >>   		"vco_cntrl = 0x%x\tprop_cntrl = 0x%x\thsfreqrange = 0x%x\n",
> >> -		setup_info->vco_cntrl, setup_info->prop_cntrl,
> >> +		clkset->vco_cntrl, clkset->prop_cntrl,
> >>   		setup_info->hsfreqrange);
> >>   }
> >>   
> >> @@ -324,7 +545,7 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
> >>   {
> >>   	struct dsi_setup_info setup_info = {};
> >>   	unsigned int timeout;
> >> -	int ret, i;
> >> +	int ret;
> >>   	int dsi_format;
> >>   	u32 phy_setup;
> >>   	u32 clockset2, clockset3;
> >> @@ -360,10 +581,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
> >>   	phy_setup |= PHYSETUP_HSFREQRANGE(setup_info.hsfreqrange);
> >>   	rcar_mipi_dsi_write(dsi, PHYSETUP, phy_setup);
> >>   
> >> -	for (i = 0; i < ARRAY_SIZE(phtw); i++) {
> >> -		ret = rcar_mipi_dsi_phtw_test(dsi, phtw[i]);
> >> +	switch (dsi->info->model) {
> >> +	case RCAR_DSI_R8A779A0:
> >> +		ret = rcar_mipi_dsi_init_phtw_v3u(dsi);
> >> +		if (ret < 0)
> >> +			return ret;
> >> +		break;
> >> +
> >> +	case RCAR_DSI_R8A779G0:
> >> +		ret = rcar_mipi_dsi_init_phtw_v4h(dsi, &setup_info);
> >>   		if (ret < 0)
> >>   			return ret;
> >> +		break;
> >> +
> >> +	default:
> >> +		return -ENODEV;
> > 
> > This can't happen. Same below.
> 
> I thought the compiler would warn about it, but at least mine doesn't, 
> so I'll drop the default cases.

smatch or other static checkers may complain. You can add a default case
to one of the labels to avoid that.

> >>   	}
> >>   
> >>   	/* PLL Clock Setting */
> >> @@ -371,12 +603,13 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
> >>   	rcar_mipi_dsi_set(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
> >>   	rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
> >>   
> >> -	clockset2 = CLOCKSET2_M(setup_info.m) | CLOCKSET2_N(setup_info.n)
> >> -		  | CLOCKSET2_VCO_CNTRL(setup_info.vco_cntrl);
> >> -	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.prop_cntrl)
> >> -		  | CLOCKSET3_INT_CNTRL(0)
> >> -		  | CLOCKSET3_CPBIAS_CNTRL(0x10)
> >> -		  | CLOCKSET3_GMP_CNTRL(1);
> >> +	clockset2 = CLOCKSET2_M(setup_info.m - dsi->info->clockset2_m_offset)
> >> +		  | CLOCKSET2_N(setup_info.n - dsi->info->clockset2_n_offset)
> >> +		  | CLOCKSET2_VCO_CNTRL(setup_info.clkset->vco_cntrl);
> >> +	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.clkset->prop_cntrl)
> >> +		  | CLOCKSET3_INT_CNTRL(setup_info.clkset->int_cntrl)
> >> +		  | CLOCKSET3_CPBIAS_CNTRL(setup_info.clkset->cpbias_cntrl)
> >> +		  | CLOCKSET3_GMP_CNTRL(setup_info.clkset->gmp_cntrl);
> >>   	rcar_mipi_dsi_write(dsi, CLOCKSET2, clockset2);
> >>   	rcar_mipi_dsi_write(dsi, CLOCKSET3, clockset3);
> >>   
> >> @@ -407,10 +640,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
> >>   		return -ETIMEDOUT;
> >>   	}
> >>   
> >> -	for (i = 0; i < ARRAY_SIZE(phtw2); i++) {
> >> -		ret = rcar_mipi_dsi_phtw_test(dsi, phtw2[i]);
> >> +	switch (dsi->info->model) {
> >> +	case RCAR_DSI_R8A779A0:
> >> +		ret = rcar_mipi_dsi_post_init_phtw_v3u(dsi);
> >>   		if (ret < 0)
> >>   			return ret;
> >> +		break;
> >> +
> >> +	case RCAR_DSI_R8A779G0:
> >> +		ret = rcar_mipi_dsi_post_init_phtw_v4h(dsi, &setup_info);
> >> +		if (ret < 0)
> >> +			return ret;
> >> +		break;
> >> +
> >> +	default:
> >> +		return -ENODEV;
> >>   	}
> >>   
> >>   	/* Enable DOT clock */
> >> @@ -427,8 +671,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
> >>   		dev_warn(dsi->dev, "unsupported format");
> >>   		return -EINVAL;
> >>   	}
> >> -	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_DIV(setup_info.div)
> >> -		|  VCLKSET_LANE(dsi->lanes - 1);
> >> +
> >> +	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_LANE(dsi->lanes - 1);
> >> +
> >> +	switch (dsi->info->model) {
> >> +	case RCAR_DSI_R8A779A0:
> >> +		vclkset |= VCLKSET_DIV_R8A779A0(__ffs(setup_info.vclk_divider));
> >> +		break;
> >> +
> >> +	case RCAR_DSI_R8A779G0:
> >> +		vclkset |= VCLKSET_DIV_R8A779G0(__ffs(setup_info.vclk_divider) - 1);
> >> +		break;
> >> +
> >> +	default:
> >> +		return -ENODEV;
> >> +	}
> >>   
> >>   	rcar_mipi_dsi_write(dsi, VCLKSET, vclkset);
> >>   
> >> @@ -841,8 +1098,25 @@ static int rcar_mipi_dsi_remove(struct platform_device *pdev)
> >>   	return 0;
> >>   }
> >>   
> >> +static const struct rcar_mipi_dsi_device_info r8a779a0_data = {
> >> +	.model = RCAR_DSI_R8A779A0,
> >> +	.clk_cfg = dsi_clk_cfg_r8a779a0,
> >> +	.clockset2_m_offset = 2,
> >> +	.clockset2_n_offset = 1,
> >> +
> > 
> > Extra blank line.
> 
> Yep.
> 
> >> +};
> >> +
> >> +static const struct rcar_mipi_dsi_device_info r8a779g0_data = {
> >> +	.model = RCAR_DSI_R8A779G0,
> >> +	.clk_cfg = dsi_clk_cfg_r8a779g0,
> >> +	.clockset2_m_offset = 0,
> >> +	.clockset2_n_offset = 1,
> > 
> > You could possibly drop clockset2_n_offset as it's identical for the two
> > variants, and there's no indication it would be different in another
> > version of the IP core.
> 
> Yep, I think that's fine.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 7/7] drm: rcar-du: dsi: Add r8a779g0 support
  2022-11-29  1:49   ` Laurent Pinchart
  2022-11-29 11:30     ` Tomi Valkeinen
@ 2022-11-29 12:59     ` Tomi Valkeinen
  1 sibling, 0 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-29 12:59 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Kieran Bingham, Rob Herring, Krzysztof Kozlowski,
	Geert Uytterhoeven, Magnus Damm, dri-devel, linux-renesas-soc,
	devicetree, linux-kernel, Andrzej Hajda, Neil Armstrong,
	Robert Foss, Jonas Karlman, Jernej Skrabec

On 29/11/2022 03:49, Laurent Pinchart wrote:

>> @@ -198,70 +436,53 @@ static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
>>   	 */
>>   	fout_target = target * mipi_dsi_pixel_format_to_bpp(dsi->format)
>>   		    / (2 * dsi->lanes);
>> -	if (fout_target < 40000000 || fout_target > 1250000000)
>> +	if (fout_target < MHZ(40) || fout_target > MHZ(1250))
>>   		return;
>>   
>>   	/* Find vco_cntrl */
>> -	for (vco_cntrl = vco_cntrl_table; vco_cntrl->min_freq != 0; vco_cntrl++) {
>> -		if (fout_target > vco_cntrl->min_freq &&
>> -		    fout_target <= vco_cntrl->max_freq) {
>> -			setup_info->vco_cntrl = vco_cntrl->value;
>> -			if (fout_target >= 1150000000)
>> -				setup_info->prop_cntrl = 0x0c;
>> -			else
>> -				setup_info->prop_cntrl = 0x0b;
>> +	for (clkset = dsi->info->clk_cfg; clkset->min_freq != 0; clkset++) {
>> +		if (fout_target > clkset->min_freq &&
>> +		    fout_target <= clkset->max_freq) {
>> +			setup_info->clkset = clkset;
>>   			break;
>>   		}
>>   	}
>>   
>> -	/* Add divider */
>> -	setup_info->div = (setup_info->vco_cntrl & 0x30) >> 4;
>> +	switch (dsi->info->model) {
>> +	case RCAR_DSI_R8A779A0:
>> +		setup_info->vclk_divider = 1 << ((clkset->vco_cntrl >> 4) & 0x3);
> 
> If you stored (clkset->vco_cntrl >> 4) & 0x3 in setup_info->vclk_divider
> you wouldn't have to use __ffs() in rcar_mipi_dsi_startup(). You could
> also drop the - 1 there, which would allow dropping one of the
> switch(dsi->info->model). You can store the real divider value in
> setup_info separately for rcar_mipi_dsi_pll_calc_r8a779a0(), or pass it
> to the function.

That's true. The reason I chose this approach was to keep dsi_setup_info 
"neutral", containing only the logical values, and the register specific 
tinkering is done only where the register is written. Mixing the logical 
and the register values in the old dsi_setup_info was confusing, and 
implementing your suggestion would again go that direction. But as you 
noticed, this is uglified a bit by the need to get the divider from the 
vco_cntrl.

We could store the logical divider in the dsi_clk_config table, though, 
which would remove the need for the above code.

  Tomi


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

* [PATCH v3 7/7] drm: rcar-du: dsi: Add r8A779g0 support
  2022-11-23  6:59 ` [PATCH v2 7/7] drm: rcar-du: dsi: " Tomi Valkeinen
  2022-11-29  1:49   ` Laurent Pinchart
@ 2022-11-29 13:41   ` Tomi Valkeinen
  2022-11-29 17:44     ` Laurent Pinchart
  2022-11-30  8:08     ` [PATCH v4 " Tomi Valkeinen
  1 sibling, 2 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-29 13:41 UTC (permalink / raw)
  To: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
	Jernej Skrabec, Tomi Valkeinen

Add DSI support for r8a779g0. The main differences to r8a779a0 are in
the PLL and PHTW setups.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
---
Changes to v2:
- Use MHZ() in the tables, with floating point values as inputs
- Use V3U/V4H names instead of R8A779A0/R8A779G0
- PLL diffs between V3U and V4H are now described in struct
  rcar_mipi_dsi_device_info, and we have a single function to calculate
  the pll settings.
- Refactor fin_rate to outside the pll calc functions.
- Fixed the PLL config debug print.
- Dropped clockset2_n_offset, which is always 1

 drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c      | 499 ++++++++++++++-----
 drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h |   6 +-
 2 files changed, 377 insertions(+), 128 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
index a7f2b7f66a17..3b812ec034fe 100644
--- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
+++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
@@ -9,6 +9,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -28,6 +29,31 @@
 #include "rcar_mipi_dsi.h"
 #include "rcar_mipi_dsi_regs.h"
 
+#define MHZ(v) ((u32)((v) * 1000000U))
+
+enum rcar_mipi_dsi_hw_model {
+	RCAR_DSI_V3U,
+	RCAR_DSI_V4H,
+};
+
+struct rcar_mipi_dsi_device_info {
+	enum rcar_mipi_dsi_hw_model model;
+
+	const struct dsi_clk_config *clk_cfg;
+
+	u8 clockset2_m_offset;
+
+	u8 n_min;
+	u8 n_max;
+	u8 n_mul;
+	unsigned long fpfd_min;
+	unsigned long fpfd_max;
+	u16 m_min;
+	u16 m_max;
+	unsigned long fout_min;
+	unsigned long fout_max;
+};
+
 struct rcar_mipi_dsi {
 	struct device *dev;
 	const struct rcar_mipi_dsi_device_info *info;
@@ -50,6 +76,17 @@ struct rcar_mipi_dsi {
 	unsigned int lanes;
 };
 
+struct dsi_setup_info {
+	unsigned long hsfreq;
+	u16 hsfreqrange;
+
+	unsigned long fout;
+	u16 m;
+	u16 n;
+	u16 vclk_divider;
+	const struct dsi_clk_config *clkset;
+};
+
 static inline struct rcar_mipi_dsi *
 bridge_to_rcar_mipi_dsi(struct drm_bridge *bridge)
 {
@@ -62,65 +99,78 @@ host_to_rcar_mipi_dsi(struct mipi_dsi_host *host)
 	return container_of(host, struct rcar_mipi_dsi, host);
 }
 
-static const u32 phtw[] = {
-	0x01020114, 0x01600115, /* General testing */
-	0x01030116, 0x0102011d, /* General testing */
-	0x011101a4, 0x018601a4, /* 1Gbps testing */
-	0x014201a0, 0x010001a3, /* 1Gbps testing */
-	0x0101011f,		/* 1Gbps testing */
-};
-
-static const u32 phtw2[] = {
-	0x010c0130, 0x010c0140, /* General testing */
-	0x010c0150, 0x010c0180, /* General testing */
-	0x010c0190,
-	0x010a0160, 0x010a0170,
-	0x01800164, 0x01800174,	/* 1Gbps testing */
-};
-
 static const u32 hsfreqrange_table[][2] = {
-	{ 80000000U,   0x00 }, { 90000000U,   0x10 }, { 100000000U,  0x20 },
-	{ 110000000U,  0x30 }, { 120000000U,  0x01 }, { 130000000U,  0x11 },
-	{ 140000000U,  0x21 }, { 150000000U,  0x31 }, { 160000000U,  0x02 },
-	{ 170000000U,  0x12 }, { 180000000U,  0x22 }, { 190000000U,  0x32 },
-	{ 205000000U,  0x03 }, { 220000000U,  0x13 }, { 235000000U,  0x23 },
-	{ 250000000U,  0x33 }, { 275000000U,  0x04 }, { 300000000U,  0x14 },
-	{ 325000000U,  0x25 }, { 350000000U,  0x35 }, { 400000000U,  0x05 },
-	{ 450000000U,  0x16 }, { 500000000U,  0x26 }, { 550000000U,  0x37 },
-	{ 600000000U,  0x07 }, { 650000000U,  0x18 }, { 700000000U,  0x28 },
-	{ 750000000U,  0x39 }, { 800000000U,  0x09 }, { 850000000U,  0x19 },
-	{ 900000000U,  0x29 }, { 950000000U,  0x3a }, { 1000000000U, 0x0a },
-	{ 1050000000U, 0x1a }, { 1100000000U, 0x2a }, { 1150000000U, 0x3b },
-	{ 1200000000U, 0x0b }, { 1250000000U, 0x1b }, { 1300000000U, 0x2b },
-	{ 1350000000U, 0x3c }, { 1400000000U, 0x0c }, { 1450000000U, 0x1c },
-	{ 1500000000U, 0x2c }, { 1550000000U, 0x3d }, { 1600000000U, 0x0d },
-	{ 1650000000U, 0x1d }, { 1700000000U, 0x2e }, { 1750000000U, 0x3e },
-	{ 1800000000U, 0x0e }, { 1850000000U, 0x1e }, { 1900000000U, 0x2f },
-	{ 1950000000U, 0x3f }, { 2000000000U, 0x0f }, { 2050000000U, 0x40 },
-	{ 2100000000U, 0x41 }, { 2150000000U, 0x42 }, { 2200000000U, 0x43 },
-	{ 2250000000U, 0x44 }, { 2300000000U, 0x45 }, { 2350000000U, 0x46 },
-	{ 2400000000U, 0x47 }, { 2450000000U, 0x48 }, { 2500000000U, 0x49 },
+	{   MHZ(80), 0x00 }, {   MHZ(90), 0x10 }, {  MHZ(100), 0x20 },
+	{  MHZ(110), 0x30 }, {  MHZ(120), 0x01 }, {  MHZ(130), 0x11 },
+	{  MHZ(140), 0x21 }, {  MHZ(150), 0x31 }, {  MHZ(160), 0x02 },
+	{  MHZ(170), 0x12 }, {  MHZ(180), 0x22 }, {  MHZ(190), 0x32 },
+	{  MHZ(205), 0x03 }, {  MHZ(220), 0x13 }, {  MHZ(235), 0x23 },
+	{  MHZ(250), 0x33 }, {  MHZ(275), 0x04 }, {  MHZ(300), 0x14 },
+	{  MHZ(325), 0x25 }, {  MHZ(350), 0x35 }, {  MHZ(400), 0x05 },
+	{  MHZ(450), 0x16 }, {  MHZ(500), 0x26 }, {  MHZ(550), 0x37 },
+	{  MHZ(600), 0x07 }, {  MHZ(650), 0x18 }, {  MHZ(700), 0x28 },
+	{  MHZ(750), 0x39 }, {  MHZ(800), 0x09 }, {  MHZ(850), 0x19 },
+	{  MHZ(900), 0x29 }, {  MHZ(950), 0x3a }, { MHZ(1000), 0x0a },
+	{ MHZ(1050), 0x1a }, { MHZ(1100), 0x2a }, { MHZ(1150), 0x3b },
+	{ MHZ(1200), 0x0b }, { MHZ(1250), 0x1b }, { MHZ(1300), 0x2b },
+	{ MHZ(1350), 0x3c }, { MHZ(1400), 0x0c }, { MHZ(1450), 0x1c },
+	{ MHZ(1500), 0x2c }, { MHZ(1550), 0x3d }, { MHZ(1600), 0x0d },
+	{ MHZ(1650), 0x1d }, { MHZ(1700), 0x2e }, { MHZ(1750), 0x3e },
+	{ MHZ(1800), 0x0e }, { MHZ(1850), 0x1e }, { MHZ(1900), 0x2f },
+	{ MHZ(1950), 0x3f }, { MHZ(2000), 0x0f }, { MHZ(2050), 0x40 },
+	{ MHZ(2100), 0x41 }, { MHZ(2150), 0x42 }, { MHZ(2200), 0x43 },
+	{ MHZ(2250), 0x44 }, { MHZ(2300), 0x45 }, { MHZ(2350), 0x46 },
+	{ MHZ(2400), 0x47 }, { MHZ(2450), 0x48 }, { MHZ(2500), 0x49 },
 	{ /* sentinel */ },
 };
 
-struct vco_cntrl_value {
+struct dsi_clk_config {
 	u32 min_freq;
 	u32 max_freq;
-	u16 value;
+	u8 vco_cntrl;
+	u8 cpbias_cntrl;
+	u8 gmp_cntrl;
+	u8 int_cntrl;
+	u8 prop_cntrl;
 };
 
-static const struct vco_cntrl_value vco_cntrl_table[] = {
-	{ .min_freq = 40000000U,   .max_freq = 55000000U,   .value = 0x3f },
-	{ .min_freq = 52500000U,   .max_freq = 80000000U,   .value = 0x39 },
-	{ .min_freq = 80000000U,   .max_freq = 110000000U,  .value = 0x2f },
-	{ .min_freq = 105000000U,  .max_freq = 160000000U,  .value = 0x29 },
-	{ .min_freq = 160000000U,  .max_freq = 220000000U,  .value = 0x1f },
-	{ .min_freq = 210000000U,  .max_freq = 320000000U,  .value = 0x19 },
-	{ .min_freq = 320000000U,  .max_freq = 440000000U,  .value = 0x0f },
-	{ .min_freq = 420000000U,  .max_freq = 660000000U,  .value = 0x09 },
-	{ .min_freq = 630000000U,  .max_freq = 1149000000U, .value = 0x03 },
-	{ .min_freq = 1100000000U, .max_freq = 1152000000U, .value = 0x01 },
-	{ .min_freq = 1150000000U, .max_freq = 1250000000U, .value = 0x01 },
+static const struct dsi_clk_config dsi_clk_cfg_v3u[] = {
+	{   MHZ(40),    MHZ(55), 0x3f, 0x10, 0x01, 0x00, 0x0b },
+	{   MHZ(52.5),  MHZ(80), 0x39, 0x10, 0x01, 0x00, 0x0b },
+	{   MHZ(80),   MHZ(110), 0x2f, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(105),   MHZ(160), 0x29, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(160),   MHZ(220), 0x1f, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(210),   MHZ(320), 0x19, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(320),   MHZ(440), 0x0f, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(420),   MHZ(660), 0x09, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(630),  MHZ(1149), 0x03, 0x10, 0x01, 0x00, 0x0b },
+	{ MHZ(1100),  MHZ(1152), 0x01, 0x10, 0x01, 0x00, 0x0b },
+	{ MHZ(1150),  MHZ(1250), 0x01, 0x10, 0x01, 0x00, 0x0c },
+	{ /* sentinel */ },
+};
+
+static const struct dsi_clk_config dsi_clk_cfg_v4h[] = {
+	{   MHZ(40),    MHZ(45.31),  0x2b, 0x00, 0x00, 0x08, 0x0a },
+	{   MHZ(45.31), MHZ(54.66),  0x28, 0x00, 0x00, 0x08, 0x0a },
+	{   MHZ(54.66), MHZ(62.5),   0x28, 0x00, 0x00, 0x08, 0x0a },
+	{   MHZ(62.5),  MHZ(75),     0x27, 0x00, 0x00, 0x08, 0x0a },
+	{   MHZ(75),    MHZ(90.63),  0x23, 0x00, 0x00, 0x08, 0x0a },
+	{   MHZ(90.63), MHZ(109.37), 0x20, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(109.37), MHZ(125),    0x20, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(125),    MHZ(150),    0x1f, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(150),    MHZ(181.25), 0x1b, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(181.25), MHZ(218.75), 0x18, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(218.75), MHZ(250),    0x18, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(250),    MHZ(300),    0x17, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(300),    MHZ(362.5),  0x13, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(362.5),  MHZ(455.48), 0x10, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(455.48), MHZ(500),    0x10, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(500),    MHZ(600),    0x0f, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(600),    MHZ(725),    0x0b, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(725),    MHZ(875),    0x08, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(875),   MHZ(1000),    0x08, 0x00, 0x00, 0x08, 0x0a },
+	{ MHZ(1000),   MHZ(1200),    0x07, 0x00, 0x00, 0x08, 0x0a },
+	{ MHZ(1200),   MHZ(1250),    0x03, 0x00, 0x00, 0x08, 0x0a },
 	{ /* sentinel */ },
 };
 
@@ -144,7 +194,7 @@ static void rcar_mipi_dsi_set(struct rcar_mipi_dsi *dsi, u32 reg, u32 set)
 	rcar_mipi_dsi_write(dsi, reg, rcar_mipi_dsi_read(dsi, reg) | set);
 }
 
-static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
+static int rcar_mipi_dsi_write_phtw(struct rcar_mipi_dsi *dsi, u32 phtw)
 {
 	u32 status;
 	int ret;
@@ -163,32 +213,181 @@ static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
 	return ret;
 }
 
+static int rcar_mipi_dsi_write_phtw_arr(struct rcar_mipi_dsi *dsi,
+					const u32 *phtw, unsigned int size)
+{
+	for (unsigned int i = 0; i < size; i++) {
+		int ret = rcar_mipi_dsi_write_phtw(dsi, phtw[i]);
+
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+#define WRITE_PHTW(...)                                               \
+	({                                                            \
+		static const u32 phtw[] = { __VA_ARGS__ };            \
+		int ret;                                              \
+		ret = rcar_mipi_dsi_write_phtw_arr(dsi, phtw,         \
+						   ARRAY_SIZE(phtw)); \
+		ret;                                                  \
+	})
+
+static int rcar_mipi_dsi_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
+{
+	return WRITE_PHTW(0x01020114, 0x01600115, 0x01030116, 0x0102011d,
+			  0x011101a4, 0x018601a4, 0x014201a0, 0x010001a3,
+			  0x0101011f);
+}
+
+static int rcar_mipi_dsi_post_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
+{
+	return WRITE_PHTW(0x010c0130, 0x010c0140, 0x010c0150, 0x010c0180,
+			  0x010c0190, 0x010a0160, 0x010a0170, 0x01800164,
+			  0x01800174);
+}
+
+static int rcar_mipi_dsi_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
+				       const struct dsi_setup_info *setup_info)
+{
+	int ret;
+
+	if (setup_info->hsfreq < MHZ(450)) {
+		ret = WRITE_PHTW(0x01010100, 0x011b01ac);
+		if (ret)
+			return ret;
+	}
+
+	ret = WRITE_PHTW(0x01010100, 0x01030173, 0x01000174, 0x01500175,
+			 0x01030176, 0x01040166, 0x010201ad);
+	if (ret)
+		return ret;
+
+	if (setup_info->hsfreq <= MHZ(1000))
+		ret = WRITE_PHTW(0x01020100, 0x01910170, 0x01020171,
+				 0x01110172);
+	else if (setup_info->hsfreq <= MHZ(1500))
+		ret = WRITE_PHTW(0x01020100, 0x01980170, 0x01030171,
+				 0x01100172);
+	else if (setup_info->hsfreq <= MHZ(2500))
+		ret = WRITE_PHTW(0x01020100, 0x0144016b, 0x01000172);
+	else
+		return -EINVAL;
+
+	if (ret)
+		return ret;
+
+	if (dsi->lanes <= 1) {
+		ret = WRITE_PHTW(0x01070100, 0x010e010b);
+		if (ret)
+			return ret;
+	}
+
+	if (dsi->lanes <= 2) {
+		ret = WRITE_PHTW(0x01090100, 0x010e010b);
+		if (ret)
+			return ret;
+	}
+
+	if (dsi->lanes <= 3) {
+		ret = WRITE_PHTW(0x010b0100, 0x010e010b);
+		if (ret)
+			return ret;
+	}
+
+	if (setup_info->hsfreq <= MHZ(1500)) {
+		ret = WRITE_PHTW(0x01010100, 0x01c0016e);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int
+rcar_mipi_dsi_post_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
+				 const struct dsi_setup_info *setup_info)
+{
+	u32 status;
+	int ret;
+
+	if (setup_info->hsfreq <= MHZ(1500)) {
+		WRITE_PHTW(0x01020100, 0x00000180);
+
+		ret = read_poll_timeout(rcar_mipi_dsi_read, status,
+					status & PHTR_TEST, 2000, 10000, false,
+					dsi, PHTR);
+		if (ret < 0) {
+			dev_err(dsi->dev, "failed to test PHTR\n");
+			return ret;
+		}
+
+		WRITE_PHTW(0x01010100, 0x0100016e);
+	}
+
+	return 0;
+}
+
 /* -----------------------------------------------------------------------------
  * Hardware Setup
  */
 
-struct dsi_setup_info {
-	unsigned long fout;
-	u16 vco_cntrl;
-	u16 prop_cntrl;
-	u16 hsfreqrange;
-	u16 div;
-	unsigned int m;
-	unsigned int n;
-};
+static void rcar_mipi_dsi_pll_calc(struct rcar_mipi_dsi *dsi,
+				   unsigned long fin_rate,
+				   unsigned long fout_target,
+				   struct dsi_setup_info *setup_info)
+{
+	unsigned int best_err = -1;
+	const struct rcar_mipi_dsi_device_info *info = dsi->info;
+
+	for (unsigned int n = info->n_min; n <= info->n_max; n++) {
+		unsigned long fpfd;
+
+		fpfd = fin_rate / n;
+
+		if (fpfd < info->fpfd_min || fpfd > info->fpfd_max)
+			continue;
+
+		for (unsigned int m = info->m_min; m <= info->m_max; m++) {
+			unsigned int err;
+			u64 fout;
+
+			fout = div64_u64((u64)fpfd * m, dsi->info->n_mul);
+
+			if (fout < info->fout_min || fout > info->fout_max)
+				continue;
+
+			fout = div64_u64(fout, setup_info->vclk_divider);
+
+			if (fout < setup_info->clkset->min_freq ||
+			    fout > setup_info->clkset->max_freq)
+				continue;
+
+			err = abs((long)(fout - fout_target) * 10000 /
+				  (long)fout_target);
+			if (err < best_err) {
+				setup_info->m = m;
+				setup_info->n = n;
+				setup_info->fout = (unsigned long)fout;
+				best_err = err;
+
+				if (err == 0)
+					return;
+			}
+		}
+	}
+}
 
 static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
 					  struct clk *clk, unsigned long target,
 					  struct dsi_setup_info *setup_info)
 {
 
-	const struct vco_cntrl_value *vco_cntrl;
+	const struct dsi_clk_config *clk_cfg;
 	unsigned long fout_target;
-	unsigned long fin, fout;
-	unsigned long hsfreq;
-	unsigned int best_err = -1;
-	unsigned int divider;
-	unsigned int n;
+	unsigned long fin_rate;
 	unsigned int i;
 	unsigned int err;
 
@@ -198,70 +397,55 @@ static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
 	 */
 	fout_target = target * mipi_dsi_pixel_format_to_bpp(dsi->format)
 		    / (2 * dsi->lanes);
-	if (fout_target < 40000000 || fout_target > 1250000000)
+	if (fout_target < MHZ(40) || fout_target > MHZ(1250))
 		return;
 
-	/* Find vco_cntrl */
-	for (vco_cntrl = vco_cntrl_table; vco_cntrl->min_freq != 0; vco_cntrl++) {
-		if (fout_target > vco_cntrl->min_freq &&
-		    fout_target <= vco_cntrl->max_freq) {
-			setup_info->vco_cntrl = vco_cntrl->value;
-			if (fout_target >= 1150000000)
-				setup_info->prop_cntrl = 0x0c;
-			else
-				setup_info->prop_cntrl = 0x0b;
+	/* Find PLL settings */
+	for (clk_cfg = dsi->info->clk_cfg; clk_cfg->min_freq != 0; clk_cfg++) {
+		if (fout_target > clk_cfg->min_freq &&
+		    fout_target <= clk_cfg->max_freq) {
+			setup_info->clkset = clk_cfg;
 			break;
 		}
 	}
 
-	/* Add divider */
-	setup_info->div = (setup_info->vco_cntrl & 0x30) >> 4;
+	fin_rate = clk_get_rate(clk);
+
+	switch (dsi->info->model) {
+	case RCAR_DSI_V3U:
+		setup_info->vclk_divider = 1 << ((clk_cfg->vco_cntrl >> 4) & 0x3);
+		break;
+
+	case RCAR_DSI_V4H:
+		setup_info->vclk_divider = 1 << (((clk_cfg->vco_cntrl >> 3) & 0x7) + 1);
+		break;
+
+	default:
+		return;
+	}
+
+	rcar_mipi_dsi_pll_calc(dsi, fin_rate, fout_target, setup_info);
 
 	/* Find hsfreqrange */
-	hsfreq = fout_target * 2;
+	setup_info->hsfreq = setup_info->fout * 2;
 	for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++) {
-		if (hsfreqrange_table[i][0] >= hsfreq) {
+		if (hsfreqrange_table[i][0] >= setup_info->hsfreq) {
 			setup_info->hsfreqrange = hsfreqrange_table[i][1];
 			break;
 		}
 	}
 
-	/*
-	 * Calculate n and m for PLL clock
-	 * Following the HW manual the ranges of n and m are
-	 * n = [3-8] and m = [64-625]
-	 */
-	fin = clk_get_rate(clk);
-	divider = 1 << setup_info->div;
-	for (n = 3; n < 9; n++) {
-		unsigned long fpfd;
-		unsigned int m;
-
-		fpfd = fin / n;
-
-		for (m = 64; m < 626; m++) {
-			fout = fpfd * m / divider;
-			err = abs((long)(fout - fout_target) * 10000 /
-				  (long)fout_target);
-			if (err < best_err) {
-				setup_info->m = m - 2;
-				setup_info->n = n - 1;
-				setup_info->fout = fout;
-				best_err = err;
-				if (err == 0)
-					goto done;
-			}
-		}
-	}
+	err = abs((long)(setup_info->fout - fout_target) * 10000 / (long)fout_target);
 
-done:
 	dev_dbg(dsi->dev,
-		"%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/DIV %u/%u/%u\n",
-		clk, fin, setup_info->fout, fout_target, best_err / 100,
-		best_err % 100, setup_info->m, setup_info->n, setup_info->div);
+		"Fout = %u * %lu / (%u * %u * %u) = %lu (target %lu Hz, error %d.%02u%%)\n",
+		setup_info->m, fin_rate, dsi->info->n_mul, setup_info->n,
+		setup_info->vclk_divider, setup_info->fout, fout_target,
+		err / 100, err % 100);
+
 	dev_dbg(dsi->dev,
 		"vco_cntrl = 0x%x\tprop_cntrl = 0x%x\thsfreqrange = 0x%x\n",
-		setup_info->vco_cntrl, setup_info->prop_cntrl,
+		clk_cfg->vco_cntrl, clk_cfg->prop_cntrl,
 		setup_info->hsfreqrange);
 }
 
@@ -324,7 +508,7 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 {
 	struct dsi_setup_info setup_info = {};
 	unsigned int timeout;
-	int ret, i;
+	int ret;
 	int dsi_format;
 	u32 phy_setup;
 	u32 clockset2, clockset3;
@@ -360,10 +544,18 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 	phy_setup |= PHYSETUP_HSFREQRANGE(setup_info.hsfreqrange);
 	rcar_mipi_dsi_write(dsi, PHYSETUP, phy_setup);
 
-	for (i = 0; i < ARRAY_SIZE(phtw); i++) {
-		ret = rcar_mipi_dsi_phtw_test(dsi, phtw[i]);
+	switch (dsi->info->model) {
+	case RCAR_DSI_V3U:
+		ret = rcar_mipi_dsi_init_phtw_v3u(dsi);
+		if (ret < 0)
+			return ret;
+		break;
+
+	case RCAR_DSI_V4H:
+		ret = rcar_mipi_dsi_init_phtw_v4h(dsi, &setup_info);
 		if (ret < 0)
 			return ret;
+		break;
 	}
 
 	/* PLL Clock Setting */
@@ -371,12 +563,13 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 	rcar_mipi_dsi_set(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
 	rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
 
-	clockset2 = CLOCKSET2_M(setup_info.m) | CLOCKSET2_N(setup_info.n)
-		  | CLOCKSET2_VCO_CNTRL(setup_info.vco_cntrl);
-	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.prop_cntrl)
-		  | CLOCKSET3_INT_CNTRL(0)
-		  | CLOCKSET3_CPBIAS_CNTRL(0x10)
-		  | CLOCKSET3_GMP_CNTRL(1);
+	clockset2 = CLOCKSET2_M(setup_info.m - dsi->info->clockset2_m_offset)
+		  | CLOCKSET2_N(setup_info.n - 1)
+		  | CLOCKSET2_VCO_CNTRL(setup_info.clkset->vco_cntrl);
+	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.clkset->prop_cntrl)
+		  | CLOCKSET3_INT_CNTRL(setup_info.clkset->int_cntrl)
+		  | CLOCKSET3_CPBIAS_CNTRL(setup_info.clkset->cpbias_cntrl)
+		  | CLOCKSET3_GMP_CNTRL(setup_info.clkset->gmp_cntrl);
 	rcar_mipi_dsi_write(dsi, CLOCKSET2, clockset2);
 	rcar_mipi_dsi_write(dsi, CLOCKSET3, clockset3);
 
@@ -407,10 +600,18 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 		return -ETIMEDOUT;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(phtw2); i++) {
-		ret = rcar_mipi_dsi_phtw_test(dsi, phtw2[i]);
+	switch (dsi->info->model) {
+	case RCAR_DSI_V3U:
+		ret = rcar_mipi_dsi_post_init_phtw_v3u(dsi);
 		if (ret < 0)
 			return ret;
+		break;
+
+	case RCAR_DSI_V4H:
+		ret = rcar_mipi_dsi_post_init_phtw_v4h(dsi, &setup_info);
+		if (ret < 0)
+			return ret;
+		break;
 	}
 
 	/* Enable DOT clock */
@@ -427,8 +628,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 		dev_warn(dsi->dev, "unsupported format");
 		return -EINVAL;
 	}
-	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_DIV(setup_info.div)
-		|  VCLKSET_LANE(dsi->lanes - 1);
+
+	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_LANE(dsi->lanes - 1);
+
+	switch (dsi->info->model) {
+	case RCAR_DSI_V3U:
+		vclkset |= VCLKSET_DIV_V3U(__ffs(setup_info.vclk_divider));
+		break;
+
+	case RCAR_DSI_V4H:
+		vclkset |= VCLKSET_DIV_V4H(__ffs(setup_info.vclk_divider) - 1);
+		break;
+
+	default:
+		return -ENODEV;
+	}
 
 	rcar_mipi_dsi_write(dsi, VCLKSET, vclkset);
 
@@ -841,8 +1055,39 @@ static int rcar_mipi_dsi_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct rcar_mipi_dsi_device_info v3u_data = {
+	.model = RCAR_DSI_V3U,
+	.clk_cfg = dsi_clk_cfg_v3u,
+	.clockset2_m_offset = 2,
+	.n_min = 3,
+	.n_max = 8,
+	.n_mul = 1,
+	.fpfd_min = MHZ(2),
+	.fpfd_max = MHZ(8),
+	.m_min = 64,
+	.m_max = 625,
+	.fout_min = MHZ(320),
+	.fout_max = MHZ(1250),
+};
+
+static const struct rcar_mipi_dsi_device_info v4h_data = {
+	.model = RCAR_DSI_V4H,
+	.clk_cfg = dsi_clk_cfg_v4h,
+	.clockset2_m_offset = 0,
+	.n_min = 1,
+	.n_max = 8,
+	.n_mul = 2,
+	.fpfd_min = MHZ(8),
+	.fpfd_max = MHZ(24),
+	.m_min = 167,
+	.m_max = 1000,
+	.fout_min = MHZ(2000),
+	.fout_max = MHZ(4000),
+};
+
 static const struct of_device_id rcar_mipi_dsi_of_table[] = {
-	{ .compatible = "renesas,r8a779a0-dsi-csi2-tx" },
+	{ .compatible = "renesas,r8a779a0-dsi-csi2-tx", .data = &v3u_data },
+	{ .compatible = "renesas,r8a779g0-dsi-csi2-tx", .data = &v4h_data },
 	{ }
 };
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
index 2eaca54636f3..f8114d11f2d1 100644
--- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
@@ -122,7 +122,8 @@
 #define VCLKSET_CKEN			(1 << 16)
 #define VCLKSET_COLOR_RGB		(0 << 8)
 #define VCLKSET_COLOR_YCC		(1 << 8)
-#define VCLKSET_DIV(x)			(((x) & 0x3) << 4)
+#define VCLKSET_DIV_V3U(x)		(((x) & 0x3) << 4)
+#define VCLKSET_DIV_V4H(x)		(((x) & 0x7) << 4)
 #define VCLKSET_BPP_16			(0 << 2)
 #define VCLKSET_BPP_18			(1 << 2)
 #define VCLKSET_BPP_18L			(2 << 2)
@@ -166,6 +167,9 @@
 #define PHTW_CWEN			(1 << 8)
 #define PHTW_TESTDIN_CODE(x)		(((x) & 0xff) << 0)
 
+#define PHTR				0x1038
+#define PHTR_TEST			(1 << 16)
+
 #define PHTC				0x103c
 #define PHTC_TESTCLR			(1 << 0)
 
-- 
2.34.1


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

* Re: [PATCH v3 7/7] drm: rcar-du: dsi: Add r8A779g0 support
  2022-11-29 13:41   ` [PATCH v3 7/7] drm: rcar-du: dsi: Add r8A779g0 support Tomi Valkeinen
@ 2022-11-29 17:44     ` Laurent Pinchart
  2022-11-30  8:08     ` [PATCH v4 " Tomi Valkeinen
  1 sibling, 0 replies; 25+ messages in thread
From: Laurent Pinchart @ 2022-11-29 17:44 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Kieran Bingham, Rob Herring, Krzysztof Kozlowski,
	Geert Uytterhoeven, Magnus Damm, dri-devel, linux-renesas-soc,
	devicetree, linux-kernel, Andrzej Hajda, Neil Armstrong,
	Robert Foss, Jonas Karlman, Jernej Skrabec

Hi Tomi,

Thank you for the patch.

On Tue, Nov 29, 2022 at 03:41:38PM +0200, Tomi Valkeinen wrote:
> Add DSI support for r8a779g0. The main differences to r8a779a0 are in
> the PLL and PHTW setups.
> 
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> ---
> Changes to v2:
> - Use MHZ() in the tables, with floating point values as inputs
> - Use V3U/V4H names instead of R8A779A0/R8A779G0
> - PLL diffs between V3U and V4H are now described in struct
>   rcar_mipi_dsi_device_info, and we have a single function to calculate
>   the pll settings.
> - Refactor fin_rate to outside the pll calc functions.
> - Fixed the PLL config debug print.
> - Dropped clockset2_n_offset, which is always 1
> 
>  drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c      | 499 ++++++++++++++-----
>  drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h |   6 +-
>  2 files changed, 377 insertions(+), 128 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> index a7f2b7f66a17..3b812ec034fe 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
> @@ -9,6 +9,7 @@
>  #include <linux/delay.h>
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
> +#include <linux/math64.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/of_device.h>
> @@ -28,6 +29,31 @@
>  #include "rcar_mipi_dsi.h"
>  #include "rcar_mipi_dsi_regs.h"
>  
> +#define MHZ(v) ((u32)((v) * 1000000U))
> +
> +enum rcar_mipi_dsi_hw_model {
> +	RCAR_DSI_V3U,
> +	RCAR_DSI_V4H,
> +};
> +
> +struct rcar_mipi_dsi_device_info {
> +	enum rcar_mipi_dsi_hw_model model;
> +
> +	const struct dsi_clk_config *clk_cfg;
> +
> +	u8 clockset2_m_offset;
> +
> +	u8 n_min;
> +	u8 n_max;
> +	u8 n_mul;
> +	unsigned long fpfd_min;
> +	unsigned long fpfd_max;
> +	u16 m_min;
> +	u16 m_max;
> +	unsigned long fout_min;
> +	unsigned long fout_max;
> +};
> +
>  struct rcar_mipi_dsi {
>  	struct device *dev;
>  	const struct rcar_mipi_dsi_device_info *info;
> @@ -50,6 +76,17 @@ struct rcar_mipi_dsi {
>  	unsigned int lanes;
>  };
>  
> +struct dsi_setup_info {
> +	unsigned long hsfreq;
> +	u16 hsfreqrange;
> +
> +	unsigned long fout;
> +	u16 m;
> +	u16 n;
> +	u16 vclk_divider;
> +	const struct dsi_clk_config *clkset;
> +};
> +
>  static inline struct rcar_mipi_dsi *
>  bridge_to_rcar_mipi_dsi(struct drm_bridge *bridge)
>  {
> @@ -62,65 +99,78 @@ host_to_rcar_mipi_dsi(struct mipi_dsi_host *host)
>  	return container_of(host, struct rcar_mipi_dsi, host);
>  }
>  
> -static const u32 phtw[] = {
> -	0x01020114, 0x01600115, /* General testing */
> -	0x01030116, 0x0102011d, /* General testing */
> -	0x011101a4, 0x018601a4, /* 1Gbps testing */
> -	0x014201a0, 0x010001a3, /* 1Gbps testing */
> -	0x0101011f,		/* 1Gbps testing */
> -};
> -
> -static const u32 phtw2[] = {
> -	0x010c0130, 0x010c0140, /* General testing */
> -	0x010c0150, 0x010c0180, /* General testing */
> -	0x010c0190,
> -	0x010a0160, 0x010a0170,
> -	0x01800164, 0x01800174,	/* 1Gbps testing */
> -};
> -
>  static const u32 hsfreqrange_table[][2] = {
> -	{ 80000000U,   0x00 }, { 90000000U,   0x10 }, { 100000000U,  0x20 },
> -	{ 110000000U,  0x30 }, { 120000000U,  0x01 }, { 130000000U,  0x11 },
> -	{ 140000000U,  0x21 }, { 150000000U,  0x31 }, { 160000000U,  0x02 },
> -	{ 170000000U,  0x12 }, { 180000000U,  0x22 }, { 190000000U,  0x32 },
> -	{ 205000000U,  0x03 }, { 220000000U,  0x13 }, { 235000000U,  0x23 },
> -	{ 250000000U,  0x33 }, { 275000000U,  0x04 }, { 300000000U,  0x14 },
> -	{ 325000000U,  0x25 }, { 350000000U,  0x35 }, { 400000000U,  0x05 },
> -	{ 450000000U,  0x16 }, { 500000000U,  0x26 }, { 550000000U,  0x37 },
> -	{ 600000000U,  0x07 }, { 650000000U,  0x18 }, { 700000000U,  0x28 },
> -	{ 750000000U,  0x39 }, { 800000000U,  0x09 }, { 850000000U,  0x19 },
> -	{ 900000000U,  0x29 }, { 950000000U,  0x3a }, { 1000000000U, 0x0a },
> -	{ 1050000000U, 0x1a }, { 1100000000U, 0x2a }, { 1150000000U, 0x3b },
> -	{ 1200000000U, 0x0b }, { 1250000000U, 0x1b }, { 1300000000U, 0x2b },
> -	{ 1350000000U, 0x3c }, { 1400000000U, 0x0c }, { 1450000000U, 0x1c },
> -	{ 1500000000U, 0x2c }, { 1550000000U, 0x3d }, { 1600000000U, 0x0d },
> -	{ 1650000000U, 0x1d }, { 1700000000U, 0x2e }, { 1750000000U, 0x3e },
> -	{ 1800000000U, 0x0e }, { 1850000000U, 0x1e }, { 1900000000U, 0x2f },
> -	{ 1950000000U, 0x3f }, { 2000000000U, 0x0f }, { 2050000000U, 0x40 },
> -	{ 2100000000U, 0x41 }, { 2150000000U, 0x42 }, { 2200000000U, 0x43 },
> -	{ 2250000000U, 0x44 }, { 2300000000U, 0x45 }, { 2350000000U, 0x46 },
> -	{ 2400000000U, 0x47 }, { 2450000000U, 0x48 }, { 2500000000U, 0x49 },
> +	{   MHZ(80), 0x00 }, {   MHZ(90), 0x10 }, {  MHZ(100), 0x20 },
> +	{  MHZ(110), 0x30 }, {  MHZ(120), 0x01 }, {  MHZ(130), 0x11 },
> +	{  MHZ(140), 0x21 }, {  MHZ(150), 0x31 }, {  MHZ(160), 0x02 },
> +	{  MHZ(170), 0x12 }, {  MHZ(180), 0x22 }, {  MHZ(190), 0x32 },
> +	{  MHZ(205), 0x03 }, {  MHZ(220), 0x13 }, {  MHZ(235), 0x23 },
> +	{  MHZ(250), 0x33 }, {  MHZ(275), 0x04 }, {  MHZ(300), 0x14 },
> +	{  MHZ(325), 0x25 }, {  MHZ(350), 0x35 }, {  MHZ(400), 0x05 },
> +	{  MHZ(450), 0x16 }, {  MHZ(500), 0x26 }, {  MHZ(550), 0x37 },
> +	{  MHZ(600), 0x07 }, {  MHZ(650), 0x18 }, {  MHZ(700), 0x28 },
> +	{  MHZ(750), 0x39 }, {  MHZ(800), 0x09 }, {  MHZ(850), 0x19 },
> +	{  MHZ(900), 0x29 }, {  MHZ(950), 0x3a }, { MHZ(1000), 0x0a },
> +	{ MHZ(1050), 0x1a }, { MHZ(1100), 0x2a }, { MHZ(1150), 0x3b },
> +	{ MHZ(1200), 0x0b }, { MHZ(1250), 0x1b }, { MHZ(1300), 0x2b },
> +	{ MHZ(1350), 0x3c }, { MHZ(1400), 0x0c }, { MHZ(1450), 0x1c },
> +	{ MHZ(1500), 0x2c }, { MHZ(1550), 0x3d }, { MHZ(1600), 0x0d },
> +	{ MHZ(1650), 0x1d }, { MHZ(1700), 0x2e }, { MHZ(1750), 0x3e },
> +	{ MHZ(1800), 0x0e }, { MHZ(1850), 0x1e }, { MHZ(1900), 0x2f },
> +	{ MHZ(1950), 0x3f }, { MHZ(2000), 0x0f }, { MHZ(2050), 0x40 },
> +	{ MHZ(2100), 0x41 }, { MHZ(2150), 0x42 }, { MHZ(2200), 0x43 },
> +	{ MHZ(2250), 0x44 }, { MHZ(2300), 0x45 }, { MHZ(2350), 0x46 },
> +	{ MHZ(2400), 0x47 }, { MHZ(2450), 0x48 }, { MHZ(2500), 0x49 },
>  	{ /* sentinel */ },
>  };
>  
> -struct vco_cntrl_value {
> +struct dsi_clk_config {
>  	u32 min_freq;
>  	u32 max_freq;
> -	u16 value;
> +	u8 vco_cntrl;
> +	u8 cpbias_cntrl;
> +	u8 gmp_cntrl;
> +	u8 int_cntrl;
> +	u8 prop_cntrl;
>  };
>  
> -static const struct vco_cntrl_value vco_cntrl_table[] = {
> -	{ .min_freq = 40000000U,   .max_freq = 55000000U,   .value = 0x3f },
> -	{ .min_freq = 52500000U,   .max_freq = 80000000U,   .value = 0x39 },
> -	{ .min_freq = 80000000U,   .max_freq = 110000000U,  .value = 0x2f },
> -	{ .min_freq = 105000000U,  .max_freq = 160000000U,  .value = 0x29 },
> -	{ .min_freq = 160000000U,  .max_freq = 220000000U,  .value = 0x1f },
> -	{ .min_freq = 210000000U,  .max_freq = 320000000U,  .value = 0x19 },
> -	{ .min_freq = 320000000U,  .max_freq = 440000000U,  .value = 0x0f },
> -	{ .min_freq = 420000000U,  .max_freq = 660000000U,  .value = 0x09 },
> -	{ .min_freq = 630000000U,  .max_freq = 1149000000U, .value = 0x03 },
> -	{ .min_freq = 1100000000U, .max_freq = 1152000000U, .value = 0x01 },
> -	{ .min_freq = 1150000000U, .max_freq = 1250000000U, .value = 0x01 },
> +static const struct dsi_clk_config dsi_clk_cfg_v3u[] = {
> +	{   MHZ(40),    MHZ(55), 0x3f, 0x10, 0x01, 0x00, 0x0b },
> +	{   MHZ(52.5),  MHZ(80), 0x39, 0x10, 0x01, 0x00, 0x0b },
> +	{   MHZ(80),   MHZ(110), 0x2f, 0x10, 0x01, 0x00, 0x0b },
> +	{  MHZ(105),   MHZ(160), 0x29, 0x10, 0x01, 0x00, 0x0b },
> +	{  MHZ(160),   MHZ(220), 0x1f, 0x10, 0x01, 0x00, 0x0b },
> +	{  MHZ(210),   MHZ(320), 0x19, 0x10, 0x01, 0x00, 0x0b },
> +	{  MHZ(320),   MHZ(440), 0x0f, 0x10, 0x01, 0x00, 0x0b },
> +	{  MHZ(420),   MHZ(660), 0x09, 0x10, 0x01, 0x00, 0x0b },
> +	{  MHZ(630),  MHZ(1149), 0x03, 0x10, 0x01, 0x00, 0x0b },
> +	{ MHZ(1100),  MHZ(1152), 0x01, 0x10, 0x01, 0x00, 0x0b },
> +	{ MHZ(1150),  MHZ(1250), 0x01, 0x10, 0x01, 0x00, 0x0c },
> +	{ /* sentinel */ },
> +};
> +
> +static const struct dsi_clk_config dsi_clk_cfg_v4h[] = {
> +	{   MHZ(40),    MHZ(45.31),  0x2b, 0x00, 0x00, 0x08, 0x0a },
> +	{   MHZ(45.31), MHZ(54.66),  0x28, 0x00, 0x00, 0x08, 0x0a },
> +	{   MHZ(54.66), MHZ(62.5),   0x28, 0x00, 0x00, 0x08, 0x0a },
> +	{   MHZ(62.5),  MHZ(75),     0x27, 0x00, 0x00, 0x08, 0x0a },
> +	{   MHZ(75),    MHZ(90.63),  0x23, 0x00, 0x00, 0x08, 0x0a },
> +	{   MHZ(90.63), MHZ(109.37), 0x20, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(109.37), MHZ(125),    0x20, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(125),    MHZ(150),    0x1f, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(150),    MHZ(181.25), 0x1b, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(181.25), MHZ(218.75), 0x18, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(218.75), MHZ(250),    0x18, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(250),    MHZ(300),    0x17, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(300),    MHZ(362.5),  0x13, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(362.5),  MHZ(455.48), 0x10, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(455.48), MHZ(500),    0x10, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(500),    MHZ(600),    0x0f, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(600),    MHZ(725),    0x0b, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(725),    MHZ(875),    0x08, 0x00, 0x00, 0x08, 0x0a },
> +	{  MHZ(875),   MHZ(1000),    0x08, 0x00, 0x00, 0x08, 0x0a },
> +	{ MHZ(1000),   MHZ(1200),    0x07, 0x00, 0x00, 0x08, 0x0a },
> +	{ MHZ(1200),   MHZ(1250),    0x03, 0x00, 0x00, 0x08, 0x0a },

That's nicer :-)

>  	{ /* sentinel */ },
>  };
>  
> @@ -144,7 +194,7 @@ static void rcar_mipi_dsi_set(struct rcar_mipi_dsi *dsi, u32 reg, u32 set)
>  	rcar_mipi_dsi_write(dsi, reg, rcar_mipi_dsi_read(dsi, reg) | set);
>  }
>  
> -static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
> +static int rcar_mipi_dsi_write_phtw(struct rcar_mipi_dsi *dsi, u32 phtw)
>  {
>  	u32 status;
>  	int ret;
> @@ -163,32 +213,181 @@ static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
>  	return ret;
>  }
>  
> +static int rcar_mipi_dsi_write_phtw_arr(struct rcar_mipi_dsi *dsi,
> +					const u32 *phtw, unsigned int size)
> +{
> +	for (unsigned int i = 0; i < size; i++) {
> +		int ret = rcar_mipi_dsi_write_phtw(dsi, phtw[i]);
> +
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +#define WRITE_PHTW(...)                                               \
> +	({                                                            \
> +		static const u32 phtw[] = { __VA_ARGS__ };            \
> +		int ret;                                              \
> +		ret = rcar_mipi_dsi_write_phtw_arr(dsi, phtw,         \
> +						   ARRAY_SIZE(phtw)); \
> +		ret;                                                  \
> +	})
> +
> +static int rcar_mipi_dsi_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
> +{
> +	return WRITE_PHTW(0x01020114, 0x01600115, 0x01030116, 0x0102011d,
> +			  0x011101a4, 0x018601a4, 0x014201a0, 0x010001a3,
> +			  0x0101011f);
> +}
> +
> +static int rcar_mipi_dsi_post_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
> +{
> +	return WRITE_PHTW(0x010c0130, 0x010c0140, 0x010c0150, 0x010c0180,
> +			  0x010c0190, 0x010a0160, 0x010a0170, 0x01800164,
> +			  0x01800174);
> +}
> +
> +static int rcar_mipi_dsi_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
> +				       const struct dsi_setup_info *setup_info)
> +{
> +	int ret;
> +
> +	if (setup_info->hsfreq < MHZ(450)) {
> +		ret = WRITE_PHTW(0x01010100, 0x011b01ac);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = WRITE_PHTW(0x01010100, 0x01030173, 0x01000174, 0x01500175,
> +			 0x01030176, 0x01040166, 0x010201ad);
> +	if (ret)
> +		return ret;
> +
> +	if (setup_info->hsfreq <= MHZ(1000))
> +		ret = WRITE_PHTW(0x01020100, 0x01910170, 0x01020171,
> +				 0x01110172);
> +	else if (setup_info->hsfreq <= MHZ(1500))
> +		ret = WRITE_PHTW(0x01020100, 0x01980170, 0x01030171,
> +				 0x01100172);
> +	else if (setup_info->hsfreq <= MHZ(2500))
> +		ret = WRITE_PHTW(0x01020100, 0x0144016b, 0x01000172);
> +	else
> +		return -EINVAL;
> +
> +	if (ret)
> +		return ret;
> +
> +	if (dsi->lanes <= 1) {
> +		ret = WRITE_PHTW(0x01070100, 0x010e010b);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (dsi->lanes <= 2) {
> +		ret = WRITE_PHTW(0x01090100, 0x010e010b);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (dsi->lanes <= 3) {
> +		ret = WRITE_PHTW(0x010b0100, 0x010e010b);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (setup_info->hsfreq <= MHZ(1500)) {
> +		ret = WRITE_PHTW(0x01010100, 0x01c0016e);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +rcar_mipi_dsi_post_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
> +				 const struct dsi_setup_info *setup_info)
> +{
> +	u32 status;
> +	int ret;
> +
> +	if (setup_info->hsfreq <= MHZ(1500)) {
> +		WRITE_PHTW(0x01020100, 0x00000180);
> +
> +		ret = read_poll_timeout(rcar_mipi_dsi_read, status,
> +					status & PHTR_TEST, 2000, 10000, false,
> +					dsi, PHTR);
> +		if (ret < 0) {
> +			dev_err(dsi->dev, "failed to test PHTR\n");
> +			return ret;
> +		}
> +
> +		WRITE_PHTW(0x01010100, 0x0100016e);
> +	}
> +
> +	return 0;
> +}
> +
>  /* -----------------------------------------------------------------------------
>   * Hardware Setup
>   */
>  
> -struct dsi_setup_info {
> -	unsigned long fout;
> -	u16 vco_cntrl;
> -	u16 prop_cntrl;
> -	u16 hsfreqrange;
> -	u16 div;
> -	unsigned int m;
> -	unsigned int n;
> -};
> +static void rcar_mipi_dsi_pll_calc(struct rcar_mipi_dsi *dsi,
> +				   unsigned long fin_rate,
> +				   unsigned long fout_target,
> +				   struct dsi_setup_info *setup_info)
> +{
> +	unsigned int best_err = -1;
> +	const struct rcar_mipi_dsi_device_info *info = dsi->info;
> +
> +	for (unsigned int n = info->n_min; n <= info->n_max; n++) {
> +		unsigned long fpfd;
> +
> +		fpfd = fin_rate / n;
> +
> +		if (fpfd < info->fpfd_min || fpfd > info->fpfd_max)
> +			continue;
> +
> +		for (unsigned int m = info->m_min; m <= info->m_max; m++) {
> +			unsigned int err;
> +			u64 fout;
> +
> +			fout = div64_u64((u64)fpfd * m, dsi->info->n_mul);
> +
> +			if (fout < info->fout_min || fout > info->fout_max)
> +				continue;
> +
> +			fout = div64_u64(fout, setup_info->vclk_divider);
> +
> +			if (fout < setup_info->clkset->min_freq ||
> +			    fout > setup_info->clkset->max_freq)
> +				continue;
> +
> +			err = abs((long)(fout - fout_target) * 10000 /
> +				  (long)fout_target);
> +			if (err < best_err) {
> +				setup_info->m = m;
> +				setup_info->n = n;
> +				setup_info->fout = (unsigned long)fout;
> +				best_err = err;
> +
> +				if (err == 0)
> +					return;
> +			}
> +		}
> +	}

This is potentially a large number of iterations, it would be nice to
optimize it, but not now.

> +}
>  
>  static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
>  					  struct clk *clk, unsigned long target,
>  					  struct dsi_setup_info *setup_info)
>  {
>  
> -	const struct vco_cntrl_value *vco_cntrl;
> +	const struct dsi_clk_config *clk_cfg;
>  	unsigned long fout_target;
> -	unsigned long fin, fout;
> -	unsigned long hsfreq;
> -	unsigned int best_err = -1;
> -	unsigned int divider;
> -	unsigned int n;
> +	unsigned long fin_rate;
>  	unsigned int i;
>  	unsigned int err;
>  
> @@ -198,70 +397,55 @@ static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
>  	 */
>  	fout_target = target * mipi_dsi_pixel_format_to_bpp(dsi->format)
>  		    / (2 * dsi->lanes);
> -	if (fout_target < 40000000 || fout_target > 1250000000)
> +	if (fout_target < MHZ(40) || fout_target > MHZ(1250))
>  		return;
>  
> -	/* Find vco_cntrl */
> -	for (vco_cntrl = vco_cntrl_table; vco_cntrl->min_freq != 0; vco_cntrl++) {
> -		if (fout_target > vco_cntrl->min_freq &&
> -		    fout_target <= vco_cntrl->max_freq) {
> -			setup_info->vco_cntrl = vco_cntrl->value;
> -			if (fout_target >= 1150000000)
> -				setup_info->prop_cntrl = 0x0c;
> -			else
> -				setup_info->prop_cntrl = 0x0b;
> +	/* Find PLL settings */
> +	for (clk_cfg = dsi->info->clk_cfg; clk_cfg->min_freq != 0; clk_cfg++) {
> +		if (fout_target > clk_cfg->min_freq &&
> +		    fout_target <= clk_cfg->max_freq) {
> +			setup_info->clkset = clk_cfg;
>  			break;
>  		}
>  	}
>  
> -	/* Add divider */
> -	setup_info->div = (setup_info->vco_cntrl & 0x30) >> 4;
> +	fin_rate = clk_get_rate(clk);
> +
> +	switch (dsi->info->model) {
> +	case RCAR_DSI_V3U:
> +		setup_info->vclk_divider = 1 << ((clk_cfg->vco_cntrl >> 4) & 0x3);
> +		break;
> +
> +	case RCAR_DSI_V4H:
> +		setup_info->vclk_divider = 1 << (((clk_cfg->vco_cntrl >> 3) & 0x7) + 1);
> +		break;
> +
> +	default:
> +		return;

Can't happen, I'd add the default label to one of the V3U or V4H label
to keep the compiler and static analyzers happy.

> +	}
> +
> +	rcar_mipi_dsi_pll_calc(dsi, fin_rate, fout_target, setup_info);
>  
>  	/* Find hsfreqrange */
> -	hsfreq = fout_target * 2;
> +	setup_info->hsfreq = setup_info->fout * 2;
>  	for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++) {
> -		if (hsfreqrange_table[i][0] >= hsfreq) {
> +		if (hsfreqrange_table[i][0] >= setup_info->hsfreq) {
>  			setup_info->hsfreqrange = hsfreqrange_table[i][1];
>  			break;
>  		}
>  	}
>  
> -	/*
> -	 * Calculate n and m for PLL clock
> -	 * Following the HW manual the ranges of n and m are
> -	 * n = [3-8] and m = [64-625]
> -	 */
> -	fin = clk_get_rate(clk);
> -	divider = 1 << setup_info->div;
> -	for (n = 3; n < 9; n++) {
> -		unsigned long fpfd;
> -		unsigned int m;
> -
> -		fpfd = fin / n;
> -
> -		for (m = 64; m < 626; m++) {
> -			fout = fpfd * m / divider;
> -			err = abs((long)(fout - fout_target) * 10000 /
> -				  (long)fout_target);
> -			if (err < best_err) {
> -				setup_info->m = m - 2;
> -				setup_info->n = n - 1;
> -				setup_info->fout = fout;
> -				best_err = err;
> -				if (err == 0)
> -					goto done;
> -			}
> -		}
> -	}
> +	err = abs((long)(setup_info->fout - fout_target) * 10000 / (long)fout_target);
>  
> -done:
>  	dev_dbg(dsi->dev,
> -		"%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/DIV %u/%u/%u\n",
> -		clk, fin, setup_info->fout, fout_target, best_err / 100,
> -		best_err % 100, setup_info->m, setup_info->n, setup_info->div);
> +		"Fout = %u * %lu / (%u * %u * %u) = %lu (target %lu Hz, error %d.%02u%%)\n",
> +		setup_info->m, fin_rate, dsi->info->n_mul, setup_info->n,
> +		setup_info->vclk_divider, setup_info->fout, fout_target,
> +		err / 100, err % 100);
> +
>  	dev_dbg(dsi->dev,
>  		"vco_cntrl = 0x%x\tprop_cntrl = 0x%x\thsfreqrange = 0x%x\n",
> -		setup_info->vco_cntrl, setup_info->prop_cntrl,
> +		clk_cfg->vco_cntrl, clk_cfg->prop_cntrl,
>  		setup_info->hsfreqrange);
>  }
>  
> @@ -324,7 +508,7 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>  {
>  	struct dsi_setup_info setup_info = {};
>  	unsigned int timeout;
> -	int ret, i;
> +	int ret;
>  	int dsi_format;
>  	u32 phy_setup;
>  	u32 clockset2, clockset3;
> @@ -360,10 +544,18 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>  	phy_setup |= PHYSETUP_HSFREQRANGE(setup_info.hsfreqrange);
>  	rcar_mipi_dsi_write(dsi, PHYSETUP, phy_setup);
>  
> -	for (i = 0; i < ARRAY_SIZE(phtw); i++) {
> -		ret = rcar_mipi_dsi_phtw_test(dsi, phtw[i]);
> +	switch (dsi->info->model) {
> +	case RCAR_DSI_V3U:
> +		ret = rcar_mipi_dsi_init_phtw_v3u(dsi);
> +		if (ret < 0)
> +			return ret;
> +		break;
> +
> +	case RCAR_DSI_V4H:
> +		ret = rcar_mipi_dsi_init_phtw_v4h(dsi, &setup_info);
>  		if (ret < 0)
>  			return ret;
> +		break;
>  	}
>  
>  	/* PLL Clock Setting */
> @@ -371,12 +563,13 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>  	rcar_mipi_dsi_set(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
>  	rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
>  
> -	clockset2 = CLOCKSET2_M(setup_info.m) | CLOCKSET2_N(setup_info.n)
> -		  | CLOCKSET2_VCO_CNTRL(setup_info.vco_cntrl);
> -	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.prop_cntrl)
> -		  | CLOCKSET3_INT_CNTRL(0)
> -		  | CLOCKSET3_CPBIAS_CNTRL(0x10)
> -		  | CLOCKSET3_GMP_CNTRL(1);
> +	clockset2 = CLOCKSET2_M(setup_info.m - dsi->info->clockset2_m_offset)
> +		  | CLOCKSET2_N(setup_info.n - 1)
> +		  | CLOCKSET2_VCO_CNTRL(setup_info.clkset->vco_cntrl);
> +	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.clkset->prop_cntrl)
> +		  | CLOCKSET3_INT_CNTRL(setup_info.clkset->int_cntrl)
> +		  | CLOCKSET3_CPBIAS_CNTRL(setup_info.clkset->cpbias_cntrl)
> +		  | CLOCKSET3_GMP_CNTRL(setup_info.clkset->gmp_cntrl);
>  	rcar_mipi_dsi_write(dsi, CLOCKSET2, clockset2);
>  	rcar_mipi_dsi_write(dsi, CLOCKSET3, clockset3);
>  
> @@ -407,10 +600,18 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>  		return -ETIMEDOUT;
>  	}
>  
> -	for (i = 0; i < ARRAY_SIZE(phtw2); i++) {
> -		ret = rcar_mipi_dsi_phtw_test(dsi, phtw2[i]);
> +	switch (dsi->info->model) {
> +	case RCAR_DSI_V3U:
> +		ret = rcar_mipi_dsi_post_init_phtw_v3u(dsi);
>  		if (ret < 0)
>  			return ret;
> +		break;
> +
> +	case RCAR_DSI_V4H:
> +		ret = rcar_mipi_dsi_post_init_phtw_v4h(dsi, &setup_info);
> +		if (ret < 0)
> +			return ret;
> +		break;
>  	}
>  
>  	/* Enable DOT clock */
> @@ -427,8 +628,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
>  		dev_warn(dsi->dev, "unsupported format");
>  		return -EINVAL;
>  	}
> -	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_DIV(setup_info.div)
> -		|  VCLKSET_LANE(dsi->lanes - 1);
> +
> +	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_LANE(dsi->lanes - 1);
> +
> +	switch (dsi->info->model) {
> +	case RCAR_DSI_V3U:
> +		vclkset |= VCLKSET_DIV_V3U(__ffs(setup_info.vclk_divider));
> +		break;
> +
> +	case RCAR_DSI_V4H:
> +		vclkset |= VCLKSET_DIV_V4H(__ffs(setup_info.vclk_divider) - 1);
> +		break;
> +
> +	default:
> +		return -ENODEV;

Can't happen, merge the default label with one of the two labels above
(or drop it).

Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

I'll let you post a v4 with the minor issues addressed, and will then
merge it in my tree.

> +	}
>  
>  	rcar_mipi_dsi_write(dsi, VCLKSET, vclkset);
>  
> @@ -841,8 +1055,39 @@ static int rcar_mipi_dsi_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static const struct rcar_mipi_dsi_device_info v3u_data = {
> +	.model = RCAR_DSI_V3U,
> +	.clk_cfg = dsi_clk_cfg_v3u,
> +	.clockset2_m_offset = 2,
> +	.n_min = 3,
> +	.n_max = 8,
> +	.n_mul = 1,
> +	.fpfd_min = MHZ(2),
> +	.fpfd_max = MHZ(8),
> +	.m_min = 64,
> +	.m_max = 625,
> +	.fout_min = MHZ(320),
> +	.fout_max = MHZ(1250),
> +};
> +
> +static const struct rcar_mipi_dsi_device_info v4h_data = {
> +	.model = RCAR_DSI_V4H,
> +	.clk_cfg = dsi_clk_cfg_v4h,
> +	.clockset2_m_offset = 0,
> +	.n_min = 1,
> +	.n_max = 8,
> +	.n_mul = 2,
> +	.fpfd_min = MHZ(8),
> +	.fpfd_max = MHZ(24),
> +	.m_min = 167,
> +	.m_max = 1000,
> +	.fout_min = MHZ(2000),
> +	.fout_max = MHZ(4000),
> +};
> +
>  static const struct of_device_id rcar_mipi_dsi_of_table[] = {
> -	{ .compatible = "renesas,r8a779a0-dsi-csi2-tx" },
> +	{ .compatible = "renesas,r8a779a0-dsi-csi2-tx", .data = &v3u_data },
> +	{ .compatible = "renesas,r8a779g0-dsi-csi2-tx", .data = &v4h_data },
>  	{ }
>  };
>  
> diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
> index 2eaca54636f3..f8114d11f2d1 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
> @@ -122,7 +122,8 @@
>  #define VCLKSET_CKEN			(1 << 16)
>  #define VCLKSET_COLOR_RGB		(0 << 8)
>  #define VCLKSET_COLOR_YCC		(1 << 8)
> -#define VCLKSET_DIV(x)			(((x) & 0x3) << 4)
> +#define VCLKSET_DIV_V3U(x)		(((x) & 0x3) << 4)
> +#define VCLKSET_DIV_V4H(x)		(((x) & 0x7) << 4)
>  #define VCLKSET_BPP_16			(0 << 2)
>  #define VCLKSET_BPP_18			(1 << 2)
>  #define VCLKSET_BPP_18L			(2 << 2)
> @@ -166,6 +167,9 @@
>  #define PHTW_CWEN			(1 << 8)
>  #define PHTW_TESTDIN_CODE(x)		(((x) & 0xff) << 0)
>  
> +#define PHTR				0x1038
> +#define PHTR_TEST			(1 << 16)
> +
>  #define PHTC				0x103c
>  #define PHTC_TESTCLR			(1 << 0)
>  

-- 
Regards,

Laurent Pinchart

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

* [PATCH v4 7/7] drm: rcar-du: dsi: Add r8A779g0 support
  2022-11-29 13:41   ` [PATCH v3 7/7] drm: rcar-du: dsi: Add r8A779g0 support Tomi Valkeinen
  2022-11-29 17:44     ` Laurent Pinchart
@ 2022-11-30  8:08     ` Tomi Valkeinen
  1 sibling, 0 replies; 25+ messages in thread
From: Tomi Valkeinen @ 2022-11-30  8:08 UTC (permalink / raw)
  To: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
	Jernej Skrabec, Tomi Valkeinen, Laurent Pinchart

Add DSI support for r8a779g0. The main differences to r8a779a0 are in
the PLL and PHTW setups.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---

Changes to v3:
- Use v3h as the default case in "switch(model)" tests
- Add Laurent's rb

 drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c      | 497 ++++++++++++++-----
 drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h |   6 +-
 2 files changed, 375 insertions(+), 128 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
index a7f2b7f66a17..e10e4d4b89a2 100644
--- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
+++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
@@ -9,6 +9,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -28,6 +29,31 @@
 #include "rcar_mipi_dsi.h"
 #include "rcar_mipi_dsi_regs.h"
 
+#define MHZ(v) ((u32)((v) * 1000000U))
+
+enum rcar_mipi_dsi_hw_model {
+	RCAR_DSI_V3U,
+	RCAR_DSI_V4H,
+};
+
+struct rcar_mipi_dsi_device_info {
+	enum rcar_mipi_dsi_hw_model model;
+
+	const struct dsi_clk_config *clk_cfg;
+
+	u8 clockset2_m_offset;
+
+	u8 n_min;
+	u8 n_max;
+	u8 n_mul;
+	unsigned long fpfd_min;
+	unsigned long fpfd_max;
+	u16 m_min;
+	u16 m_max;
+	unsigned long fout_min;
+	unsigned long fout_max;
+};
+
 struct rcar_mipi_dsi {
 	struct device *dev;
 	const struct rcar_mipi_dsi_device_info *info;
@@ -50,6 +76,17 @@ struct rcar_mipi_dsi {
 	unsigned int lanes;
 };
 
+struct dsi_setup_info {
+	unsigned long hsfreq;
+	u16 hsfreqrange;
+
+	unsigned long fout;
+	u16 m;
+	u16 n;
+	u16 vclk_divider;
+	const struct dsi_clk_config *clkset;
+};
+
 static inline struct rcar_mipi_dsi *
 bridge_to_rcar_mipi_dsi(struct drm_bridge *bridge)
 {
@@ -62,65 +99,78 @@ host_to_rcar_mipi_dsi(struct mipi_dsi_host *host)
 	return container_of(host, struct rcar_mipi_dsi, host);
 }
 
-static const u32 phtw[] = {
-	0x01020114, 0x01600115, /* General testing */
-	0x01030116, 0x0102011d, /* General testing */
-	0x011101a4, 0x018601a4, /* 1Gbps testing */
-	0x014201a0, 0x010001a3, /* 1Gbps testing */
-	0x0101011f,		/* 1Gbps testing */
-};
-
-static const u32 phtw2[] = {
-	0x010c0130, 0x010c0140, /* General testing */
-	0x010c0150, 0x010c0180, /* General testing */
-	0x010c0190,
-	0x010a0160, 0x010a0170,
-	0x01800164, 0x01800174,	/* 1Gbps testing */
-};
-
 static const u32 hsfreqrange_table[][2] = {
-	{ 80000000U,   0x00 }, { 90000000U,   0x10 }, { 100000000U,  0x20 },
-	{ 110000000U,  0x30 }, { 120000000U,  0x01 }, { 130000000U,  0x11 },
-	{ 140000000U,  0x21 }, { 150000000U,  0x31 }, { 160000000U,  0x02 },
-	{ 170000000U,  0x12 }, { 180000000U,  0x22 }, { 190000000U,  0x32 },
-	{ 205000000U,  0x03 }, { 220000000U,  0x13 }, { 235000000U,  0x23 },
-	{ 250000000U,  0x33 }, { 275000000U,  0x04 }, { 300000000U,  0x14 },
-	{ 325000000U,  0x25 }, { 350000000U,  0x35 }, { 400000000U,  0x05 },
-	{ 450000000U,  0x16 }, { 500000000U,  0x26 }, { 550000000U,  0x37 },
-	{ 600000000U,  0x07 }, { 650000000U,  0x18 }, { 700000000U,  0x28 },
-	{ 750000000U,  0x39 }, { 800000000U,  0x09 }, { 850000000U,  0x19 },
-	{ 900000000U,  0x29 }, { 950000000U,  0x3a }, { 1000000000U, 0x0a },
-	{ 1050000000U, 0x1a }, { 1100000000U, 0x2a }, { 1150000000U, 0x3b },
-	{ 1200000000U, 0x0b }, { 1250000000U, 0x1b }, { 1300000000U, 0x2b },
-	{ 1350000000U, 0x3c }, { 1400000000U, 0x0c }, { 1450000000U, 0x1c },
-	{ 1500000000U, 0x2c }, { 1550000000U, 0x3d }, { 1600000000U, 0x0d },
-	{ 1650000000U, 0x1d }, { 1700000000U, 0x2e }, { 1750000000U, 0x3e },
-	{ 1800000000U, 0x0e }, { 1850000000U, 0x1e }, { 1900000000U, 0x2f },
-	{ 1950000000U, 0x3f }, { 2000000000U, 0x0f }, { 2050000000U, 0x40 },
-	{ 2100000000U, 0x41 }, { 2150000000U, 0x42 }, { 2200000000U, 0x43 },
-	{ 2250000000U, 0x44 }, { 2300000000U, 0x45 }, { 2350000000U, 0x46 },
-	{ 2400000000U, 0x47 }, { 2450000000U, 0x48 }, { 2500000000U, 0x49 },
+	{   MHZ(80), 0x00 }, {   MHZ(90), 0x10 }, {  MHZ(100), 0x20 },
+	{  MHZ(110), 0x30 }, {  MHZ(120), 0x01 }, {  MHZ(130), 0x11 },
+	{  MHZ(140), 0x21 }, {  MHZ(150), 0x31 }, {  MHZ(160), 0x02 },
+	{  MHZ(170), 0x12 }, {  MHZ(180), 0x22 }, {  MHZ(190), 0x32 },
+	{  MHZ(205), 0x03 }, {  MHZ(220), 0x13 }, {  MHZ(235), 0x23 },
+	{  MHZ(250), 0x33 }, {  MHZ(275), 0x04 }, {  MHZ(300), 0x14 },
+	{  MHZ(325), 0x25 }, {  MHZ(350), 0x35 }, {  MHZ(400), 0x05 },
+	{  MHZ(450), 0x16 }, {  MHZ(500), 0x26 }, {  MHZ(550), 0x37 },
+	{  MHZ(600), 0x07 }, {  MHZ(650), 0x18 }, {  MHZ(700), 0x28 },
+	{  MHZ(750), 0x39 }, {  MHZ(800), 0x09 }, {  MHZ(850), 0x19 },
+	{  MHZ(900), 0x29 }, {  MHZ(950), 0x3a }, { MHZ(1000), 0x0a },
+	{ MHZ(1050), 0x1a }, { MHZ(1100), 0x2a }, { MHZ(1150), 0x3b },
+	{ MHZ(1200), 0x0b }, { MHZ(1250), 0x1b }, { MHZ(1300), 0x2b },
+	{ MHZ(1350), 0x3c }, { MHZ(1400), 0x0c }, { MHZ(1450), 0x1c },
+	{ MHZ(1500), 0x2c }, { MHZ(1550), 0x3d }, { MHZ(1600), 0x0d },
+	{ MHZ(1650), 0x1d }, { MHZ(1700), 0x2e }, { MHZ(1750), 0x3e },
+	{ MHZ(1800), 0x0e }, { MHZ(1850), 0x1e }, { MHZ(1900), 0x2f },
+	{ MHZ(1950), 0x3f }, { MHZ(2000), 0x0f }, { MHZ(2050), 0x40 },
+	{ MHZ(2100), 0x41 }, { MHZ(2150), 0x42 }, { MHZ(2200), 0x43 },
+	{ MHZ(2250), 0x44 }, { MHZ(2300), 0x45 }, { MHZ(2350), 0x46 },
+	{ MHZ(2400), 0x47 }, { MHZ(2450), 0x48 }, { MHZ(2500), 0x49 },
 	{ /* sentinel */ },
 };
 
-struct vco_cntrl_value {
+struct dsi_clk_config {
 	u32 min_freq;
 	u32 max_freq;
-	u16 value;
+	u8 vco_cntrl;
+	u8 cpbias_cntrl;
+	u8 gmp_cntrl;
+	u8 int_cntrl;
+	u8 prop_cntrl;
 };
 
-static const struct vco_cntrl_value vco_cntrl_table[] = {
-	{ .min_freq = 40000000U,   .max_freq = 55000000U,   .value = 0x3f },
-	{ .min_freq = 52500000U,   .max_freq = 80000000U,   .value = 0x39 },
-	{ .min_freq = 80000000U,   .max_freq = 110000000U,  .value = 0x2f },
-	{ .min_freq = 105000000U,  .max_freq = 160000000U,  .value = 0x29 },
-	{ .min_freq = 160000000U,  .max_freq = 220000000U,  .value = 0x1f },
-	{ .min_freq = 210000000U,  .max_freq = 320000000U,  .value = 0x19 },
-	{ .min_freq = 320000000U,  .max_freq = 440000000U,  .value = 0x0f },
-	{ .min_freq = 420000000U,  .max_freq = 660000000U,  .value = 0x09 },
-	{ .min_freq = 630000000U,  .max_freq = 1149000000U, .value = 0x03 },
-	{ .min_freq = 1100000000U, .max_freq = 1152000000U, .value = 0x01 },
-	{ .min_freq = 1150000000U, .max_freq = 1250000000U, .value = 0x01 },
+static const struct dsi_clk_config dsi_clk_cfg_v3u[] = {
+	{   MHZ(40),    MHZ(55), 0x3f, 0x10, 0x01, 0x00, 0x0b },
+	{   MHZ(52.5),  MHZ(80), 0x39, 0x10, 0x01, 0x00, 0x0b },
+	{   MHZ(80),   MHZ(110), 0x2f, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(105),   MHZ(160), 0x29, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(160),   MHZ(220), 0x1f, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(210),   MHZ(320), 0x19, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(320),   MHZ(440), 0x0f, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(420),   MHZ(660), 0x09, 0x10, 0x01, 0x00, 0x0b },
+	{  MHZ(630),  MHZ(1149), 0x03, 0x10, 0x01, 0x00, 0x0b },
+	{ MHZ(1100),  MHZ(1152), 0x01, 0x10, 0x01, 0x00, 0x0b },
+	{ MHZ(1150),  MHZ(1250), 0x01, 0x10, 0x01, 0x00, 0x0c },
+	{ /* sentinel */ },
+};
+
+static const struct dsi_clk_config dsi_clk_cfg_v4h[] = {
+	{   MHZ(40),    MHZ(45.31),  0x2b, 0x00, 0x00, 0x08, 0x0a },
+	{   MHZ(45.31), MHZ(54.66),  0x28, 0x00, 0x00, 0x08, 0x0a },
+	{   MHZ(54.66), MHZ(62.5),   0x28, 0x00, 0x00, 0x08, 0x0a },
+	{   MHZ(62.5),  MHZ(75),     0x27, 0x00, 0x00, 0x08, 0x0a },
+	{   MHZ(75),    MHZ(90.63),  0x23, 0x00, 0x00, 0x08, 0x0a },
+	{   MHZ(90.63), MHZ(109.37), 0x20, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(109.37), MHZ(125),    0x20, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(125),    MHZ(150),    0x1f, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(150),    MHZ(181.25), 0x1b, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(181.25), MHZ(218.75), 0x18, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(218.75), MHZ(250),    0x18, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(250),    MHZ(300),    0x17, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(300),    MHZ(362.5),  0x13, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(362.5),  MHZ(455.48), 0x10, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(455.48), MHZ(500),    0x10, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(500),    MHZ(600),    0x0f, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(600),    MHZ(725),    0x0b, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(725),    MHZ(875),    0x08, 0x00, 0x00, 0x08, 0x0a },
+	{  MHZ(875),   MHZ(1000),    0x08, 0x00, 0x00, 0x08, 0x0a },
+	{ MHZ(1000),   MHZ(1200),    0x07, 0x00, 0x00, 0x08, 0x0a },
+	{ MHZ(1200),   MHZ(1250),    0x03, 0x00, 0x00, 0x08, 0x0a },
 	{ /* sentinel */ },
 };
 
@@ -144,7 +194,7 @@ static void rcar_mipi_dsi_set(struct rcar_mipi_dsi *dsi, u32 reg, u32 set)
 	rcar_mipi_dsi_write(dsi, reg, rcar_mipi_dsi_read(dsi, reg) | set);
 }
 
-static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
+static int rcar_mipi_dsi_write_phtw(struct rcar_mipi_dsi *dsi, u32 phtw)
 {
 	u32 status;
 	int ret;
@@ -163,32 +213,181 @@ static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
 	return ret;
 }
 
+static int rcar_mipi_dsi_write_phtw_arr(struct rcar_mipi_dsi *dsi,
+					const u32 *phtw, unsigned int size)
+{
+	for (unsigned int i = 0; i < size; i++) {
+		int ret = rcar_mipi_dsi_write_phtw(dsi, phtw[i]);
+
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+#define WRITE_PHTW(...)                                               \
+	({                                                            \
+		static const u32 phtw[] = { __VA_ARGS__ };            \
+		int ret;                                              \
+		ret = rcar_mipi_dsi_write_phtw_arr(dsi, phtw,         \
+						   ARRAY_SIZE(phtw)); \
+		ret;                                                  \
+	})
+
+static int rcar_mipi_dsi_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
+{
+	return WRITE_PHTW(0x01020114, 0x01600115, 0x01030116, 0x0102011d,
+			  0x011101a4, 0x018601a4, 0x014201a0, 0x010001a3,
+			  0x0101011f);
+}
+
+static int rcar_mipi_dsi_post_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
+{
+	return WRITE_PHTW(0x010c0130, 0x010c0140, 0x010c0150, 0x010c0180,
+			  0x010c0190, 0x010a0160, 0x010a0170, 0x01800164,
+			  0x01800174);
+}
+
+static int rcar_mipi_dsi_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
+				       const struct dsi_setup_info *setup_info)
+{
+	int ret;
+
+	if (setup_info->hsfreq < MHZ(450)) {
+		ret = WRITE_PHTW(0x01010100, 0x011b01ac);
+		if (ret)
+			return ret;
+	}
+
+	ret = WRITE_PHTW(0x01010100, 0x01030173, 0x01000174, 0x01500175,
+			 0x01030176, 0x01040166, 0x010201ad);
+	if (ret)
+		return ret;
+
+	if (setup_info->hsfreq <= MHZ(1000))
+		ret = WRITE_PHTW(0x01020100, 0x01910170, 0x01020171,
+				 0x01110172);
+	else if (setup_info->hsfreq <= MHZ(1500))
+		ret = WRITE_PHTW(0x01020100, 0x01980170, 0x01030171,
+				 0x01100172);
+	else if (setup_info->hsfreq <= MHZ(2500))
+		ret = WRITE_PHTW(0x01020100, 0x0144016b, 0x01000172);
+	else
+		return -EINVAL;
+
+	if (ret)
+		return ret;
+
+	if (dsi->lanes <= 1) {
+		ret = WRITE_PHTW(0x01070100, 0x010e010b);
+		if (ret)
+			return ret;
+	}
+
+	if (dsi->lanes <= 2) {
+		ret = WRITE_PHTW(0x01090100, 0x010e010b);
+		if (ret)
+			return ret;
+	}
+
+	if (dsi->lanes <= 3) {
+		ret = WRITE_PHTW(0x010b0100, 0x010e010b);
+		if (ret)
+			return ret;
+	}
+
+	if (setup_info->hsfreq <= MHZ(1500)) {
+		ret = WRITE_PHTW(0x01010100, 0x01c0016e);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int
+rcar_mipi_dsi_post_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
+				 const struct dsi_setup_info *setup_info)
+{
+	u32 status;
+	int ret;
+
+	if (setup_info->hsfreq <= MHZ(1500)) {
+		WRITE_PHTW(0x01020100, 0x00000180);
+
+		ret = read_poll_timeout(rcar_mipi_dsi_read, status,
+					status & PHTR_TEST, 2000, 10000, false,
+					dsi, PHTR);
+		if (ret < 0) {
+			dev_err(dsi->dev, "failed to test PHTR\n");
+			return ret;
+		}
+
+		WRITE_PHTW(0x01010100, 0x0100016e);
+	}
+
+	return 0;
+}
+
 /* -----------------------------------------------------------------------------
  * Hardware Setup
  */
 
-struct dsi_setup_info {
-	unsigned long fout;
-	u16 vco_cntrl;
-	u16 prop_cntrl;
-	u16 hsfreqrange;
-	u16 div;
-	unsigned int m;
-	unsigned int n;
-};
+static void rcar_mipi_dsi_pll_calc(struct rcar_mipi_dsi *dsi,
+				   unsigned long fin_rate,
+				   unsigned long fout_target,
+				   struct dsi_setup_info *setup_info)
+{
+	unsigned int best_err = -1;
+	const struct rcar_mipi_dsi_device_info *info = dsi->info;
+
+	for (unsigned int n = info->n_min; n <= info->n_max; n++) {
+		unsigned long fpfd;
+
+		fpfd = fin_rate / n;
+
+		if (fpfd < info->fpfd_min || fpfd > info->fpfd_max)
+			continue;
+
+		for (unsigned int m = info->m_min; m <= info->m_max; m++) {
+			unsigned int err;
+			u64 fout;
+
+			fout = div64_u64((u64)fpfd * m, dsi->info->n_mul);
+
+			if (fout < info->fout_min || fout > info->fout_max)
+				continue;
+
+			fout = div64_u64(fout, setup_info->vclk_divider);
+
+			if (fout < setup_info->clkset->min_freq ||
+			    fout > setup_info->clkset->max_freq)
+				continue;
+
+			err = abs((long)(fout - fout_target) * 10000 /
+				  (long)fout_target);
+			if (err < best_err) {
+				setup_info->m = m;
+				setup_info->n = n;
+				setup_info->fout = (unsigned long)fout;
+				best_err = err;
+
+				if (err == 0)
+					return;
+			}
+		}
+	}
+}
 
 static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
 					  struct clk *clk, unsigned long target,
 					  struct dsi_setup_info *setup_info)
 {
 
-	const struct vco_cntrl_value *vco_cntrl;
+	const struct dsi_clk_config *clk_cfg;
 	unsigned long fout_target;
-	unsigned long fin, fout;
-	unsigned long hsfreq;
-	unsigned int best_err = -1;
-	unsigned int divider;
-	unsigned int n;
+	unsigned long fin_rate;
 	unsigned int i;
 	unsigned int err;
 
@@ -198,70 +397,53 @@ static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
 	 */
 	fout_target = target * mipi_dsi_pixel_format_to_bpp(dsi->format)
 		    / (2 * dsi->lanes);
-	if (fout_target < 40000000 || fout_target > 1250000000)
+	if (fout_target < MHZ(40) || fout_target > MHZ(1250))
 		return;
 
-	/* Find vco_cntrl */
-	for (vco_cntrl = vco_cntrl_table; vco_cntrl->min_freq != 0; vco_cntrl++) {
-		if (fout_target > vco_cntrl->min_freq &&
-		    fout_target <= vco_cntrl->max_freq) {
-			setup_info->vco_cntrl = vco_cntrl->value;
-			if (fout_target >= 1150000000)
-				setup_info->prop_cntrl = 0x0c;
-			else
-				setup_info->prop_cntrl = 0x0b;
+	/* Find PLL settings */
+	for (clk_cfg = dsi->info->clk_cfg; clk_cfg->min_freq != 0; clk_cfg++) {
+		if (fout_target > clk_cfg->min_freq &&
+		    fout_target <= clk_cfg->max_freq) {
+			setup_info->clkset = clk_cfg;
 			break;
 		}
 	}
 
-	/* Add divider */
-	setup_info->div = (setup_info->vco_cntrl & 0x30) >> 4;
+	fin_rate = clk_get_rate(clk);
+
+	switch (dsi->info->model) {
+	case RCAR_DSI_V3U:
+	default:
+		setup_info->vclk_divider = 1 << ((clk_cfg->vco_cntrl >> 4) & 0x3);
+		break;
+
+	case RCAR_DSI_V4H:
+		setup_info->vclk_divider = 1 << (((clk_cfg->vco_cntrl >> 3) & 0x7) + 1);
+		break;
+	}
+
+	rcar_mipi_dsi_pll_calc(dsi, fin_rate, fout_target, setup_info);
 
 	/* Find hsfreqrange */
-	hsfreq = fout_target * 2;
+	setup_info->hsfreq = setup_info->fout * 2;
 	for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++) {
-		if (hsfreqrange_table[i][0] >= hsfreq) {
+		if (hsfreqrange_table[i][0] >= setup_info->hsfreq) {
 			setup_info->hsfreqrange = hsfreqrange_table[i][1];
 			break;
 		}
 	}
 
-	/*
-	 * Calculate n and m for PLL clock
-	 * Following the HW manual the ranges of n and m are
-	 * n = [3-8] and m = [64-625]
-	 */
-	fin = clk_get_rate(clk);
-	divider = 1 << setup_info->div;
-	for (n = 3; n < 9; n++) {
-		unsigned long fpfd;
-		unsigned int m;
-
-		fpfd = fin / n;
-
-		for (m = 64; m < 626; m++) {
-			fout = fpfd * m / divider;
-			err = abs((long)(fout - fout_target) * 10000 /
-				  (long)fout_target);
-			if (err < best_err) {
-				setup_info->m = m - 2;
-				setup_info->n = n - 1;
-				setup_info->fout = fout;
-				best_err = err;
-				if (err == 0)
-					goto done;
-			}
-		}
-	}
+	err = abs((long)(setup_info->fout - fout_target) * 10000 / (long)fout_target);
 
-done:
 	dev_dbg(dsi->dev,
-		"%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/DIV %u/%u/%u\n",
-		clk, fin, setup_info->fout, fout_target, best_err / 100,
-		best_err % 100, setup_info->m, setup_info->n, setup_info->div);
+		"Fout = %u * %lu / (%u * %u * %u) = %lu (target %lu Hz, error %d.%02u%%)\n",
+		setup_info->m, fin_rate, dsi->info->n_mul, setup_info->n,
+		setup_info->vclk_divider, setup_info->fout, fout_target,
+		err / 100, err % 100);
+
 	dev_dbg(dsi->dev,
 		"vco_cntrl = 0x%x\tprop_cntrl = 0x%x\thsfreqrange = 0x%x\n",
-		setup_info->vco_cntrl, setup_info->prop_cntrl,
+		clk_cfg->vco_cntrl, clk_cfg->prop_cntrl,
 		setup_info->hsfreqrange);
 }
 
@@ -324,7 +506,7 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 {
 	struct dsi_setup_info setup_info = {};
 	unsigned int timeout;
-	int ret, i;
+	int ret;
 	int dsi_format;
 	u32 phy_setup;
 	u32 clockset2, clockset3;
@@ -360,10 +542,19 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 	phy_setup |= PHYSETUP_HSFREQRANGE(setup_info.hsfreqrange);
 	rcar_mipi_dsi_write(dsi, PHYSETUP, phy_setup);
 
-	for (i = 0; i < ARRAY_SIZE(phtw); i++) {
-		ret = rcar_mipi_dsi_phtw_test(dsi, phtw[i]);
+	switch (dsi->info->model) {
+	case RCAR_DSI_V3U:
+	default:
+		ret = rcar_mipi_dsi_init_phtw_v3u(dsi);
 		if (ret < 0)
 			return ret;
+		break;
+
+	case RCAR_DSI_V4H:
+		ret = rcar_mipi_dsi_init_phtw_v4h(dsi, &setup_info);
+		if (ret < 0)
+			return ret;
+		break;
 	}
 
 	/* PLL Clock Setting */
@@ -371,12 +562,13 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 	rcar_mipi_dsi_set(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
 	rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
 
-	clockset2 = CLOCKSET2_M(setup_info.m) | CLOCKSET2_N(setup_info.n)
-		  | CLOCKSET2_VCO_CNTRL(setup_info.vco_cntrl);
-	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.prop_cntrl)
-		  | CLOCKSET3_INT_CNTRL(0)
-		  | CLOCKSET3_CPBIAS_CNTRL(0x10)
-		  | CLOCKSET3_GMP_CNTRL(1);
+	clockset2 = CLOCKSET2_M(setup_info.m - dsi->info->clockset2_m_offset)
+		  | CLOCKSET2_N(setup_info.n - 1)
+		  | CLOCKSET2_VCO_CNTRL(setup_info.clkset->vco_cntrl);
+	clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.clkset->prop_cntrl)
+		  | CLOCKSET3_INT_CNTRL(setup_info.clkset->int_cntrl)
+		  | CLOCKSET3_CPBIAS_CNTRL(setup_info.clkset->cpbias_cntrl)
+		  | CLOCKSET3_GMP_CNTRL(setup_info.clkset->gmp_cntrl);
 	rcar_mipi_dsi_write(dsi, CLOCKSET2, clockset2);
 	rcar_mipi_dsi_write(dsi, CLOCKSET3, clockset3);
 
@@ -407,10 +599,19 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 		return -ETIMEDOUT;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(phtw2); i++) {
-		ret = rcar_mipi_dsi_phtw_test(dsi, phtw2[i]);
+	switch (dsi->info->model) {
+	case RCAR_DSI_V3U:
+	default:
+		ret = rcar_mipi_dsi_post_init_phtw_v3u(dsi);
+		if (ret < 0)
+			return ret;
+		break;
+
+	case RCAR_DSI_V4H:
+		ret = rcar_mipi_dsi_post_init_phtw_v4h(dsi, &setup_info);
 		if (ret < 0)
 			return ret;
+		break;
 	}
 
 	/* Enable DOT clock */
@@ -427,8 +628,19 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
 		dev_warn(dsi->dev, "unsupported format");
 		return -EINVAL;
 	}
-	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_DIV(setup_info.div)
-		|  VCLKSET_LANE(dsi->lanes - 1);
+
+	vclkset |= VCLKSET_COLOR_RGB | VCLKSET_LANE(dsi->lanes - 1);
+
+	switch (dsi->info->model) {
+	case RCAR_DSI_V3U:
+	default:
+		vclkset |= VCLKSET_DIV_V3U(__ffs(setup_info.vclk_divider));
+		break;
+
+	case RCAR_DSI_V4H:
+		vclkset |= VCLKSET_DIV_V4H(__ffs(setup_info.vclk_divider) - 1);
+		break;
+	}
 
 	rcar_mipi_dsi_write(dsi, VCLKSET, vclkset);
 
@@ -841,8 +1053,39 @@ static int rcar_mipi_dsi_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct rcar_mipi_dsi_device_info v3u_data = {
+	.model = RCAR_DSI_V3U,
+	.clk_cfg = dsi_clk_cfg_v3u,
+	.clockset2_m_offset = 2,
+	.n_min = 3,
+	.n_max = 8,
+	.n_mul = 1,
+	.fpfd_min = MHZ(2),
+	.fpfd_max = MHZ(8),
+	.m_min = 64,
+	.m_max = 625,
+	.fout_min = MHZ(320),
+	.fout_max = MHZ(1250),
+};
+
+static const struct rcar_mipi_dsi_device_info v4h_data = {
+	.model = RCAR_DSI_V4H,
+	.clk_cfg = dsi_clk_cfg_v4h,
+	.clockset2_m_offset = 0,
+	.n_min = 1,
+	.n_max = 8,
+	.n_mul = 2,
+	.fpfd_min = MHZ(8),
+	.fpfd_max = MHZ(24),
+	.m_min = 167,
+	.m_max = 1000,
+	.fout_min = MHZ(2000),
+	.fout_max = MHZ(4000),
+};
+
 static const struct of_device_id rcar_mipi_dsi_of_table[] = {
-	{ .compatible = "renesas,r8a779a0-dsi-csi2-tx" },
+	{ .compatible = "renesas,r8a779a0-dsi-csi2-tx", .data = &v3u_data },
+	{ .compatible = "renesas,r8a779g0-dsi-csi2-tx", .data = &v4h_data },
 	{ }
 };
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
index 2eaca54636f3..f8114d11f2d1 100644
--- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
@@ -122,7 +122,8 @@
 #define VCLKSET_CKEN			(1 << 16)
 #define VCLKSET_COLOR_RGB		(0 << 8)
 #define VCLKSET_COLOR_YCC		(1 << 8)
-#define VCLKSET_DIV(x)			(((x) & 0x3) << 4)
+#define VCLKSET_DIV_V3U(x)		(((x) & 0x3) << 4)
+#define VCLKSET_DIV_V4H(x)		(((x) & 0x7) << 4)
 #define VCLKSET_BPP_16			(0 << 2)
 #define VCLKSET_BPP_18			(1 << 2)
 #define VCLKSET_BPP_18L			(2 << 2)
@@ -166,6 +167,9 @@
 #define PHTW_CWEN			(1 << 8)
 #define PHTW_TESTDIN_CODE(x)		(((x) & 0xff) << 0)
 
+#define PHTR				0x1038
+#define PHTR_TEST			(1 << 16)
+
 #define PHTC				0x103c
 #define PHTC_TESTCLR			(1 << 0)
 
-- 
2.34.1


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

* Re: [PATCH v2 3/7] clk: renesas: r8a779g0: Add display related clocks
  2022-11-23  6:59 ` [PATCH v2 3/7] clk: renesas: r8a779g0: Add display related clocks Tomi Valkeinen
@ 2022-11-30 19:18   ` Geert Uytterhoeven
  2022-12-01  9:06     ` Tomi Valkeinen
  2022-12-01  9:26     ` Tomi Valkeinen
  0 siblings, 2 replies; 25+ messages in thread
From: Geert Uytterhoeven @ 2022-11-30 19:18 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel, Andrzej Hajda,
	Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec

Hi Tomi,

On Wed, Nov 23, 2022 at 8:00 AM Tomi Valkeinen
<tomi.valkeinen+renesas@ideasonboard.com> wrote:
> Add clocks related to display which are needed to get the DSI output
> working.
>
> Extracted from Renesas BSP tree.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Thanks for your patch!

> --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c
> +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c
> @@ -145,6 +145,8 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = {
>         DEF_FIXED("viobusd2",   R8A779G0_CLK_VIOBUSD2,  CLK_VIO,        2, 1),
>         DEF_FIXED("vcbus",      R8A779G0_CLK_VCBUS,     CLK_VC,         1, 1),
>         DEF_FIXED("vcbusd2",    R8A779G0_CLK_VCBUSD2,   CLK_VC,         2, 1),
> +       DEF_FIXED("dsiref",     R8A779G0_CLK_DSIREF,    CLK_PLL5_DIV4,  48, 1),
> +       DEF_DIV6P1("dsiext",    R8A779G0_CLK_DSIEXT,    CLK_PLL5_DIV4,  0x884),
>
>         DEF_GEN4_SDH("sd0h",    R8A779G0_CLK_SD0H,      CLK_SDSRC,         0x870),
>         DEF_GEN4_SD("sd0",      R8A779G0_CLK_SD0,       R8A779G0_CLK_SD0H, 0x870),
> @@ -161,6 +163,14 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
>         DEF_MOD("avb0",         211,    R8A779G0_CLK_S0D4_HSC),
>         DEF_MOD("avb1",         212,    R8A779G0_CLK_S0D4_HSC),
>         DEF_MOD("avb2",         213,    R8A779G0_CLK_S0D4_HSC),
> +

Weird horizontal and vertical spacing below...

> +       DEF_MOD("dis0",                 411,    R8A779G0_CLK_S0D3),

I doubt this parent clock is correct.
Based on Table 8.1.4e ("Lists of CPG clocks generated from PLL5"),
this should be one of the VIOBUS clocks.
VIOBUSD2 has the same rate as S0D3, so I'd use that one.

> +       DEF_MOD("dsitxlink0",           415,    R8A779G0_CLK_DSIREF),
> +       DEF_MOD("dsitxlink1",           416,    R8A779G0_CLK_DSIREF),
> +
> +       DEF_MOD("fcpvd0",               508,    R8A779G0_CLK_S0D3),
> +       DEF_MOD("fcpvd1",               509,    R8A779G0_CLK_S0D3),

Likewise.

> +
>         DEF_MOD("hscif0",       514,    R8A779G0_CLK_SASYNCPERD1),
>         DEF_MOD("hscif1",       515,    R8A779G0_CLK_SASYNCPERD1),
>         DEF_MOD("hscif2",       516,    R8A779G0_CLK_SASYNCPERD1),
> @@ -193,6 +203,10 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
>         DEF_MOD("tmu3",         716,    R8A779G0_CLK_SASYNCPERD2),
>         DEF_MOD("tmu4",         717,    R8A779G0_CLK_SASYNCPERD2),
>         DEF_MOD("tpu0",         718,    R8A779G0_CLK_SASYNCPERD4),
> +
> +       DEF_MOD("vspd0",                830,    R8A779G0_CLK_S0D1_VIO),
> +       DEF_MOD("vspd1",                831,    R8A779G0_CLK_S0D1_VIO),

While S0D1_VIO is a VIO clock, it is clocked from PLL1, which supports
spread-spectrum, unlike PLL5.
Again, based on Table 8.1.4e ("Lists of CPG clocks generated from
PLL5"), this should be one of the VIOBUS clocks.

Not that all of this matters a lot: all of these parents are always-on,
and I think "dis0" is the only clock where we care about the actual
clock rate?

> +
>         DEF_MOD("wdt1:wdt0",    907,    R8A779G0_CLK_R),
>         DEF_MOD("cmt0",         910,    R8A779G0_CLK_R),
>         DEF_MOD("cmt1",         911,    R8A779G0_CLK_R),

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 3/7] clk: renesas: r8a779g0: Add display related clocks
  2022-11-30 19:18   ` Geert Uytterhoeven
@ 2022-12-01  9:06     ` Tomi Valkeinen
  2022-12-01  9:34       ` Geert Uytterhoeven
  2022-12-01  9:26     ` Tomi Valkeinen
  1 sibling, 1 reply; 25+ messages in thread
From: Tomi Valkeinen @ 2022-12-01  9:06 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel, Andrzej Hajda,
	Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec

Hi,

On 30/11/2022 21:18, Geert Uytterhoeven wrote:
> Hi Tomi,
> 
> On Wed, Nov 23, 2022 at 8:00 AM Tomi Valkeinen
> <tomi.valkeinen+renesas@ideasonboard.com> wrote:
>> Add clocks related to display which are needed to get the DSI output
>> working.
>>
>> Extracted from Renesas BSP tree.
>>
>> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
>> Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
>> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> Thanks for your patch!
> 
>> --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c
>> +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c
>> @@ -145,6 +145,8 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = {
>>          DEF_FIXED("viobusd2",   R8A779G0_CLK_VIOBUSD2,  CLK_VIO,        2, 1),
>>          DEF_FIXED("vcbus",      R8A779G0_CLK_VCBUS,     CLK_VC,         1, 1),
>>          DEF_FIXED("vcbusd2",    R8A779G0_CLK_VCBUSD2,   CLK_VC,         2, 1),
>> +       DEF_FIXED("dsiref",     R8A779G0_CLK_DSIREF,    CLK_PLL5_DIV4,  48, 1),
>> +       DEF_DIV6P1("dsiext",    R8A779G0_CLK_DSIEXT,    CLK_PLL5_DIV4,  0x884),
>>
>>          DEF_GEN4_SDH("sd0h",    R8A779G0_CLK_SD0H,      CLK_SDSRC,         0x870),
>>          DEF_GEN4_SD("sd0",      R8A779G0_CLK_SD0,       R8A779G0_CLK_SD0H, 0x870),
>> @@ -161,6 +163,14 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
>>          DEF_MOD("avb0",         211,    R8A779G0_CLK_S0D4_HSC),
>>          DEF_MOD("avb1",         212,    R8A779G0_CLK_S0D4_HSC),
>>          DEF_MOD("avb2",         213,    R8A779G0_CLK_S0D4_HSC),
>> +
> 
> Weird horizontal and vertical spacing below...

Yep. I added those to keep the lines more visible for me while working 
on this, but forgot to remove.

> 
>> +       DEF_MOD("dis0",                 411,    R8A779G0_CLK_S0D3),
> 
> I doubt this parent clock is correct.
> Based on Table 8.1.4e ("Lists of CPG clocks generated from PLL5"),
> this should be one of the VIOBUS clocks.
> VIOBUSD2 has the same rate as S0D3, so I'd use that one.

I'm pretty clueless about Renesas clocks, and I can't find a nice 
clock-tree picture from the docs, but looking at the table, what you say 
makes sense.

Both VIOBUS and VIOBUSD2 are marked to go to the video IPs, but with a 
bit of browsing, I can't find any more info about the clocking. Afaik, 
we don't care about the dis0 rate in the driver, so... Basically any 
clock will work here =). I'll pick VIOBUSD2 as you suggest (why would 
there be a /2 clock if it's not used...).

>> +       DEF_MOD("dsitxlink0",           415,    R8A779G0_CLK_DSIREF),
>> +       DEF_MOD("dsitxlink1",           416,    R8A779G0_CLK_DSIREF),
>> +
>> +       DEF_MOD("fcpvd0",               508,    R8A779G0_CLK_S0D3),
>> +       DEF_MOD("fcpvd1",               509,    R8A779G0_CLK_S0D3),
> 
> Likewise.

Ack.

>> +
>>          DEF_MOD("hscif0",       514,    R8A779G0_CLK_SASYNCPERD1),
>>          DEF_MOD("hscif1",       515,    R8A779G0_CLK_SASYNCPERD1),
>>          DEF_MOD("hscif2",       516,    R8A779G0_CLK_SASYNCPERD1),
>> @@ -193,6 +203,10 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
>>          DEF_MOD("tmu3",         716,    R8A779G0_CLK_SASYNCPERD2),
>>          DEF_MOD("tmu4",         717,    R8A779G0_CLK_SASYNCPERD2),
>>          DEF_MOD("tpu0",         718,    R8A779G0_CLK_SASYNCPERD4),
>> +
>> +       DEF_MOD("vspd0",                830,    R8A779G0_CLK_S0D1_VIO),
>> +       DEF_MOD("vspd1",                831,    R8A779G0_CLK_S0D1_VIO),
> 
> While S0D1_VIO is a VIO clock, it is clocked from PLL1, which supports
> spread-spectrum, unlike PLL5.
> Again, based on Table 8.1.4e ("Lists of CPG clocks generated from
> PLL5"), this should be one of the VIOBUS clocks.

Yep.

> Not that all of this matters a lot: all of these parents are always-on,
> and I think "dis0" is the only clock where we care about the actual
> clock rate?
No, of the clocks added above, in the drivers we only care about the 
dsiref rate. That's used for the DSI PLL, and that PLL is used as the 
DU's pclk.

  Tomi


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

* Re: [PATCH v2 4/7] arm64: dts: renesas: r8a779g0: Add display related nodes
  2022-11-23  6:59 ` [PATCH v2 4/7] arm64: dts: renesas: r8a779g0: Add display related nodes Tomi Valkeinen
@ 2022-12-01  9:20   ` Geert Uytterhoeven
  0 siblings, 0 replies; 25+ messages in thread
From: Geert Uytterhoeven @ 2022-12-01  9:20 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Magnus Damm, dri-devel, linux-renesas-soc,
	devicetree, linux-kernel, Andrzej Hajda, Neil Armstrong,
	Robert Foss, Jonas Karlman, Jernej Skrabec

On Wed, Nov 23, 2022 at 8:00 AM Tomi Valkeinen
<tomi.valkeinen+renesas@ideasonboard.com> wrote:
> Add DT nodes for components needed to get the DSI output working:
> - FCPv
> - VSPd
> - DU
> - DSI
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-devel for v6.3.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 3/7] clk: renesas: r8a779g0: Add display related clocks
  2022-11-30 19:18   ` Geert Uytterhoeven
  2022-12-01  9:06     ` Tomi Valkeinen
@ 2022-12-01  9:26     ` Tomi Valkeinen
  2022-12-01  9:45       ` Geert Uytterhoeven
  1 sibling, 1 reply; 25+ messages in thread
From: Tomi Valkeinen @ 2022-12-01  9:26 UTC (permalink / raw)
  To: Geert Uytterhoeven, Laurent Pinchart
  Cc: Kieran Bingham, Rob Herring, Krzysztof Kozlowski,
	Geert Uytterhoeven, Magnus Damm, dri-devel, linux-renesas-soc,
	devicetree, linux-kernel, Andrzej Hajda, Neil Armstrong,
	Robert Foss, Jonas Karlman, Jernej Skrabec

Hi Geert, Laurent,

On 30/11/2022 21:18, Geert Uytterhoeven wrote:
> Hi Tomi,
> 
> On Wed, Nov 23, 2022 at 8:00 AM Tomi Valkeinen
> <tomi.valkeinen+renesas@ideasonboard.com> wrote:
>> Add clocks related to display which are needed to get the DSI output
>> working.
>>
>> Extracted from Renesas BSP tree.
>>
>> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
>> Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
>> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> Thanks for your patch!
> 
>> --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c
>> +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c
>> @@ -145,6 +145,8 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = {
>>          DEF_FIXED("viobusd2",   R8A779G0_CLK_VIOBUSD2,  CLK_VIO,        2, 1),
>>          DEF_FIXED("vcbus",      R8A779G0_CLK_VCBUS,     CLK_VC,         1, 1),
>>          DEF_FIXED("vcbusd2",    R8A779G0_CLK_VCBUSD2,   CLK_VC,         2, 1),
>> +       DEF_FIXED("dsiref",     R8A779G0_CLK_DSIREF,    CLK_PLL5_DIV4,  48, 1),
>> +       DEF_DIV6P1("dsiext",    R8A779G0_CLK_DSIEXT,    CLK_PLL5_DIV4,  0x884),
>>
>>          DEF_GEN4_SDH("sd0h",    R8A779G0_CLK_SD0H,      CLK_SDSRC,         0x870),
>>          DEF_GEN4_SD("sd0",      R8A779G0_CLK_SD0,       R8A779G0_CLK_SD0H, 0x870),
>> @@ -161,6 +163,14 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
>>          DEF_MOD("avb0",         211,    R8A779G0_CLK_S0D4_HSC),
>>          DEF_MOD("avb1",         212,    R8A779G0_CLK_S0D4_HSC),
>>          DEF_MOD("avb2",         213,    R8A779G0_CLK_S0D4_HSC),
>> +
> 
> Weird horizontal and vertical spacing below...
> 
>> +       DEF_MOD("dis0",                 411,    R8A779G0_CLK_S0D3),
> 
> I doubt this parent clock is correct.
> Based on Table 8.1.4e ("Lists of CPG clocks generated from PLL5"),
> this should be one of the VIOBUS clocks.
> VIOBUSD2 has the same rate as S0D3, so I'd use that one.
> 
>> +       DEF_MOD("dsitxlink0",           415,    R8A779G0_CLK_DSIREF),
>> +       DEF_MOD("dsitxlink1",           416,    R8A779G0_CLK_DSIREF),

Now that you started questioning about the clocks, I started to wonder 
about the DSI clocks. They don't quite make sense to me, but here also I 
just assumed it's "fine" as I copied it and it works.

The VIOBUS & VIOBUSD2 are marked to as going to the DSI. But we don't 
actually mark any of the DSI clocks as coming from those sources.

DSIREF is quite clear, it's the source for DSI PLL.

DSIEXT goes to the DSI PHY and is also marked to be used for LP-TX.

In the DT we have now:

clocks = <&cpg CPG_MOD 415>,
	 <&cpg CPG_CORE R8A779G0_CLK_DSIEXT>,
	 <&cpg CPG_CORE R8A779G0_CLK_DSIREF>;
clock-names = "fck", "dsi", "pll";

The "dsi" clock name is a bit vague, but maybe it's "not fclk, not pll, 
but still needed for dsi"? =)

Is it ok to refer to DSIEXT & DSIREF like that, or should they be in the 
r8a779g0_mod_clks list? Or is that list for fclks only?

So the fclk in the dts is mod clock 415 (416 for the second dsi), which 
is dsitxlink0 or dsitxlink1. Well, those names don't quite make sense if 
it's a fclk.

I would rename those clocks to "dsi0" and "dsi1", and source them from 
R8A779G0_CLK_VIOBUSD2, similarly to the other video clocks.

Does the above make sense?

  Tomi


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

* Re: [PATCH v2 3/7] clk: renesas: r8a779g0: Add display related clocks
  2022-12-01  9:06     ` Tomi Valkeinen
@ 2022-12-01  9:34       ` Geert Uytterhoeven
  0 siblings, 0 replies; 25+ messages in thread
From: Geert Uytterhoeven @ 2022-12-01  9:34 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel, Andrzej Hajda,
	Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec

Hi Tomi,

On Thu, Dec 1, 2022 at 10:06 AM Tomi Valkeinen
<tomi.valkeinen+renesas@ideasonboard.com> wrote:
> On 30/11/2022 21:18, Geert Uytterhoeven wrote:
> > On Wed, Nov 23, 2022 at 8:00 AM Tomi Valkeinen
> > <tomi.valkeinen+renesas@ideasonboard.com> wrote:
> >> Add clocks related to display which are needed to get the DSI output
> >> working.
> >>
> >> Extracted from Renesas BSP tree.
> >>
> >> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> >> Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> >> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> > Not that all of this matters a lot: all of these parents are always-on,
> > and I think "dis0" is the only clock where we care about the actual
> > clock rate?
>
> No, of the clocks added above, in the drivers we only care about the
> dsiref rate. That's used for the DSI PLL, and that PLL is used as the
> DU's pclk.

IC. As the DU node has only a single clocks property, I thought that
clock is used to derive the pixel clock from.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 3/7] clk: renesas: r8a779g0: Add display related clocks
  2022-12-01  9:26     ` Tomi Valkeinen
@ 2022-12-01  9:45       ` Geert Uytterhoeven
  0 siblings, 0 replies; 25+ messages in thread
From: Geert Uytterhoeven @ 2022-12-01  9:45 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Geert Uytterhoeven, Magnus Damm, dri-devel,
	linux-renesas-soc, devicetree, linux-kernel, Andrzej Hajda,
	Neil Armstrong, Robert Foss, Jonas Karlman, Jernej Skrabec

Hi Tomi,

On Thu, Dec 1, 2022 at 10:26 AM Tomi Valkeinen
<tomi.valkeinen+renesas@ideasonboard.com> wrote:
> On 30/11/2022 21:18, Geert Uytterhoeven wrote:
> > On Wed, Nov 23, 2022 at 8:00 AM Tomi Valkeinen
> > <tomi.valkeinen+renesas@ideasonboard.com> wrote:
> >> Add clocks related to display which are needed to get the DSI output
> >> working.
> >>
> >> Extracted from Renesas BSP tree.
> >>
> >> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> >> Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> >> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> >> --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c
> >> +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c

> >> +       DEF_MOD("dis0",                 411,    R8A779G0_CLK_S0D3),
> >
> > I doubt this parent clock is correct.
> > Based on Table 8.1.4e ("Lists of CPG clocks generated from PLL5"),
> > this should be one of the VIOBUS clocks.
> > VIOBUSD2 has the same rate as S0D3, so I'd use that one.
> >
> >> +       DEF_MOD("dsitxlink0",           415,    R8A779G0_CLK_DSIREF),
> >> +       DEF_MOD("dsitxlink1",           416,    R8A779G0_CLK_DSIREF),
>
> Now that you started questioning about the clocks, I started to wonder
> about the DSI clocks. They don't quite make sense to me, but here also I
> just assumed it's "fine" as I copied it and it works.
>
> The VIOBUS & VIOBUSD2 are marked to as going to the DSI. But we don't
> actually mark any of the DSI clocks as coming from those sources.
>
> DSIREF is quite clear, it's the source for DSI PLL.
>
> DSIEXT goes to the DSI PHY and is also marked to be used for LP-TX.
>
> In the DT we have now:
>
> clocks = <&cpg CPG_MOD 415>,
>          <&cpg CPG_CORE R8A779G0_CLK_DSIEXT>,
>          <&cpg CPG_CORE R8A779G0_CLK_DSIREF>;
> clock-names = "fck", "dsi", "pll";
>
> The "dsi" clock name is a bit vague, but maybe it's "not fclk, not pll,
> but still needed for dsi"? =)
>
> Is it ok to refer to DSIEXT & DSIREF like that, or should they be in the

Sounds fine to me.

> r8a779g0_mod_clks list? Or is that list for fclks only?

That list is only for clocks which have a bit in an MSTPCR (module
stop control register, Section 9.2.3).  These are typically controlled
through the Clock Domain and Runtime PM (but not for the DU, as there
is always only a single node in DT, even when the DU has multiple module
clocks on R-Car Gen2/3).

Actually our abstraction may be a bit off: sometimes that bit may gate
multiple clocks leading to the module, but as that was never documented
well, we settled on a single functional clock only, which is the most
common case.

> So the fclk in the dts is mod clock 415 (416 for the second dsi), which
> is dsitxlink0 or dsitxlink1. Well, those names don't quite make sense if
> it's a fclk.
>
> I would rename those clocks to "dsi0" and "dsi1", and source them from
> R8A779G0_CLK_VIOBUSD2, similarly to the other video clocks.
>
> Does the above make sense?

Please keep the names, as that's how they are called in Section 9.2.3.5
("Module Stop Control Register 4 (MSTPCR4)").

Thanks!

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 5/7] arm64: dts: renesas: white-hawk-cpu: Add DP output support
  2022-11-23  6:59 ` [PATCH v2 5/7] arm64: dts: renesas: white-hawk-cpu: Add DP output support Tomi Valkeinen
@ 2022-12-01 10:03   ` Geert Uytterhoeven
  0 siblings, 0 replies; 25+ messages in thread
From: Geert Uytterhoeven @ 2022-12-01 10:03 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Laurent Pinchart, Kieran Bingham, Rob Herring,
	Krzysztof Kozlowski, Magnus Damm, dri-devel, linux-renesas-soc,
	devicetree, linux-kernel, Andrzej Hajda, Neil Armstrong,
	Robert Foss, Jonas Karlman, Jernej Skrabec

Hi Tomi,

On Wed, Nov 23, 2022 at 8:00 AM Tomi Valkeinen
<tomi.valkeinen+renesas@ideasonboard.com> wrote:
> Add DT nodes needed for the mini DP connector. The DP is driven by
> sn65dsi86, which in turn gets the pixel data from the SoC via DSI.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Thanks for your patch!

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-devel for v6.3, with the mini-dp-con node
moved up.

> --- a/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi
> +++ b/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi
> @@ -97,6 +97,15 @@ memory@600000000 {
>                 reg = <0x6 0x00000000 0x1 0x00000000>;
>         };
>
> +       reg_1p2v: regulator-1p2v {
> +               compatible = "regulator-fixed";
> +               regulator-name = "fixed-1.2V";
> +               regulator-min-microvolt = <1200000>;
> +               regulator-max-microvolt = <1200000>;
> +               regulator-boot-on;
> +               regulator-always-on;
> +       };
> +
>         reg_1p8v: regulator-1p8v {
>                 compatible = "regulator-fixed";
>                 regulator-name = "fixed-1.8V";
> @@ -114,6 +123,24 @@ reg_3p3v: regulator-3p3v {
>                 regulator-boot-on;
>                 regulator-always-on;
>         };
> +
> +       mini-dp-con {
> +               compatible = "dp-connector";
> +               label = "CN5";
> +               type = "mini";
> +
> +               port {
> +                       mini_dp_con_in: endpoint {
> +                               remote-endpoint = <&sn65dsi86_out>;
> +                       };
> +               };
> +       };

Moving up while applying to preserve sort order...

> +
> +       sn65dsi86_refclk: clk-x6 {
> +               compatible = "fixed-clock";
> +               #clock-cells = <0>;
> +               clock-frequency = <38400000>;
> +       };
>  };
>
>  &avb0 {

> @@ -172,6 +216,51 @@ eeprom@50 {
>         };
>  };
>
> +&i2c1 {
> +       pinctrl-0 = <&i2c1_pins>;
> +       pinctrl-names = "default";
> +
> +       status = "okay";
> +       clock-frequency = <400000>;
> +
> +       bridge@2c {

Ideally, this needs pinctrl for the intc_ex irq0 pin.
Unfortunately[1] is still in limbo as the naming of the alternate pins
is inconsistent.

> +               compatible = "ti,sn65dsi86";
> +               reg = <0x2c>;
> +
> +               clocks = <&sn65dsi86_refclk>;
> +               clock-names = "refclk";
> +
> +               interrupt-parent = <&intc_ex>;
> +               interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
> +
> +               enable-gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
> +
> +               vccio-supply = <&reg_1p8v>;
> +               vpll-supply = <&reg_1p8v>;
> +               vcca-supply = <&reg_1p2v>;
> +               vcc-supply = <&reg_1p2v>;
> +
> +               ports {
> +                       #address-cells = <1>;
> +                       #size-cells = <0>;
> +
> +                       port@0 {
> +                               reg = <0>;
> +                               sn65dsi86_in: endpoint {
> +                                       remote-endpoint = <&dsi0_out>;
> +                               };
> +                       };
> +
> +                       port@1 {
> +                               reg = <1>;
> +                               sn65dsi86_out: endpoint {
> +                                       remote-endpoint = <&mini_dp_con_in>;
> +                               };
> +                       };
> +               };
> +       };
> +};
> +
>  &mmc0 {
>         pinctrl-0 = <&mmc_pins>;
>         pinctrl-1 = <&mmc_pins>;

[1] "[PATCH/RFC] pinctrl: renesas: r8a779g0: Add INTC-EX pins, groups,
and function"
    https://lore.kernel.org/all/28fe05d41bea5a03ea6c8434f5a4fb6c80b48867.1664368425.git.geert+renesas@glider.be

Gr{oetje,eeting}s,

                                                Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                                            -- Linus Torvalds

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

end of thread, other threads:[~2022-12-01 10:03 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-23  6:59 [PATCH v2 0/7] Renesas V4H DSI & DP output support Tomi Valkeinen
2022-11-23  6:59 ` [PATCH v2 1/7] dt-bindings: display: renesas,du: Provide bindings for r8a779g0 Tomi Valkeinen
2022-11-23  6:59 ` [PATCH v2 2/7] dt-bindings: display: bridge: renesas,dsi-csi2-tx: Add r8a779g0 Tomi Valkeinen
2022-11-23  6:59 ` [PATCH v2 3/7] clk: renesas: r8a779g0: Add display related clocks Tomi Valkeinen
2022-11-30 19:18   ` Geert Uytterhoeven
2022-12-01  9:06     ` Tomi Valkeinen
2022-12-01  9:34       ` Geert Uytterhoeven
2022-12-01  9:26     ` Tomi Valkeinen
2022-12-01  9:45       ` Geert Uytterhoeven
2022-11-23  6:59 ` [PATCH v2 4/7] arm64: dts: renesas: r8a779g0: Add display related nodes Tomi Valkeinen
2022-12-01  9:20   ` Geert Uytterhoeven
2022-11-23  6:59 ` [PATCH v2 5/7] arm64: dts: renesas: white-hawk-cpu: Add DP output support Tomi Valkeinen
2022-12-01 10:03   ` Geert Uytterhoeven
2022-11-23  6:59 ` [PATCH v2 6/7] drm: rcar-du: Add r8a779g0 support Tomi Valkeinen
2022-11-23  6:59 ` [PATCH v2 7/7] drm: rcar-du: dsi: " Tomi Valkeinen
2022-11-29  1:49   ` Laurent Pinchart
2022-11-29 11:30     ` Tomi Valkeinen
2022-11-29 11:40       ` Biju Das
2022-11-29 11:49         ` Geert Uytterhoeven
2022-11-29 12:05       ` Laurent Pinchart
2022-11-29 12:59     ` Tomi Valkeinen
2022-11-29 13:41   ` [PATCH v3 7/7] drm: rcar-du: dsi: Add r8A779g0 support Tomi Valkeinen
2022-11-29 17:44     ` Laurent Pinchart
2022-11-30  8:08     ` [PATCH v4 " Tomi Valkeinen
2022-11-29  1:58 ` [PATCH v2 0/7] Renesas V4H DSI & DP output support Laurent Pinchart

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).