linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/9] Add DRM driver for StarFive SoC JH7110
@ 2023-06-02  7:40 Keith Zhao
  2023-06-02  7:40 ` [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem Keith Zhao
                   ` (9 more replies)
  0 siblings, 10 replies; 46+ messages in thread
From: Keith Zhao @ 2023-06-02  7:40 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Keith Zhao, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Hi,

This series is a DRM driver for StarFive SoC JH7110, which includes a
display controller driver for Verisilicon DC8200 and an HMDI driver.

We use GEM framework for buffer management and allocate memory by 
using DMA APIs.

The JH7110 display subsystem includes a display controller Verisilicon
DC8200 and an HDMI transmitter. The HDMI TX IP is designed for transmitting 
video and audio data from DC8200 to a display device. The HDMI TX IP 
consists of  the digital controller and the physical layer.

This series does not support HDMI audio driver.

Keith Zhao (9):
  dt-bindings: display: Add yamls for JH7110 display subsystem
  riscv: dts: starfive: jh7110: add dc&hdmi controller node
  drm/verisilicon: Add basic drm driver
  drm/verisilicon: Add gem driver for JH7110 SoC
  drm/verisilicon: Add mode config funcs
  drm/verisilicon: Add drm crtc funcs
  drm/verisilicon: Add drm plane funcs
  drm/verisilicon: Add verisilicon dc controller driver
  drm/verisilicon: Add starfive hdmi driver

 .../display/verisilicon/starfive-hdmi.yaml    |   93 +
 .../display/verisilicon/verisilicon-dc.yaml   |  110 +
 .../display/verisilicon/verisilicon-drm.yaml  |   42 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 MAINTAINERS                                   |    9 +
 .../jh7110-starfive-visionfive-2.dtsi         |   87 +
 arch/riscv/boot/dts/starfive/jh7110.dtsi      |   46 +
 drivers/gpu/drm/Kconfig                       |    2 +
 drivers/gpu/drm/Makefile                      |    1 +
 drivers/gpu/drm/verisilicon/Kconfig           |   24 +
 drivers/gpu/drm/verisilicon/Makefile          |   13 +
 drivers/gpu/drm/verisilicon/starfive_hdmi.c   |  928 ++++++++
 drivers/gpu/drm/verisilicon/starfive_hdmi.h   |  296 +++
 drivers/gpu/drm/verisilicon/vs_crtc.c         |  388 ++++
 drivers/gpu/drm/verisilicon/vs_crtc.h         |   74 +
 drivers/gpu/drm/verisilicon/vs_dc.c           | 1040 +++++++++
 drivers/gpu/drm/verisilicon/vs_dc.h           |   62 +
 drivers/gpu/drm/verisilicon/vs_dc_hw.c        | 2008 +++++++++++++++++
 drivers/gpu/drm/verisilicon/vs_dc_hw.h        |  496 ++++
 drivers/gpu/drm/verisilicon/vs_drv.c          |  301 +++
 drivers/gpu/drm/verisilicon/vs_drv.h          |   52 +
 drivers/gpu/drm/verisilicon/vs_fb.c           |  181 ++
 drivers/gpu/drm/verisilicon/vs_fb.h           |   15 +
 drivers/gpu/drm/verisilicon/vs_gem.c          |  372 +++
 drivers/gpu/drm/verisilicon/vs_gem.h          |   72 +
 drivers/gpu/drm/verisilicon/vs_plane.c        |  440 ++++
 drivers/gpu/drm/verisilicon/vs_plane.h        |   74 +
 drivers/gpu/drm/verisilicon/vs_type.h         |   72 +
 include/uapi/drm/drm_fourcc.h                 |   83 +
 include/uapi/drm/vs_drm.h                     |   50 +
 30 files changed, 7433 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
 create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
 create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
 create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
 create mode 100644 drivers/gpu/drm/verisilicon/Makefile
 create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.c
 create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_fb.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_fb.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_gem.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_gem.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
 create mode 100644 include/uapi/drm/vs_drm.h

-- 
2.34.1


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

* [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem
  2023-06-02  7:40 [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Keith Zhao
@ 2023-06-02  7:40 ` Keith Zhao
  2023-06-02 18:21   ` Conor Dooley
  2023-06-07  7:35   ` Krzysztof Kozlowski
  2023-06-02  7:40 ` [PATCH 2/9] riscv: dts: starfive: jh7110: add dc&hdmi controller node Keith Zhao
                   ` (8 subsequent siblings)
  9 siblings, 2 replies; 46+ messages in thread
From: Keith Zhao @ 2023-06-02  7:40 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Keith Zhao, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Add bindings for JH7110 display subsystem which
has a display controller verisilicon dc8200
and an HDMI interface.

Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
---
 .../display/verisilicon/starfive-hdmi.yaml    |  93 +++++++++++++++
 .../display/verisilicon/verisilicon-dc.yaml   | 110 ++++++++++++++++++
 .../display/verisilicon/verisilicon-drm.yaml  |  42 +++++++
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 MAINTAINERS                                   |   7 ++
 5 files changed, 254 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
 create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
 create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml

diff --git a/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml b/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
new file mode 100644
index 000000000000..c30b7954a355
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/verisilicon/starfive-hdmi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive HDMI transmiter
+
+description:
+  The StarFive SoC uses the HDMI signal transmiter based on innosilicon IP
+  to generate HDMI signal from its input and transmit the signal to the screen.
+
+maintainers:
+  - Keith Zhao <keith.zhao@starfivetech.com>
+  - ShengYang Chen <shengyang.chen@starfivetech.com>
+
+properties:
+  compatible:
+    const: starfive,hdmi
+
+  reg:
+    minItems: 1
+
+  interrupts:
+    items:
+      - description: The HDMI hot plug detection interrupt.
+
+  clocks:
+    items:
+      - description: System clock of HDMI module.
+      - description: Mclk clock of HDMI audio.
+      - description: Bclk clock of HDMI audio.
+      - description: Pixel clock generated by HDMI module.
+
+  clock-names:
+    items:
+      - const: sysclk
+      - const: mclk
+      - const: bclk
+      - const: pclk
+
+  resets:
+    items:
+      - description: Reset for HDMI module.
+
+  reset-names:
+    items:
+      - const: hdmi_tx
+
+  '#sound-dai-cells':
+    const: 0
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+    description:
+      Port node with one endpoint connected to a display connector node.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - '#sound-dai-cells'
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    hdmi: hdmi@29590000 {
+      compatible = "starfive,hdmi";
+      reg = <0x29590000 0x4000>;
+      interrupts = <99>;
+      clocks = <&voutcrg 17>,
+               <&voutcrg 15>,
+               <&voutcrg 16>,
+               <&hdmitx0_pixelclk>;
+      clock-names = "sysclk", "mclk","bclk","pclk";
+      resets = <&voutcrg 9>;
+      reset-names = "hdmi_tx";
+      #sound-dai-cells = <0>;
+      hdmi_in: port {
+          #address-cells = <1>;
+          #size-cells = <0>;
+          hdmi_input: endpoint@0 {
+            reg = <0>;
+            remote-endpoint = <&dc_out_dpi0>;
+          };
+      };
+    };
diff --git a/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
new file mode 100644
index 000000000000..1322502c4cde
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
@@ -0,0 +1,110 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-dc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive display controller
+
+description:
+  The StarFive SoC uses the display controller based on Verisilicon IP
+  to transfer the image data from a video memory
+  buffer to an external LCD interface.
+
+maintainers:
+  - Keith Zhao <keith.zhao@starfivetech.com>
+  - ShengYang Chen <shengyang.chen@starfivetech.com>
+
+properties:
+  compatible:
+    const: verisilicon,dc8200
+
+  reg:
+    maxItems: 3
+
+  interrupts:
+    items:
+      - description: The interrupt will be generated when DC finish one frame
+
+  clocks:
+    items:
+      - description: Clock for display system noc bus.
+      - description: Pixel clock for display channel 0.
+      - description: Pixel clock for display channel 1.
+      - description: Clock for axi interface of display controller.
+      - description: Core clock for display controller.
+      - description: Clock for ahb interface of display controller.
+      - description: External HDMI pixel clock.
+      - description: Parent clock for pixel clock
+
+  clock-names:
+    items:
+      - const: clk_vout_noc_disp
+      - const: clk_vout_pix0
+      - const: clk_vout_pix1
+      - const: clk_vout_axi
+      - const: clk_vout_core
+      - const: clk_vout_vout_ahb
+      - const: hdmitx0_pixel
+      - const: clk_vout_dc8200
+
+  resets:
+    items:
+      - description: Reset for axi interface of display controller.
+      - description: Reset for ahb interface of display controller.
+      - description: Core reset of display controller.
+
+  reset-names:
+    items:
+      - const: rst_vout_axi
+      - const: rst_vout_ahb
+      - const: rst_vout_core
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+    description:
+      Port node with one endpoint connected to a hdmi node.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    dc8200: dc8200@29400000 {
+      compatible = "verisilicon,dc8200";
+      reg = <0x29400000 0x100>,
+            <0x29400800 0x2000>,
+            <0x295B0000 0x90>;
+      interrupts = <95>;
+      clocks = <&syscrg 60>,
+               <&voutcrg 7>,
+               <&voutcrg 8>,
+               <&voutcrg 4>,
+               <&voutcrg 5>,
+               <&voutcrg 6>,
+               <&hdmitx0_pixelclk>,
+               <&voutcrg 1>;
+      clock-names = "clk_vout_noc_disp", "clk_vout_pix0", "clk_vout_pix1", "clk_vout_axi",
+                    "clk_vout_core", "clk_vout_vout_ahb", "hdmitx0_pixel","clk_vout_dc8200";
+      resets = <&voutcrg 0>,
+               <&voutcrg 1>,
+               <&voutcrg 2>;
+      reset-names = "rst_vout_axi","rst_vout_ahb","rst_vout_core";
+      dc_out: port {
+          #address-cells = <1>;
+          #size-cells = <0>;
+          dc_out_dpi0: endpoint@0 {
+              reg = <0>;
+              remote-endpoint = <&hdmi_input>;
+          };
+      };
+    };
diff --git a/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
new file mode 100644
index 000000000000..aed8d4af2c55
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-drm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Verisilicon DRM master device
+
+maintainers:
+  - Keith Zhao <keith.zhao@starfivetech.com>
+  - ShengYang Chen <shengyang.chen@starfivetech.com>
+
+description: |
+  The Verisilicon DRM master device is a virtual device needed to list all
+  display controller or other display interface nodes that comprise the
+  graphics subsystem.
+
+properties:
+  compatible:
+    const: verisilicon,display-subsystem
+
+  ports:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      maxItems: 1
+    description: |
+      Should contain a list of phandles pointing to display interface ports
+      of display controller devices. Display controller definitions as defined in
+      Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
+
+required:
+  - compatible
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    display-subsystem {
+        compatible = "verisilicon,display-subsystem";
+        ports = <&dc_out>;
+    };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 82d39ab0231b..52c04fd098be 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1436,6 +1436,8 @@ patternProperties:
     description: Variscite Ltd.
   "^vdl,.*":
     description: Van der Laan b.v.
+  "^verisilicon,.*":
+    description: Verisilicon Technologies, Inc.
   "^vertexcom,.*":
     description: Vertexcom Technologies, Inc.
   "^via,.*":
diff --git a/MAINTAINERS b/MAINTAINERS
index 2a0496448b7f..293aa13d484c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7049,6 +7049,13 @@ F:	Documentation/devicetree/bindings/display/brcm,bcm2835-*.yaml
 F:	drivers/gpu/drm/vc4/
 F:	include/uapi/drm/vc4_drm.h
 
+DRM DRIVERS FOR VERISILICON
+M:	Keith Zhao <keith.zhao@starfivetech.com>
+L:	dri-devel@lists.freedesktop.org
+S:	Maintained
+T:	git git://anongit.freedesktop.org/drm/drm-misc
+F:	Documentation/devicetree/bindings/display/verisilicon/
+
 DRM DRIVERS FOR VIVANTE GPU IP
 M:	Lucas Stach <l.stach@pengutronix.de>
 R:	Russell King <linux+etnaviv@armlinux.org.uk>
-- 
2.34.1


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

* [PATCH 2/9] riscv: dts: starfive: jh7110: add dc&hdmi controller node
  2023-06-02  7:40 [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Keith Zhao
  2023-06-02  7:40 ` [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem Keith Zhao
@ 2023-06-02  7:40 ` Keith Zhao
  2023-06-07  7:38   ` Krzysztof Kozlowski
  2023-06-02  7:40 ` [PATCH 3/9] drm/verisilicon: Add basic drm driver Keith Zhao
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 46+ messages in thread
From: Keith Zhao @ 2023-06-02  7:40 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Keith Zhao, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Add the dc controller and hdmi node for the Starfive JH7110 SoC.

Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
---
 .../jh7110-starfive-visionfive-2.dtsi         | 87 +++++++++++++++++++
 arch/riscv/boot/dts/starfive/jh7110.dtsi      | 46 ++++++++++
 2 files changed, 133 insertions(+)

diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
index 1155b97b593d..8dc6c8a15c59 100644
--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
@@ -31,6 +31,21 @@ memory@40000000 {
 		reg = <0x0 0x40000000 0x1 0x0>;
 	};
 
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0x0 0x20000000>;
+			alignment = <0x0 0x1000>;
+			alloc-ranges = <0x0 0x80000000 0x0 0x20000000>;
+			linux,cma-default;
+		};
+	};
+
 	gpio-restart {
 		compatible = "gpio-restart";
 		gpios = <&sysgpio 35 GPIO_ACTIVE_HIGH>;
@@ -214,6 +229,41 @@ GPOEN_DISABLE,
 			slew-rate = <0>;
 		};
 	};
+
+	hdmi_pins: hdmi-0 {
+		hdmi-scl-pins {
+			pinmux = <GPIOMUX(0, GPOUT_SYS_HDMI_DDC_SCL,
+					     GPOEN_SYS_HDMI_DDC_SCL,
+					     GPI_SYS_HDMI_DDC_SCL)>;
+			input-enable;
+			bias-pull-up;
+		};
+
+		hdmi-sda-pins {
+			pinmux = <GPIOMUX(1, GPOUT_SYS_HDMI_DDC_SDA,
+					     GPOEN_SYS_HDMI_DDC_SDA,
+					     GPI_SYS_HDMI_DDC_SDA)>;
+			input-enable;
+			bias-pull-up;
+		};
+
+		hdmi-cec-pins {
+			pinmux = <GPIOMUX(14, GPOUT_SYS_HDMI_CEC_SDA,
+					     GPOEN_SYS_HDMI_CEC_SDA,
+					     GPI_SYS_HDMI_CEC_SDA)>;
+			input-enable;
+			bias-pull-up;
+		};
+
+		hdmi-hpd-pins {
+			pinmux = <GPIOMUX(15, GPOUT_HIGH,
+					     GPOEN_ENABLE,
+					     GPI_SYS_HDMI_HPD)>;
+			input-enable;
+			bias-disable; /* external pull-up */
+		};
+	};
+
 };
 
 &uart0 {
@@ -221,3 +271,40 @@ &uart0 {
 	pinctrl-0 = <&uart0_pins>;
 	status = "okay";
 };
+
+&voutcrg {
+	status = "okay";
+};
+
+&display {
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_pins>;
+
+	hdmi_in: port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		hdmi_input: endpoint@0 {
+			reg = <0>;
+			remote-endpoint = <&dc_out_dpi0>;
+		};
+	};
+};
+
+&dc8200 {
+	status = "okay";
+
+	dc_out: port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		dc_out_dpi0: endpoint@0 {
+			reg = <0>;
+			remote-endpoint = <&hdmi_input>;
+		};
+
+	};
+};
diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
index 9acb5fb1716d..66be6e65a066 100644
--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
@@ -249,6 +249,11 @@ tdm_ext: tdm-ext-clock {
 		#clock-cells = <0>;
 	};
 
+	display: display-subsystem {
+		compatible = "verisilicon,display-subsystem";
+		ports = <&dc_out>;
+	};
+
 	soc {
 		compatible = "simple-bus";
 		interrupt-parent = <&plic>;
@@ -570,5 +575,46 @@ voutcrg: clock-controller@295c0000 {
 			#reset-cells = <1>;
 			power-domains = <&pwrc JH7110_PD_VOUT>;
 		};
+
+		dc8200: dc8200@29400000 {
+			compatible = "verisilicon,dc8200";
+			reg = <0x0 0x29400000 0x0 0x100>,
+			      <0x0 0x29400800 0x0 0x2000>,
+			      <0x0 0x295B0000 0x0 0x90>;
+			interrupts = <95>;
+			clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_DISP_AXI>,
+				<&voutcrg JH7110_VOUTCLK_DC8200_PIX0>,
+				<&voutcrg JH7110_VOUTCLK_DC8200_PIX1>,
+				<&voutcrg JH7110_VOUTCLK_DC8200_AXI>,
+				<&voutcrg JH7110_VOUTCLK_DC8200_CORE>,
+				<&voutcrg JH7110_VOUTCLK_DC8200_AHB>,
+				<&hdmitx0_pixelclk>,
+				<&voutcrg JH7110_VOUTCLK_DC8200_PIX>;
+			clock-names = "clk_vout_noc_disp",
+				"clk_vout_pix0","clk_vout_pix1",
+				"clk_vout_axi","clk_vout_core",
+				"clk_vout_vout_ahb","hdmitx0_pixel",
+				"clk_vout_dc8200";
+			resets = <&voutcrg JH7110_VOUTRST_DC8200_AXI>,
+				 <&voutcrg JH7110_VOUTRST_DC8200_AHB>,
+				 <&voutcrg JH7110_VOUTRST_DC8200_CORE>;
+			reset-names = "rst_vout_axi","rst_vout_ahb",
+						"rst_vout_core";
+		};
+
+		hdmi: hdmi@29590000 {
+			compatible = "starfive,hdmi";
+			reg = <0x0 0x29590000 0x0 0x4000>;
+			interrupts = <99>;
+
+			clocks = <&voutcrg JH7110_VOUTCLK_HDMI_TX_SYS>,
+				 <&voutcrg JH7110_VOUTCLK_HDMI_TX_MCLK>,
+				 <&voutcrg JH7110_VOUTCLK_HDMI_TX_BCLK>,
+				 <&hdmitx0_pixelclk>;
+			clock-names = "sysclk", "mclk","bclk","pclk";
+			resets = <&voutcrg JH7110_VOUTRST_HDMI_TX_HDMI>;
+			reset-names = "hdmi_tx";
+			#sound-dai-cells = <0>;
+		};
 	};
 };
-- 
2.34.1


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

* [PATCH 3/9] drm/verisilicon: Add basic drm driver
  2023-06-02  7:40 [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Keith Zhao
  2023-06-02  7:40 ` [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem Keith Zhao
  2023-06-02  7:40 ` [PATCH 2/9] riscv: dts: starfive: jh7110: add dc&hdmi controller node Keith Zhao
@ 2023-06-02  7:40 ` Keith Zhao
  2023-06-07  8:53   ` Lucas Stach
                     ` (2 more replies)
  2023-06-02  7:40 ` [PATCH 4/9] drm/verisilicon: Add gem driver for JH7110 SoC Keith Zhao
                   ` (6 subsequent siblings)
  9 siblings, 3 replies; 46+ messages in thread
From: Keith Zhao @ 2023-06-02  7:40 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Keith Zhao, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Add a basic platform driver of the DRM driver for JH7110 SoC.

Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
---
 MAINTAINERS                          |   2 +
 drivers/gpu/drm/Kconfig              |   2 +
 drivers/gpu/drm/Makefile             |   1 +
 drivers/gpu/drm/verisilicon/Kconfig  |  13 ++
 drivers/gpu/drm/verisilicon/Makefile |   6 +
 drivers/gpu/drm/verisilicon/vs_drv.c | 284 +++++++++++++++++++++++++++
 drivers/gpu/drm/verisilicon/vs_drv.h |  48 +++++
 include/uapi/drm/drm_fourcc.h        |  83 ++++++++
 include/uapi/drm/vs_drm.h            |  50 +++++
 9 files changed, 489 insertions(+)
 create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
 create mode 100644 drivers/gpu/drm/verisilicon/Makefile
 create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
 create mode 100644 include/uapi/drm/vs_drm.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 293aa13d484c..da5b6766a7bb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7055,6 +7055,8 @@ L:	dri-devel@lists.freedesktop.org
 S:	Maintained
 T:	git git://anongit.freedesktop.org/drm/drm-misc
 F:	Documentation/devicetree/bindings/display/verisilicon/
+F:	drivers/gpu/drm/verisilicon/
+F:	include/uapi/drm/vs_drm.h
 
 DRM DRIVERS FOR VIVANTE GPU IP
 M:	Lucas Stach <l.stach@pengutronix.de>
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index ba3fb04bb691..f7e461fa4656 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -371,6 +371,8 @@ source "drivers/gpu/drm/solomon/Kconfig"
 
 source "drivers/gpu/drm/sprd/Kconfig"
 
+source "drivers/gpu/drm/verisilicon/Kconfig"
+
 config DRM_HYPERV
 	tristate "DRM Support for Hyper-V synthetic video device"
 	depends on DRM && PCI && MMU && HYPERV
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index a33257d2bc7f..e50622ee4e46 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -194,3 +194,4 @@ obj-y			+= gud/
 obj-$(CONFIG_DRM_HYPERV) += hyperv/
 obj-y			+= solomon/
 obj-$(CONFIG_DRM_SPRD) += sprd/
+obj-$(CONFIG_DRM_VERISILICON) += verisilicon/
diff --git a/drivers/gpu/drm/verisilicon/Kconfig b/drivers/gpu/drm/verisilicon/Kconfig
new file mode 100644
index 000000000000..89d12185f73b
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config DRM_VERISILICON
+	tristate "DRM Support for VeriSilicon"
+	depends on DRM
+	select DRM_KMS_HELPER
+	select CMA
+	select DMA_CMA
+	help
+	  Choose this option if you have a VeriSilicon soc chipset.
+	  This driver provides VeriSilicon kernel mode
+	  setting and buffer management. It does not
+	  provide 2D or 3D acceleration.
diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
new file mode 100644
index 000000000000..64ce1b26546c
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+
+vs_drm-objs := vs_drv.o
+
+obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
+
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
new file mode 100644
index 000000000000..24d333598477
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_drv.c
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/iommu.h>
+#include <linux/of_graph.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/version.h>
+
+#include <drm/drm_aperture.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_debugfs.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_generic.h>
+#include <drm/drm_file.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_of.h>
+#include <drm/drm_prime.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "vs_drv.h"
+
+#define DRV_NAME	"starfive"
+#define DRV_DESC	"Starfive DRM driver"
+#define DRV_DATE	"202305161"
+#define DRV_MAJOR	1
+#define DRV_MINOR	0
+
+static struct platform_driver vs_drm_platform_driver;
+
+static const struct file_operations fops = {
+	.owner			= THIS_MODULE,
+	.open			= drm_open,
+	.release		= drm_release,
+	.unlocked_ioctl	= drm_ioctl,
+	.compat_ioctl	= drm_compat_ioctl,
+	.poll			= drm_poll,
+	.read			= drm_read,
+};
+
+static struct drm_driver vs_drm_driver = {
+	.driver_features	= DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
+	.lastclose		= drm_fb_helper_lastclose,
+	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+	.fops			= &fops,
+	.name			= DRV_NAME,
+	.desc			= DRV_DESC,
+	.date			= DRV_DATE,
+	.major			= DRV_MAJOR,
+	.minor			= DRV_MINOR,
+};
+
+void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
+				   unsigned int alignment)
+{
+	struct vs_drm_private *priv = drm_dev->dev_private;
+
+	if (alignment > priv->pitch_alignment)
+		priv->pitch_alignment = alignment;
+}
+
+static int vs_drm_bind(struct device *dev)
+{
+	struct drm_device *drm_dev;
+	struct vs_drm_private *priv;
+	int ret;
+	static u64 dma_mask = DMA_BIT_MASK(40);
+
+	/* Remove existing drivers that may own the framebuffer memory. */
+	ret = drm_aperture_remove_framebuffers(false, &vs_drm_driver);
+	if (ret) {
+		DRM_DEV_ERROR(dev,
+			      "Failed to remove existing framebuffers - %d.\n",
+			      ret);
+		return ret;
+	}
+
+	drm_dev = drm_dev_alloc(&vs_drm_driver, dev);
+	if (IS_ERR(drm_dev))
+		return PTR_ERR(drm_dev);
+
+	dev_set_drvdata(dev, drm_dev);
+
+	priv = devm_kzalloc(drm_dev->dev, sizeof(struct vs_drm_private),
+			    GFP_KERNEL);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto err_put_dev;
+	}
+
+	priv->pitch_alignment = 64;
+	priv->dma_dev = drm_dev->dev;
+	priv->dma_dev->coherent_dma_mask = dma_mask;
+	drm_dev->dev_private = priv;
+
+	drm_mode_config_init(drm_dev);
+
+	/* Now try and bind all our sub-components */
+	ret = component_bind_all(dev, drm_dev);
+	if (ret)
+		goto err_mode;
+
+	ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
+	if (ret)
+		goto err_bind;
+
+	drm_mode_config_reset(drm_dev);
+
+	drm_kms_helper_poll_init(drm_dev);
+
+	ret = drm_dev_register(drm_dev, 0);
+	if (ret)
+		goto err_helper;
+
+	drm_fbdev_generic_setup(drm_dev, 32);
+
+	return 0;
+
+err_helper:
+	drm_kms_helper_poll_fini(drm_dev);
+err_bind:
+	component_unbind_all(drm_dev->dev, drm_dev);
+err_mode:
+	drm_mode_config_cleanup(drm_dev);
+	if (priv->domain)
+		iommu_domain_free(priv->domain);
+err_put_dev:
+	drm_dev->dev_private = NULL;
+	dev_set_drvdata(dev, NULL);
+	drm_dev_put(drm_dev);
+	return ret;
+}
+
+static void vs_drm_unbind(struct device *dev)
+{
+	struct drm_device *drm_dev = dev_get_drvdata(dev);
+	struct vs_drm_private *priv = drm_dev->dev_private;
+
+	drm_dev_unregister(drm_dev);
+
+	drm_kms_helper_poll_fini(drm_dev);
+
+	component_unbind_all(drm_dev->dev, drm_dev);
+
+	drm_mode_config_cleanup(drm_dev);
+
+	if (priv->domain) {
+		iommu_domain_free(priv->domain);
+		priv->domain = NULL;
+	}
+
+	drm_dev->dev_private = NULL;
+	dev_set_drvdata(dev, NULL);
+	drm_dev_put(drm_dev);
+}
+
+static const struct component_master_ops vs_drm_ops = {
+	.bind = vs_drm_bind,
+	.unbind = vs_drm_unbind,
+};
+
+static struct platform_driver *drm_sub_drivers[] = {
+};
+
+#define NUM_DRM_DRIVERS \
+	(sizeof(drm_sub_drivers) / sizeof(struct platform_driver *))
+
+static int compare_dev(struct device *dev, void *data)
+{
+	return dev == (struct device *)data;
+}
+
+static struct component_match *vs_drm_match_add(struct device *dev)
+{
+	struct component_match *match = NULL;
+	int i;
+
+	for (i = 0; i < NUM_DRM_DRIVERS; ++i) {
+		struct platform_driver *drv = drm_sub_drivers[i];
+		struct device *p = NULL, *d;
+
+		while ((d = platform_find_device_by_driver(p, &drv->driver))) {
+			put_device(p);
+
+			component_match_add(dev, &match, compare_dev, d);
+			p = d;
+		}
+		put_device(p);
+	}
+
+	return match ?: ERR_PTR(-ENODEV);
+}
+
+static int vs_drm_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct component_match *match;
+
+	match = vs_drm_match_add(dev);
+	if (IS_ERR(match))
+		return PTR_ERR(match);
+
+	return component_master_add_with_match(dev, &vs_drm_ops, match);
+}
+
+static int vs_drm_platform_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &vs_drm_ops);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int vs_drm_suspend(struct device *dev)
+{
+	struct drm_device *drm = dev_get_drvdata(dev);
+
+	return drm_mode_config_helper_suspend(drm);
+}
+
+static int vs_drm_resume(struct device *dev)
+{
+	struct drm_device *drm = dev_get_drvdata(dev);
+
+	return drm_mode_config_helper_resume(drm);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(vs_drm_pm_ops, vs_drm_suspend, vs_drm_resume);
+
+static const struct of_device_id vs_drm_dt_ids[] = {
+	{ .compatible = "verisilicon,display-subsystem", },
+};
+
+MODULE_DEVICE_TABLE(of, vs_drm_dt_ids);
+
+static struct platform_driver vs_drm_platform_driver = {
+	.probe = vs_drm_platform_probe,
+	.remove = vs_drm_platform_remove,
+
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = vs_drm_dt_ids,
+		.pm = &vs_drm_pm_ops,
+	},
+};
+
+static int __init vs_drm_init(void)
+{
+	int ret;
+
+	ret = platform_register_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&vs_drm_platform_driver);
+	if (ret)
+		platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
+
+	return ret;
+}
+
+static void __exit vs_drm_fini(void)
+{
+	platform_driver_unregister(&vs_drm_platform_driver);
+	platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
+}
+
+module_init(vs_drm_init);
+module_exit(vs_drm_fini);
+
+MODULE_DESCRIPTION("VeriSilicon DRM Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
new file mode 100644
index 000000000000..0382b44e3bf0
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_drv.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_DRV_H__
+#define __VS_DRV_H__
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_gem.h>
+
+/*
+ *
+ * @dma_dev: device for DMA API.
+ *	- use the first attached device if support iommu
+	else use drm device (only contiguous buffer support)
+ * @domain: iommu domain for DRM.
+ *	- all DC IOMMU share same domain to reduce mapping
+ * @pitch_alignment: buffer pitch alignment required by sub-devices.
+ *
+ */
+struct vs_drm_private {
+	struct device *dma_dev;
+	struct iommu_domain *domain;
+	unsigned int pitch_alignment;
+};
+
+void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
+				   unsigned int alignment);
+
+static inline struct device *to_dma_dev(struct drm_device *dev)
+{
+	struct vs_drm_private *priv = dev->dev_private;
+
+	return priv->dma_dev;
+}
+
+static inline bool is_iommu_enabled(struct drm_device *dev)
+{
+	struct vs_drm_private *priv = dev->dev_private;
+
+	return priv->domain ? true : false;
+}
+
+#endif /* __VS_DRV_H__ */
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index de703c6be969..af4fb50f9207 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -419,6 +419,7 @@ extern "C" {
 #define DRM_FORMAT_MOD_VENDOR_ARM     0x08
 #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09
 #define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a
+#define DRM_FORMAT_MOD_VENDOR_VS      0x0b
 
 /* add more to the end as needed */
 
@@ -1519,6 +1520,88 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
 #define AMD_FMT_MOD_CLEAR(field) \
 	(~((__u64)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT))
 
+#define DRM_FORMAT_MOD_VS_TYPE_NORMAL        0x00
+#define DRM_FORMAT_MOD_VS_TYPE_COMPRESSED    0x01
+#define DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT  0x02
+#define DRM_FORMAT_MOD_VS_TYPE_MASK     ((__u64)0x3 << 54)
+
+#define fourcc_mod_vs_code(type, val) \
+	fourcc_mod_code(VS, ((((__u64)type) << 54) | (val)))
+
+#define DRM_FORMAT_MOD_VS_DEC_TILE_MODE_MASK    0x3F
+#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_XMAJOR   0x00
+#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_YMAJOR   0x01
+#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4     0x02
+#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4      0x03
+#define DRM_FORMAT_MOD_VS_DEC_TILE_4X8      0x04
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X4   0x06
+#define DRM_FORMAT_MOD_VS_DEC_TILE_64X4     0x07
+#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4     0x08
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X1  0x09
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X1  0x0A
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X4   0x0B
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X2  0x0C
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X2  0x0D
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X4  0x0E
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X1   0x0F
+#define DRM_FORMAT_MOD_VS_DEC_TILE_16X8     0x10
+#define DRM_FORMAT_MOD_VS_DEC_TILE_8X16     0x11
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_512X1  0x12
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X4   0x13
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X2   0x14
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X2   0x15
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X1   0x16
+#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X1   0x17
+#define DRM_FORMAT_MOD_VS_DEC_TILE_128X4    0x18
+#define DRM_FORMAT_MOD_VS_DEC_TILE_256X4    0x19
+#define DRM_FORMAT_MOD_VS_DEC_TILE_512X4    0x1A
+#define DRM_FORMAT_MOD_VS_DEC_TILE_16X16    0x1B
+#define DRM_FORMAT_MOD_VS_DEC_TILE_32X16    0x1C
+#define DRM_FORMAT_MOD_VS_DEC_TILE_64X16    0x1D
+#define DRM_FORMAT_MOD_VS_DEC_TILE_128X8    0x1E
+#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4_S    0x1F
+#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_S   0x20
+#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_S   0x21
+#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_LSB 0x22
+#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_LSB 0x23
+#define DRM_FORMAT_MOD_VS_DEC_TILE_32X8     0x24
+
+#define DRM_FORMAT_MOD_VS_DEC_ALIGN_32      (0x01 << 6)
+#define DRM_FORMAT_MOD_VS_DEC_ALIGN_64      (0x01 << 7)
+
+#define fourcc_mod_vs_dec_code(tile, align) \
+	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_COMPRESSED, \
+				((tile) | (align)))
+
+#define DRM_FORMAT_MOD_VS_NORM_MODE_MASK        0x1F
+#define DRM_FORMAT_MOD_VS_LINEAR                0x00
+#define DRM_FORMAT_MOD_VS_TILED4x4              0x01
+#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR    0x02
+#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR    0x03
+#define DRM_FORMAT_MOD_VS_TILE_8X8              0x04
+#define DRM_FORMAT_MOD_VS_TILE_MODE1            0x05
+#define DRM_FORMAT_MOD_VS_TILE_MODE2            0x06
+#define DRM_FORMAT_MOD_VS_TILE_8X4              0x07
+#define DRM_FORMAT_MOD_VS_TILE_MODE4            0x08
+#define DRM_FORMAT_MOD_VS_TILE_MODE5            0x09
+#define DRM_FORMAT_MOD_VS_TILE_MODE6            0x0A
+#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4    0x0B
+#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8    0x0C
+#define DRM_FORMAT_MOD_VS_TILE_Y                0x0D
+#define DRM_FORMAT_MOD_VS_TILE_128X1            0x0F
+#define DRM_FORMAT_MOD_VS_TILE_256X1            0x10
+#define DRM_FORMAT_MOD_VS_TILE_32X1             0x11
+#define DRM_FORMAT_MOD_VS_TILE_64X1             0x12
+#define DRM_FORMAT_MOD_VS_TILE_MODE4X4          0x15
+
+#define fourcc_mod_vs_norm_code(tile) \
+	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_NORMAL, \
+				(tile))
+
+#define fourcc_mod_vs_custom_code(tile) \
+	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT, \
+				(tile))
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/include/uapi/drm/vs_drm.h b/include/uapi/drm/vs_drm.h
new file mode 100644
index 000000000000..96b7fc95d658
--- /dev/null
+++ b/include/uapi/drm/vs_drm.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_DRM_H__
+#define __VS_DRM_H__
+
+#include "drm.h"
+
+enum drm_vs_degamma_mode {
+	VS_DEGAMMA_DISABLE = 0,
+	VS_DEGAMMA_BT709 = 1,
+	VS_DEGAMMA_BT2020 = 2,
+};
+
+enum drm_vs_sync_dc_mode {
+	VS_SINGLE_DC = 0,
+	VS_MULTI_DC_PRIMARY = 1,
+	VS_MULTI_DC_SECONDARY = 2,
+};
+
+enum drm_vs_mmu_prefetch_mode {
+	VS_MMU_PREFETCH_DISABLE = 0,
+	VS_MMU_PREFETCH_ENABLE = 1,
+};
+
+struct drm_vs_watermark {
+	__u32 watermark;
+	__u8 qos_low;
+	__u8 qos_high;
+};
+
+struct drm_vs_color_mgmt {
+	__u32 colorkey;
+	__u32 colorkey_high;
+	__u32 clear_value;
+	bool  clear_enable;
+	bool  transparency;
+};
+
+struct drm_vs_roi {
+	bool enable;
+	__u16 roi_x;
+	__u16 roi_y;
+	__u16 roi_w;
+	__u16 roi_h;
+};
+
+#endif /* __VS_DRM_H__ */
-- 
2.34.1


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

* [PATCH 4/9] drm/verisilicon: Add gem driver for JH7110 SoC
  2023-06-02  7:40 [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Keith Zhao
                   ` (2 preceding siblings ...)
  2023-06-02  7:40 ` [PATCH 3/9] drm/verisilicon: Add basic drm driver Keith Zhao
@ 2023-06-02  7:40 ` Keith Zhao
  2023-06-19 13:18   ` Thomas Zimmermann
  2023-06-19 14:22   ` Thomas Zimmermann
  2023-06-02  7:40 ` [PATCH 5/9] drm/verisilicon: Add mode config funcs Keith Zhao
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 46+ messages in thread
From: Keith Zhao @ 2023-06-02  7:40 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Keith Zhao, Jack Zhu, Shengyang Chen,
	Changhuang Liang

This patch implements gem related APIs for JH7100 SoC.

Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
---
 drivers/gpu/drm/verisilicon/Makefile |   3 +-
 drivers/gpu/drm/verisilicon/vs_drv.c |   6 +
 drivers/gpu/drm/verisilicon/vs_gem.c | 372 +++++++++++++++++++++++++++
 drivers/gpu/drm/verisilicon/vs_gem.h |  72 ++++++
 4 files changed, 452 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/verisilicon/vs_gem.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_gem.h

diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index 64ce1b26546c..30360e370e47 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
-vs_drm-objs := vs_drv.o
+vs_drm-objs := vs_drv.o \
+		vs_gem.o
 
 obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
 
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
index 24d333598477..e0a2fc43b55f 100644
--- a/drivers/gpu/drm/verisilicon/vs_drv.c
+++ b/drivers/gpu/drm/verisilicon/vs_drv.c
@@ -30,6 +30,7 @@
 #include <drm/drm_vblank.h>
 
 #include "vs_drv.h"
+#include "vs_gem.h"
 
 #define DRV_NAME	"starfive"
 #define DRV_DESC	"Starfive DRM driver"
@@ -47,6 +48,7 @@ static const struct file_operations fops = {
 	.compat_ioctl	= drm_compat_ioctl,
 	.poll			= drm_poll,
 	.read			= drm_read,
+	.mmap			= vs_gem_mmap,
 };
 
 static struct drm_driver vs_drm_driver = {
@@ -54,6 +56,10 @@ static struct drm_driver vs_drm_driver = {
 	.lastclose		= drm_fb_helper_lastclose,
 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+	.gem_prime_import	= vs_gem_prime_import,
+	.gem_prime_import_sg_table = vs_gem_prime_import_sg_table,
+	.gem_prime_mmap		= vs_gem_prime_mmap,
+	.dumb_create		= vs_gem_dumb_create,
 	.fops			= &fops,
 	.name			= DRV_NAME,
 	.desc			= DRV_DESC,
diff --git a/drivers/gpu/drm/verisilicon/vs_gem.c b/drivers/gpu/drm/verisilicon/vs_gem.c
new file mode 100644
index 000000000000..3f963471c1ab
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_gem.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#include <linux/dma-buf.h>
+#include <linux/of_reserved_mem.h>
+#include <drm/drm_gem_dma_helper.h>
+
+#include "vs_drv.h"
+#include "vs_gem.h"
+
+static const struct drm_gem_object_funcs vs_gem_default_funcs;
+
+static int vs_gem_alloc_buf(struct vs_gem_object *vs_obj)
+{
+	struct drm_device *dev = vs_obj->base.dev;
+	unsigned int nr_pages;
+	struct sg_table sgt;
+	int ret = -ENOMEM;
+
+	if (vs_obj->dma_addr) {
+		DRM_DEV_DEBUG_KMS(dev->dev, "already allocated.\n");
+		return 0;
+	}
+
+	vs_obj->dma_attrs = DMA_ATTR_WRITE_COMBINE | DMA_ATTR_FORCE_CONTIGUOUS
+			   | DMA_ATTR_NO_KERNEL_MAPPING;
+
+	nr_pages = vs_obj->size >> PAGE_SHIFT;
+
+	vs_obj->pages = kvmalloc_array(nr_pages, sizeof(struct page *),
+				       GFP_KERNEL | __GFP_ZERO);
+	if (!vs_obj->pages) {
+		DRM_DEV_ERROR(dev->dev, "failed to allocate pages.\n");
+		return -ENOMEM;
+	}
+
+	vs_obj->cookie = dma_alloc_attrs(to_dma_dev(dev), vs_obj->size,
+					 &vs_obj->dma_addr, GFP_KERNEL,
+					 vs_obj->dma_attrs);
+
+	if (!vs_obj->cookie) {
+		DRM_DEV_ERROR(dev->dev, "failed to allocate buffer.\n");
+		goto err_free;
+	}
+
+	vs_obj->iova = vs_obj->dma_addr;
+
+	ret = dma_get_sgtable_attrs(to_dma_dev(dev), &sgt,
+				    vs_obj->cookie, vs_obj->dma_addr,
+				    vs_obj->size, vs_obj->dma_attrs);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev->dev, "failed to get sgtable.\n");
+		goto err_mem_free;
+	}
+
+	if (drm_prime_sg_to_page_array(&sgt, vs_obj->pages, nr_pages)) {
+		DRM_DEV_ERROR(dev->dev, "invalid sgtable.\n");
+		ret = -EINVAL;
+		goto err_sgt_free;
+	}
+
+	sg_free_table(&sgt);
+
+	return 0;
+
+err_sgt_free:
+	sg_free_table(&sgt);
+err_mem_free:
+		dma_free_attrs(to_dma_dev(dev), vs_obj->size, vs_obj->cookie,
+			       vs_obj->dma_addr, vs_obj->dma_attrs);
+err_free:
+	kvfree(vs_obj->pages);
+
+	return ret;
+}
+
+static void vs_gem_free_buf(struct vs_gem_object *vs_obj)
+{
+	struct drm_device *dev = vs_obj->base.dev;
+
+	if (!vs_obj->dma_addr) {
+		DRM_DEV_DEBUG_KMS(dev->dev, "dma_addr is invalid.\n");
+		return;
+	}
+
+	dma_free_attrs(to_dma_dev(dev), vs_obj->size, vs_obj->cookie,
+		       (dma_addr_t)vs_obj->dma_addr,
+		       vs_obj->dma_attrs);
+
+	kvfree(vs_obj->pages);
+}
+
+static void vs_gem_free_object(struct drm_gem_object *obj)
+{
+	struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
+
+	if (obj->import_attach)
+		drm_prime_gem_destroy(obj, vs_obj->sgt);
+	else
+		vs_gem_free_buf(vs_obj);
+
+	drm_gem_object_release(obj);
+
+	kfree(vs_obj);
+}
+
+static struct vs_gem_object *vs_gem_alloc_object(struct drm_device *dev,
+						 size_t size)
+{
+	struct vs_gem_object *vs_obj;
+	struct drm_gem_object *obj;
+	int ret;
+
+	vs_obj = kzalloc(sizeof(*vs_obj), GFP_KERNEL);
+	if (!vs_obj)
+		return ERR_PTR(-ENOMEM);
+
+	vs_obj->size = size;
+	obj = &vs_obj->base;
+
+	ret = drm_gem_object_init(dev, obj, size);
+	if (ret)
+		goto err_free;
+
+	vs_obj->base.funcs = &vs_gem_default_funcs;
+
+	ret = drm_gem_create_mmap_offset(obj);
+	if (ret) {
+		drm_gem_object_release(obj);
+		goto err_free;
+	}
+
+	return vs_obj;
+
+err_free:
+	kfree(vs_obj);
+	return ERR_PTR(ret);
+}
+
+struct vs_gem_object *vs_gem_create_object(struct drm_device *dev,
+					   size_t size)
+{
+	struct vs_gem_object *vs_obj;
+	int ret;
+
+	size = PAGE_ALIGN(size);
+
+	vs_obj = vs_gem_alloc_object(dev, size);
+	if (IS_ERR(vs_obj))
+		return vs_obj;
+
+	ret = vs_gem_alloc_buf(vs_obj);
+	if (ret) {
+		drm_gem_object_release(&vs_obj->base);
+		kfree(vs_obj);
+		return ERR_PTR(ret);
+	}
+
+	return vs_obj;
+}
+
+static struct vs_gem_object *vs_gem_create_with_handle(struct drm_device *dev,
+						       struct drm_file *file,
+						       size_t size,
+						       unsigned int *handle)
+{
+	struct vs_gem_object *vs_obj;
+	struct drm_gem_object *obj;
+	int ret;
+
+	vs_obj = vs_gem_create_object(dev, size);
+	if (IS_ERR(vs_obj))
+		return vs_obj;
+
+	obj = &vs_obj->base;
+
+	ret = drm_gem_handle_create(file, obj, handle);
+
+	drm_gem_object_put(obj);
+
+	if (ret)
+		return ERR_PTR(ret);
+
+	return vs_obj;
+}
+
+static int vs_gem_mmap_obj(struct drm_gem_object *obj,
+			   struct vm_area_struct *vma)
+{
+	struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
+	struct drm_device *drm_dev = vs_obj->base.dev;
+	unsigned long vm_size;
+	int ret = 0;
+
+	vm_size = vma->vm_end - vma->vm_start;
+	if (vm_size > vs_obj->size)
+		return -EINVAL;
+
+	vma->vm_pgoff = 0;
+
+	/*
+	 * We allocated a struct page table for starfive_obj, so clear
+	 * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
+	 */
+	vm_flags_mod(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP, VM_PFNMAP);
+
+	vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
+
+	ret = dma_mmap_attrs(to_dma_dev(drm_dev), vma, vs_obj->cookie,
+			     vs_obj->dma_addr, vs_obj->size,
+			     vs_obj->dma_attrs);
+
+	if (ret)
+		drm_gem_vm_close(vma);
+
+	return ret;
+}
+
+struct sg_table *vs_gem_prime_get_sg_table(struct drm_gem_object *obj)
+{
+	struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
+
+	return drm_prime_pages_to_sg(obj->dev, vs_obj->pages,
+					 vs_obj->size >> PAGE_SHIFT);
+}
+
+int vs_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
+{
+	struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
+
+	void *vaddr = vs_obj->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING ?
+		       page_address(vs_obj->cookie) : vs_obj->cookie;
+
+	iosys_map_set_vaddr(map, vaddr);
+
+	return 0;
+}
+
+void vs_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
+{
+	/* Nothing to do */
+}
+
+static const struct vm_operations_struct vs_vm_ops = {
+	.open  = drm_gem_vm_open,
+	.close = drm_gem_vm_close,
+};
+
+static const struct drm_gem_object_funcs vs_gem_default_funcs = {
+	.free = vs_gem_free_object,
+	.get_sg_table = vs_gem_prime_get_sg_table,
+	.vmap = vs_gem_prime_vmap,
+	.vunmap = vs_gem_prime_vunmap,
+	.vm_ops = &vs_vm_ops,
+};
+
+int vs_gem_dumb_create(struct drm_file *file,
+		       struct drm_device *dev,
+		       struct drm_mode_create_dumb *args)
+{
+	struct vs_drm_private *priv = dev->dev_private;
+	struct vs_gem_object *vs_obj;
+	unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+
+	if (args->bpp % 10)
+		args->pitch = ALIGN(pitch, priv->pitch_alignment);
+	else
+		/* for costum 10bit format with no bit gaps */
+		args->pitch = pitch;
+	args->size = PAGE_ALIGN(args->pitch * args->height);
+	vs_obj = vs_gem_create_with_handle(dev, file, args->size,
+					   &args->handle);
+	return PTR_ERR_OR_ZERO(vs_obj);
+}
+
+struct drm_gem_object *vs_gem_prime_import(struct drm_device *dev,
+					   struct dma_buf *dma_buf)
+{
+	return drm_gem_prime_import_dev(dev, dma_buf, to_dma_dev(dev));
+}
+
+struct drm_gem_object *
+vs_gem_prime_import_sg_table(struct drm_device *dev,
+			     struct dma_buf_attachment *attach,
+			     struct sg_table *sgt)
+{
+	struct vs_gem_object *vs_obj;
+	int npages;
+	int ret;
+	struct scatterlist *s;
+	u32 i;
+	dma_addr_t expected;
+	size_t size = attach->dmabuf->size;
+
+	size = PAGE_ALIGN(size);
+
+	vs_obj = vs_gem_alloc_object(dev, size);
+	if (IS_ERR(vs_obj))
+		return ERR_CAST(vs_obj);
+
+	expected = sg_dma_address(sgt->sgl);
+	for_each_sg(sgt->sgl, s, sgt->nents, i) {
+		if (sg_dma_address(s) != expected) {
+			DRM_ERROR("sg_table is not contiguous");
+			ret = -EINVAL;
+			goto err;
+		}
+		if (sg_dma_len(s) & (PAGE_SIZE - 1)) {
+			ret = -EINVAL;
+			goto err;
+		}
+		if (i == 0)
+			vs_obj->iova = sg_dma_address(s);
+		expected = sg_dma_address(s) + sg_dma_len(s);
+	}
+
+	vs_obj->dma_addr = sg_dma_address(sgt->sgl);
+
+	npages = vs_obj->size >> PAGE_SHIFT;
+	vs_obj->pages = kvmalloc_array(npages, sizeof(struct page *),
+				       GFP_KERNEL);
+	if (!vs_obj->pages) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = drm_prime_sg_to_page_array(sgt, vs_obj->pages, npages);
+	if (ret)
+		goto err_free_page;
+
+	vs_obj->sgt = sgt;
+
+	return &vs_obj->base;
+
+err_free_page:
+	kvfree(vs_obj->pages);
+err:
+	vs_gem_free_object(&vs_obj->base);
+
+	return ERR_PTR(ret);
+}
+
+int vs_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+{
+	int ret = 0;
+
+	ret = drm_gem_mmap_obj(obj, obj->size, vma);
+	if (ret < 0)
+		return ret;
+
+	return vs_gem_mmap_obj(obj, vma);
+}
+
+int vs_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct drm_gem_object *obj;
+	int ret;
+
+	ret = drm_gem_mmap(filp, vma);
+	if (ret)
+		return ret;
+
+	obj = vma->vm_private_data;
+
+	if (obj->import_attach)
+		return dma_buf_mmap(obj->dma_buf, vma, 0);
+
+	return vs_gem_mmap_obj(obj, vma);
+}
diff --git a/drivers/gpu/drm/verisilicon/vs_gem.h b/drivers/gpu/drm/verisilicon/vs_gem.h
new file mode 100644
index 000000000000..3a6d7452cb06
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_gem.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_GEM_H__
+#define __VS_GEM_H__
+
+#include <linux/dma-buf.h>
+
+#include <drm/drm_gem.h>
+#include <drm/drm_prime.h>
+
+#include "vs_drv.h"
+/*
+ *
+ * @base: drm gem object.
+ * @size: size requested from user
+ * @cookie: cookie returned by dma_alloc_attrs
+ *	- not kernel virtual address with DMA_ATTR_NO_KERNEL_MAPPING
+ * @dma_addr: bus address(accessed by dma) to allocated memory region.
+ *	- this address could be physical address without IOMMU and
+ *	device address with IOMMU.
+ * @dma_attrs: attribute for DMA API
+ * @get_pages: flag for manually applying for non-contiguous memory.
+ * @pages: Array of backing pages.
+ * @sgt: Imported sg_table.
+ *
+ */
+struct vs_gem_object {
+	struct drm_gem_object	base;
+	size_t			size;
+	void			*cookie;
+	dma_addr_t		dma_addr;
+	u32				iova;
+	unsigned long	dma_attrs;
+	bool			get_pages;
+	struct page		**pages;
+	struct sg_table *sgt;
+};
+
+static inline
+struct vs_gem_object *to_vs_gem_object(struct drm_gem_object *obj)
+{
+	return container_of(obj, struct vs_gem_object, base);
+}
+
+struct vs_gem_object *vs_gem_create_object(struct drm_device *dev,
+					   size_t size);
+
+int vs_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map);
+void vs_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map);
+
+int vs_gem_prime_mmap(struct drm_gem_object *obj,
+		      struct vm_area_struct *vma);
+
+int vs_gem_dumb_create(struct drm_file *file_priv,
+		       struct drm_device *drm,
+		       struct drm_mode_create_dumb *args);
+
+int vs_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+
+struct sg_table *vs_gem_prime_get_sg_table(struct drm_gem_object *obj);
+
+struct drm_gem_object *vs_gem_prime_import(struct drm_device *dev,
+					   struct dma_buf *dma_buf);
+struct drm_gem_object *
+vs_gem_prime_import_sg_table(struct drm_device *dev,
+			     struct dma_buf_attachment *attach,
+			     struct sg_table *sgt);
+
+#endif /* __VS_GEM_H__ */
-- 
2.34.1


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

* [PATCH 5/9] drm/verisilicon: Add mode config funcs
  2023-06-02  7:40 [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Keith Zhao
                   ` (3 preceding siblings ...)
  2023-06-02  7:40 ` [PATCH 4/9] drm/verisilicon: Add gem driver for JH7110 SoC Keith Zhao
@ 2023-06-02  7:40 ` Keith Zhao
  2023-06-21 11:04   ` Thomas Zimmermann
  2023-06-02  7:40 ` [PATCH 6/9] drm/verisilicon: Add drm crtc funcs Keith Zhao
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 46+ messages in thread
From: Keith Zhao @ 2023-06-02  7:40 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Keith Zhao, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Add mode setting functions for JH7110 SoC.

Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
---
 drivers/gpu/drm/verisilicon/Makefile |   1 +
 drivers/gpu/drm/verisilicon/vs_drv.c |   3 +
 drivers/gpu/drm/verisilicon/vs_fb.c  | 181 +++++++++++++++++++++++++++
 drivers/gpu/drm/verisilicon/vs_fb.h  |  15 +++
 4 files changed, 200 insertions(+)
 create mode 100644 drivers/gpu/drm/verisilicon/vs_fb.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_fb.h

diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index 30360e370e47..38254dc5d98d 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 vs_drm-objs := vs_drv.o \
+		vs_fb.o \
 		vs_gem.o
 
 obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
index e0a2fc43b55f..d84aacd751bc 100644
--- a/drivers/gpu/drm/verisilicon/vs_drv.c
+++ b/drivers/gpu/drm/verisilicon/vs_drv.c
@@ -30,6 +30,7 @@
 #include <drm/drm_vblank.h>
 
 #include "vs_drv.h"
+#include "vs_fb.h"
 #include "vs_gem.h"
 
 #define DRV_NAME	"starfive"
@@ -118,6 +119,8 @@ static int vs_drm_bind(struct device *dev)
 	if (ret)
 		goto err_mode;
 
+	vs_mode_config_init(drm_dev);
+
 	ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
 	if (ret)
 		goto err_bind;
diff --git a/drivers/gpu/drm/verisilicon/vs_fb.c b/drivers/gpu/drm/verisilicon/vs_fb.c
new file mode 100644
index 000000000000..3e85f7365084
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_fb.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+
+#include "vs_fb.h"
+#include "vs_gem.h"
+
+#define fourcc_mod_vs_get_type(val) \
+	(((val) & DRM_FORMAT_MOD_VS_TYPE_MASK) >> 54)
+
+static struct drm_framebuffer_funcs vs_fb_funcs = {
+	.create_handle	= drm_gem_fb_create_handle,
+	.destroy	= drm_gem_fb_destroy,
+	.dirty		= drm_atomic_helper_dirtyfb,
+};
+
+static struct drm_framebuffer *
+vs_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd,
+	    struct vs_gem_object **obj, unsigned int num_planes)
+{
+	struct drm_framebuffer *fb;
+	int ret, i;
+
+	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
+	if (!fb)
+		return ERR_PTR(-ENOMEM);
+
+	drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
+
+	for (i = 0; i < num_planes; i++)
+		fb->obj[i] = &obj[i]->base;
+
+	ret = drm_framebuffer_init(dev, fb, &vs_fb_funcs);
+	if (ret) {
+		dev_err(dev->dev, "Failed to initialize framebuffer: %d\n",
+			ret);
+		kfree(fb);
+		return ERR_PTR(ret);
+	}
+
+	return fb;
+}
+
+static struct drm_framebuffer *vs_fb_create(struct drm_device *dev,
+					    struct drm_file *file_priv,
+					    const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	struct drm_framebuffer *fb;
+	const struct drm_format_info *info;
+	struct vs_gem_object *objs[MAX_NUM_PLANES];
+	struct drm_gem_object *obj;
+	unsigned int height, size;
+	unsigned char i, num_planes;
+	int ret = 0;
+
+	info = drm_get_format_info(dev, mode_cmd);
+	if (!info)
+		return ERR_PTR(-EINVAL);
+
+	num_planes = info->num_planes;
+	if (num_planes > MAX_NUM_PLANES)
+		return ERR_PTR(-EINVAL);
+
+	for (i = 0; i < num_planes; i++) {
+		obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
+		if (!obj) {
+			dev_err(dev->dev, "Failed to lookup GEM object.\n");
+			ret = -ENXIO;
+			goto err;
+		}
+
+		height = drm_format_info_plane_height(info,
+						      mode_cmd->height, i);
+
+		size = height * mode_cmd->pitches[i] + mode_cmd->offsets[i];
+
+		if (obj->size < size) {
+			drm_gem_object_put(obj);
+
+			ret = -EINVAL;
+			goto err;
+		}
+
+		objs[i] = to_vs_gem_object(obj);
+	}
+
+	fb = vs_fb_alloc(dev, mode_cmd, objs, i);
+	if (IS_ERR(fb)) {
+		ret = PTR_ERR(fb);
+		goto err;
+	}
+
+	return fb;
+
+err:
+	for (; i > 0; i--)
+		drm_gem_object_put(&objs[i - 1]->base);
+
+	return ERR_PTR(ret);
+}
+
+struct vs_gem_object *vs_fb_get_gem_obj(struct drm_framebuffer *fb,
+					unsigned char plane)
+{
+	if (plane > MAX_NUM_PLANES)
+		return NULL;
+
+	return to_vs_gem_object(fb->obj[plane]);
+}
+
+static const struct drm_format_info vs_formats[] = {
+	{.format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .char_per_block = { 20, 40, 0 },
+	 .block_w = { 4, 4, 0 }, .block_h = { 4, 4, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true},
+	{.format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .char_per_block = { 20, 20, 20 },
+	 .block_w = { 4, 4, 4 }, .block_h = { 4, 4, 4 }, .hsub = 1, .vsub = 1, .is_yuv = true},
+};
+
+static const struct drm_format_info *
+vs_lookup_format_info(const struct drm_format_info formats[],
+		      int num_formats, u32 format)
+{
+	int i;
+
+	for (i = 0; i < num_formats; i++) {
+		if (formats[i].format == format)
+			return &formats[i];
+	}
+
+	return NULL;
+}
+
+static const struct drm_format_info *
+vs_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
+{
+	if (fourcc_mod_vs_get_type(cmd->modifier[0]) ==
+		DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT)
+		return vs_lookup_format_info(vs_formats, ARRAY_SIZE(vs_formats),
+									 cmd->pixel_format);
+	else
+		return NULL;
+}
+
+static const struct drm_mode_config_funcs vs_mode_config_funcs = {
+	.fb_create			 = vs_fb_create,
+	.get_format_info	 = vs_get_format_info,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
+	.atomic_check		 = drm_atomic_helper_check,
+	.atomic_commit		 = drm_atomic_helper_commit,
+};
+
+static struct drm_mode_config_helper_funcs vs_mode_config_helpers = {
+	.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
+};
+
+void vs_mode_config_init(struct drm_device *dev)
+{
+	dev->mode_config.fb_modifiers_not_supported = false;
+
+	if (dev->mode_config.max_width == 0 ||
+	    dev->mode_config.max_height == 0) {
+		dev->mode_config.min_width  = 0;
+		dev->mode_config.min_height = 0;
+		dev->mode_config.max_width  = 4096;
+		dev->mode_config.max_height = 4096;
+	}
+	dev->mode_config.funcs = &vs_mode_config_funcs;
+	dev->mode_config.helper_private = &vs_mode_config_helpers;
+}
diff --git a/drivers/gpu/drm/verisilicon/vs_fb.h b/drivers/gpu/drm/verisilicon/vs_fb.h
new file mode 100644
index 000000000000..78dda8e42894
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_fb.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_FB_H__
+#define __VS_FB_H__
+
+#define MAX_NUM_PLANES		3 /* colour format plane */
+
+struct vs_gem_object *vs_fb_get_gem_obj(struct drm_framebuffer *fb,
+					unsigned char plane);
+
+void vs_mode_config_init(struct drm_device *dev);
+#endif /* __VS_FB_H__ */
-- 
2.34.1


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

* [PATCH 6/9] drm/verisilicon: Add drm crtc funcs
  2023-06-02  7:40 [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Keith Zhao
                   ` (4 preceding siblings ...)
  2023-06-02  7:40 ` [PATCH 5/9] drm/verisilicon: Add mode config funcs Keith Zhao
@ 2023-06-02  7:40 ` Keith Zhao
  2023-06-30 11:55   ` Thomas Zimmermann
  2023-06-02  7:40 ` [PATCH 7/9] drm/verisilicon: Add drm plane funcs Keith Zhao
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 46+ messages in thread
From: Keith Zhao @ 2023-06-02  7:40 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Keith Zhao, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Add crtc driver which implements crtc related operation functions.

Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
---
 drivers/gpu/drm/verisilicon/Makefile  |   1 +
 drivers/gpu/drm/verisilicon/vs_crtc.c | 388 ++++++++++++++++++++++++++
 drivers/gpu/drm/verisilicon/vs_crtc.h |  74 +++++
 drivers/gpu/drm/verisilicon/vs_type.h |  72 +++++
 4 files changed, 535 insertions(+)
 create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h

diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index 38254dc5d98d..bae5fbab9bbb 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 vs_drm-objs := vs_drv.o \
+		vs_crtc.o \
 		vs_fb.o \
 		vs_gem.o
 
diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c
new file mode 100644
index 000000000000..a9e742d7bd1a
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_crtc.c
@@ -0,0 +1,388 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/media-bus-format.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/vs_drm.h>
+
+#include "vs_crtc.h"
+
+void vs_crtc_destroy(struct drm_crtc *crtc)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+
+	drm_crtc_cleanup(crtc);
+	kfree(vs_crtc);
+}
+
+static void vs_crtc_reset(struct drm_crtc *crtc)
+{
+	struct vs_crtc_state *state;
+
+	if (crtc->state) {
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+		state = to_vs_crtc_state(crtc->state);
+		kfree(state);
+		crtc->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return;
+
+	__drm_atomic_helper_crtc_reset(crtc, &state->base);
+
+	state->sync_mode = VS_SINGLE_DC;
+	state->output_fmt = MEDIA_BUS_FMT_RBG888_1X24;
+	state->encoder_type = DRM_MODE_ENCODER_NONE;
+}
+
+static struct drm_crtc_state *
+vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
+{
+	struct vs_crtc_state *ori_state;
+	struct vs_crtc_state *state;
+
+	if (WARN_ON(!crtc->state))
+		return NULL;
+
+	ori_state = to_vs_crtc_state(crtc->state);
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+
+	state->sync_mode = ori_state->sync_mode;
+	state->output_fmt = ori_state->output_fmt;
+	state->encoder_type = ori_state->encoder_type;
+	state->bg_color = ori_state->bg_color;
+	state->bpp = ori_state->bpp;
+	state->sync_enable = ori_state->sync_enable;
+	state->dither_enable = ori_state->dither_enable;
+	state->underflow = ori_state->underflow;
+
+	return &state->base;
+}
+
+static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
+					 struct drm_crtc_state *state)
+{
+	__drm_atomic_helper_crtc_destroy_state(state);
+	kfree(to_vs_crtc_state(state));
+}
+
+static int vs_crtc_atomic_set_property(struct drm_crtc *crtc,
+				       struct drm_crtc_state *state,
+				       struct drm_property *property,
+				       uint64_t val)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(state);
+
+	if (property == vs_crtc->sync_mode)
+		vs_crtc_state->sync_mode = val;
+	else if (property == vs_crtc->mmu_prefetch)
+		vs_crtc_state->mmu_prefetch = val;
+	else if (property == vs_crtc->bg_color)
+		vs_crtc_state->bg_color = val;
+	else if (property == vs_crtc->panel_sync)
+		vs_crtc_state->sync_enable = val;
+	else if (property == vs_crtc->dither)
+		vs_crtc_state->dither_enable = val;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vs_crtc_atomic_get_property(struct drm_crtc *crtc,
+				       const struct drm_crtc_state *state,
+				       struct drm_property *property,
+				       uint64_t *val)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	const struct vs_crtc_state *vs_crtc_state =
+		container_of(state, const struct vs_crtc_state, base);
+
+	if (property == vs_crtc->sync_mode)
+		*val = vs_crtc_state->sync_mode;
+	else if (property == vs_crtc->mmu_prefetch)
+		*val = vs_crtc_state->mmu_prefetch;
+	else if (property == vs_crtc->bg_color)
+		*val = vs_crtc_state->bg_color;
+	else if (property == vs_crtc->panel_sync)
+		*val = vs_crtc_state->sync_enable;
+	else if (property == vs_crtc->dither)
+		*val = vs_crtc_state->dither_enable;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vs_crtc_late_register(struct drm_crtc *crtc)
+{
+	return 0;
+}
+
+static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+
+	vs_crtc->funcs->enable_vblank(vs_crtc->dev, true);
+
+	return 0;
+}
+
+static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+
+	vs_crtc->funcs->enable_vblank(vs_crtc->dev, false);
+}
+
+static const struct drm_crtc_funcs vs_crtc_funcs = {
+	.set_config		= drm_atomic_helper_set_config,
+	.destroy		= vs_crtc_destroy,
+	.page_flip		= drm_atomic_helper_page_flip,
+	.reset			= vs_crtc_reset,
+	.atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
+	.atomic_destroy_state	= vs_crtc_atomic_destroy_state,
+	.atomic_set_property	= vs_crtc_atomic_set_property,
+	.atomic_get_property	= vs_crtc_atomic_get_property,
+	.late_register		= vs_crtc_late_register,
+	.enable_vblank		= vs_crtc_enable_vblank,
+	.disable_vblank		= vs_crtc_disable_vblank,
+};
+
+static u8 cal_pixel_bits(u32 bus_format)
+{
+	u8 bpp;
+
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+		bpp = 16;
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+		bpp = 18;
+		break;
+	case MEDIA_BUS_FMT_UYVY10_1X20:
+		bpp = 20;
+		break;
+	case MEDIA_BUS_FMT_BGR888_1X24:
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+	case MEDIA_BUS_FMT_YUV8_1X24:
+		bpp = 24;
+		break;
+	case MEDIA_BUS_FMT_RGB101010_1X30:
+	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+	case MEDIA_BUS_FMT_YUV10_1X30:
+		bpp = 30;
+		break;
+	default:
+		bpp = 24;
+		break;
+	}
+
+	return bpp;
+}
+
+static bool vs_crtc_mode_fixup(struct drm_crtc *crtc,
+			       const struct drm_display_mode *mode,
+			       struct drm_display_mode *adjusted_mode)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+
+	return vs_crtc->funcs->mode_fixup(vs_crtc->dev, mode, adjusted_mode);
+}
+
+static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
+				  struct drm_atomic_state *state)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
+
+	vs_crtc_state->bpp = cal_pixel_bits(vs_crtc_state->output_fmt);
+
+	vs_crtc->funcs->enable(vs_crtc->dev, crtc);
+	drm_crtc_vblank_on(crtc);
+}
+
+static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
+				   struct drm_atomic_state *state)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+
+	drm_crtc_vblank_off(crtc);
+
+	vs_crtc->funcs->disable(vs_crtc->dev, crtc);
+
+	if (crtc->state->event && !crtc->state->active) {
+		spin_lock_irq(&crtc->dev->event_lock);
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		spin_unlock_irq(&crtc->dev->event_lock);
+
+		crtc->state->event = NULL;
+	}
+}
+
+static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
+				 struct drm_atomic_state *state)
+{
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
+
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct device *dev = vs_crtc->dev;
+	struct drm_property_blob *blob = crtc->state->gamma_lut;
+	struct drm_color_lut *lut;
+
+	if (crtc_state->color_mgmt_changed) {
+		if (blob && blob->length) {
+			lut = blob->data;
+			vs_crtc->funcs->set_gamma(dev, crtc, lut,
+						  blob->length / sizeof(*lut));
+			vs_crtc->funcs->enable_gamma(dev, crtc, true);
+		} else {
+			vs_crtc->funcs->enable_gamma(dev, crtc, false);
+		}
+	}
+}
+
+static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
+				 struct drm_atomic_state *state)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct drm_pending_vblank_event *event = crtc->state->event;
+
+	vs_crtc->funcs->commit(vs_crtc->dev);
+
+	if (event) {
+		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+		spin_lock_irq(&crtc->dev->event_lock);
+		drm_crtc_arm_vblank_event(crtc, event);
+		spin_unlock_irq(&crtc->dev->event_lock);
+		crtc->state->event = NULL;
+	}
+}
+
+static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
+	.mode_fixup = vs_crtc_mode_fixup,
+	.atomic_enable	= vs_crtc_atomic_enable,
+	.atomic_disable = vs_crtc_atomic_disable,
+	.atomic_begin	= vs_crtc_atomic_begin,
+	.atomic_flush	= vs_crtc_atomic_flush,
+};
+
+static const struct drm_prop_enum_list vs_sync_mode_enum_list[] = {
+	{ VS_SINGLE_DC,			"single dc mode" },
+	{ VS_MULTI_DC_PRIMARY,		"primary dc for multi dc mode" },
+	{ VS_MULTI_DC_SECONDARY,	"secondary dc for multi dc mode" },
+};
+
+struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
+			       struct vs_dc_info *info)
+{
+	struct vs_crtc *crtc;
+	int ret;
+
+	if (!info)
+		return NULL;
+
+	crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
+	if (!crtc)
+		return NULL;
+
+	ret = drm_crtc_init_with_planes(drm_dev, &crtc->base,
+					NULL, NULL, &vs_crtc_funcs,
+					info->name ? info->name : NULL);
+	if (ret)
+		goto err_free_crtc;
+
+	drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
+
+	/* Set up the crtc properties */
+	if (info->pipe_sync) {
+		crtc->sync_mode = drm_property_create_enum(drm_dev, 0,
+							   "SYNC_MODE",
+							    vs_sync_mode_enum_list,
+							    ARRAY_SIZE(vs_sync_mode_enum_list));
+
+		if (!crtc->sync_mode)
+			goto err_cleanup_crts;
+
+		drm_object_attach_property(&crtc->base.base,
+					   crtc->sync_mode,
+					   VS_SINGLE_DC);
+	}
+
+	if (info->gamma_size) {
+		ret = drm_mode_crtc_set_gamma_size(&crtc->base,
+						   info->gamma_size);
+		if (ret)
+			goto err_cleanup_crts;
+
+		drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
+					   info->gamma_size);
+	}
+
+	if (info->background) {
+		crtc->bg_color = drm_property_create_range(drm_dev, 0,
+							   "BG_COLOR", 0, 0xffffffff);
+
+		if (!crtc->bg_color)
+			goto err_cleanup_crts;
+
+		drm_object_attach_property(&crtc->base.base, crtc->bg_color, 0);
+	}
+
+	if (info->panel_sync) {
+		crtc->panel_sync = drm_property_create_bool(drm_dev, 0, "SYNC_ENABLED");
+
+		if (!crtc->panel_sync)
+			goto err_cleanup_crts;
+
+		drm_object_attach_property(&crtc->base.base, crtc->panel_sync, 0);
+	}
+
+	crtc->dither = drm_property_create_bool(drm_dev, 0, "DITHER_ENABLED");
+	if (!crtc->dither)
+		goto err_cleanup_crts;
+
+	drm_object_attach_property(&crtc->base.base, crtc->dither, 0);
+
+	crtc->max_bpc = info->max_bpc;
+	crtc->color_formats = info->color_formats;
+	return crtc;
+
+err_cleanup_crts:
+	drm_crtc_cleanup(&crtc->base);
+
+err_free_crtc:
+	kfree(crtc);
+	return NULL;
+}
+
+void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow)
+{
+	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
+
+	drm_crtc_handle_vblank(crtc);
+
+	vs_crtc_state->underflow = underflow;
+}
diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h b/drivers/gpu/drm/verisilicon/vs_crtc.h
new file mode 100644
index 000000000000..33b3b14249ce
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_CRTC_H__
+#define __VS_CRTC_H__
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "vs_type.h"
+
+struct vs_crtc_funcs {
+	void (*enable)(struct device *dev, struct drm_crtc *crtc);
+	void (*disable)(struct device *dev, struct drm_crtc *crtc);
+	bool (*mode_fixup)(struct device *dev,
+			   const struct drm_display_mode *mode,
+			   struct drm_display_mode *adjusted_mode);
+	void (*set_gamma)(struct device *dev, struct drm_crtc *crtc,
+			  struct drm_color_lut *lut, unsigned int size);
+	void (*enable_gamma)(struct device *dev, struct drm_crtc *crtc,
+			     bool enable);
+	void (*enable_vblank)(struct device *dev, bool enable);
+	void (*commit)(struct device *dev);
+};
+
+struct vs_crtc_state {
+	struct drm_crtc_state base;
+
+	u32 sync_mode;
+	u32 output_fmt;
+	u32 bg_color;
+	u8 encoder_type;
+	u8 mmu_prefetch;
+	u8 bpp;
+	bool sync_enable;
+	bool dither_enable;
+	bool underflow;
+};
+
+struct vs_crtc {
+	struct drm_crtc base;
+	struct device *dev;
+	struct drm_pending_vblank_event *event;
+	unsigned int max_bpc;
+	unsigned int color_formats; /* supported color format */
+
+	struct drm_property *sync_mode;
+	struct drm_property *mmu_prefetch;
+	struct drm_property *bg_color;
+	struct drm_property *panel_sync;
+	struct drm_property *dither;
+
+	const struct vs_crtc_funcs *funcs;
+};
+
+void vs_crtc_destroy(struct drm_crtc *crtc);
+
+struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
+			       struct vs_dc_info *info);
+void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow);
+
+static inline struct vs_crtc *to_vs_crtc(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct vs_crtc, base);
+}
+
+static inline struct vs_crtc_state *
+to_vs_crtc_state(struct drm_crtc_state *state)
+{
+	return container_of(state, struct vs_crtc_state, base);
+}
+#endif /* __VS_CRTC_H__ */
diff --git a/drivers/gpu/drm/verisilicon/vs_type.h b/drivers/gpu/drm/verisilicon/vs_type.h
new file mode 100644
index 000000000000..6f8db65a703d
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_type.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_TYPE_H__
+#define __VS_TYPE_H__
+
+#include <linux/version.h>
+
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+
+struct vs_plane_info {
+	const char *name;
+	u8 id;
+	enum drm_plane_type type;
+	unsigned int num_formats;
+	const u32 *formats;
+	u8 num_modifiers;
+	const u64 *modifiers;
+	unsigned int min_width;
+	unsigned int min_height;
+	unsigned int max_width;
+	unsigned int max_height;
+	unsigned int rotation;
+	unsigned int blend_mode;
+	unsigned int color_encoding;
+
+	/* 0 means no de-gamma LUT */
+	unsigned int degamma_size;
+
+	int min_scale; /* 16.16 fixed point */
+	int max_scale; /* 16.16 fixed point */
+
+	/* default zorder value,
+	 * and 255 means unsupported zorder capability
+	 */
+	u8	 zpos;
+
+	bool watermark;
+	bool color_mgmt;
+	bool roi;
+};
+
+struct vs_dc_info {
+	const char *name;
+
+	u8 panel_num;
+
+	/* planes */
+	u8 plane_num;
+	const struct vs_plane_info *planes;
+
+	u8 layer_num;
+	unsigned int max_bpc;
+	unsigned int color_formats;
+
+	/* 0 means no gamma LUT */
+	u16 gamma_size;
+	u8 gamma_bits;
+
+	u16 pitch_alignment;
+
+	bool pipe_sync;
+	bool mmu_prefetch;
+	bool background;
+	bool panel_sync;
+	bool cap_dec;
+};
+
+#endif /* __VS_TYPE_H__ */
-- 
2.34.1


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

* [PATCH 7/9] drm/verisilicon: Add drm plane funcs
  2023-06-02  7:40 [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Keith Zhao
                   ` (5 preceding siblings ...)
  2023-06-02  7:40 ` [PATCH 6/9] drm/verisilicon: Add drm crtc funcs Keith Zhao
@ 2023-06-02  7:40 ` Keith Zhao
  2023-06-30 12:14   ` Thomas Zimmermann
  2023-07-10 16:46   ` Shengyu Qu
  2023-06-02  7:40 ` [PATCH 8/9] drm/verisilicon: Add verisilicon dc controller driver Keith Zhao
                   ` (2 subsequent siblings)
  9 siblings, 2 replies; 46+ messages in thread
From: Keith Zhao @ 2023-06-02  7:40 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Keith Zhao, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Implement plane functions for the DRM driver.

Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
---
 drivers/gpu/drm/verisilicon/Makefile   |   3 +-
 drivers/gpu/drm/verisilicon/vs_plane.c | 440 +++++++++++++++++++++++++
 drivers/gpu/drm/verisilicon/vs_plane.h |  74 +++++
 3 files changed, 516 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h

diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index bae5fbab9bbb..d96ad9399fc7 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -3,7 +3,8 @@
 vs_drm-objs := vs_drv.o \
 		vs_crtc.o \
 		vs_fb.o \
-		vs_gem.o
+		vs_gem.o \
+		vs_plane.o
 
 obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
 
diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c
new file mode 100644
index 000000000000..7b0dcef232ae
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_plane.c
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_fb_dma_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_plane_helper.h>
+
+#include <drm/vs_drm.h>
+
+#include "vs_crtc.h"
+#include "vs_fb.h"
+#include "vs_gem.h"
+#include "vs_plane.h"
+#include "vs_type.h"
+
+void vs_plane_destory(struct drm_plane *plane)
+{
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+
+	drm_plane_cleanup(plane);
+	kfree(vs_plane);
+}
+
+static void vs_plane_reset(struct drm_plane *plane)
+{
+	struct vs_plane_state *state;
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+
+	if (plane->state) {
+		__drm_atomic_helper_plane_destroy_state(plane->state);
+
+		state = to_vs_plane_state(plane->state);
+		kfree(state);
+		plane->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return;
+
+	__drm_atomic_helper_plane_reset(plane, &state->base);
+
+	state->degamma = VS_DEGAMMA_DISABLE;
+	state->degamma_changed = false;
+	state->base.zpos = vs_plane->id;
+
+	memset(&state->status, 0, sizeof(state->status));
+}
+
+static void _vs_plane_duplicate_blob(struct vs_plane_state *state,
+				     struct vs_plane_state *ori_state)
+{
+	state->watermark = ori_state->watermark;
+	state->color_mgmt = ori_state->color_mgmt;
+	state->roi = ori_state->roi;
+
+	if (state->watermark)
+		drm_property_blob_get(state->watermark);
+	if (state->color_mgmt)
+		drm_property_blob_get(state->color_mgmt);
+	if (state->roi)
+		drm_property_blob_get(state->roi);
+}
+
+static int
+_vs_plane_set_property_blob_from_id(struct drm_device *dev,
+				    struct drm_property_blob **blob,
+				    u64 blob_id,
+				    size_t expected_size)
+{
+	struct drm_property_blob *new_blob = NULL;
+
+	if (blob_id) {
+		new_blob = drm_property_lookup_blob(dev, blob_id);
+		if (!new_blob)
+			return -EINVAL;
+
+		if (new_blob->length != expected_size) {
+			drm_property_blob_put(new_blob);
+			return -EINVAL;
+		}
+	}
+
+	drm_property_replace_blob(blob, new_blob);
+	drm_property_blob_put(new_blob);
+
+	return 0;
+}
+
+static struct drm_plane_state *
+vs_plane_atomic_duplicate_state(struct drm_plane *plane)
+{
+	struct vs_plane_state *ori_state;
+	struct vs_plane_state *state;
+
+	if (WARN_ON(!plane->state))
+		return NULL;
+
+	ori_state = to_vs_plane_state(plane->state);
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
+
+	state->degamma = ori_state->degamma;
+	state->degamma_changed = ori_state->degamma_changed;
+
+	_vs_plane_duplicate_blob(state, ori_state);
+	memcpy(&state->status, &ori_state->status, sizeof(ori_state->status));
+
+	return &state->base;
+}
+
+static void vs_plane_atomic_destroy_state(struct drm_plane *plane,
+					  struct drm_plane_state *state)
+{
+	struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
+
+	__drm_atomic_helper_plane_destroy_state(state);
+
+	drm_property_blob_put(vs_plane_state->watermark);
+	drm_property_blob_put(vs_plane_state->color_mgmt);
+	drm_property_blob_put(vs_plane_state->roi);
+	kfree(vs_plane_state);
+}
+
+static int vs_plane_atomic_set_property(struct drm_plane *plane,
+					struct drm_plane_state *state,
+					struct drm_property *property,
+					uint64_t val)
+{
+	struct drm_device *dev = plane->dev;
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+	struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
+	int ret = 0;
+
+	if (property == vs_plane->degamma_mode) {
+		if (vs_plane_state->degamma != val) {
+			vs_plane_state->degamma = val;
+			vs_plane_state->degamma_changed = true;
+		} else {
+			vs_plane_state->degamma_changed = false;
+		}
+	} else if (property == vs_plane->watermark_prop) {
+		ret = _vs_plane_set_property_blob_from_id(dev,
+							  &vs_plane_state->watermark,
+							  val,
+							  sizeof(struct drm_vs_watermark));
+		return ret;
+	} else if (property == vs_plane->color_mgmt_prop) {
+		ret = _vs_plane_set_property_blob_from_id(dev,
+							  &vs_plane_state->color_mgmt,
+							  val,
+							  sizeof(struct drm_vs_color_mgmt));
+		return ret;
+	} else if (property == vs_plane->roi_prop) {
+		ret = _vs_plane_set_property_blob_from_id(dev,
+							  &vs_plane_state->roi,
+							  val,
+							  sizeof(struct drm_vs_roi));
+		return ret;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vs_plane_atomic_get_property(struct drm_plane *plane,
+					const struct drm_plane_state *state,
+					struct drm_property *property,
+					uint64_t *val)
+{
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+	const struct vs_plane_state *vs_plane_state =
+		container_of(state, const struct vs_plane_state, base);
+
+	if (property == vs_plane->degamma_mode)
+		*val = vs_plane_state->degamma;
+	else if (property == vs_plane->watermark_prop)
+		*val = (vs_plane_state->watermark) ?
+					vs_plane_state->watermark->base.id : 0;
+	else if (property == vs_plane->color_mgmt_prop)
+		*val = (vs_plane_state->color_mgmt) ?
+					vs_plane_state->color_mgmt->base.id : 0;
+	else if (property == vs_plane->roi_prop)
+		*val = (vs_plane_state->roi) ?
+					vs_plane_state->roi->base.id : 0;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static bool vs_format_mod_supported(struct drm_plane *plane,
+				    u32 format,
+				    u64 modifier)
+{
+	int i;
+
+       /* We always have to allow these modifiers:
+	* 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
+	* 2. Not passing any modifiers is the same as explicitly passing INVALID.
+	*/
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return true;
+
+	/* Check that the modifier is on the list of the plane's supported modifiers. */
+	for (i = 0; i < plane->modifier_count; i++) {
+		if (modifier == plane->modifiers[i])
+			break;
+	}
+
+	if (i == plane->modifier_count)
+		return false;
+
+	return true;
+}
+
+const struct drm_plane_funcs vs_plane_funcs = {
+	.update_plane		= drm_atomic_helper_update_plane,
+	.disable_plane		= drm_atomic_helper_disable_plane,
+	.destroy		= vs_plane_destory,
+	.reset			= vs_plane_reset,
+	.atomic_duplicate_state = vs_plane_atomic_duplicate_state,
+	.atomic_destroy_state	= vs_plane_atomic_destroy_state,
+	.atomic_set_property	= vs_plane_atomic_set_property,
+	.atomic_get_property	= vs_plane_atomic_get_property,
+	.format_mod_supported	= vs_format_mod_supported,
+};
+
+static unsigned char vs_get_plane_number(struct drm_framebuffer *fb)
+{
+	const struct drm_format_info *info;
+
+	if (!fb)
+		return 0;
+
+	info = drm_format_info(fb->format->format);
+	if (!info || info->num_planes > MAX_NUM_PLANES)
+		return 0;
+
+	return info->num_planes;
+}
+
+static int vs_plane_atomic_check(struct drm_plane *plane,
+				 struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
+										 plane);
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+	struct drm_framebuffer *fb = new_plane_state->fb;
+	struct drm_crtc *crtc = new_plane_state->crtc;
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+
+	if (!crtc || !fb)
+		return 0;
+
+	//return vs_plane->funcs->check(vs_crtc->dev, vs_plane, new_plane_state);
+	return vs_plane->funcs->check(vs_crtc->dev, plane, state);
+}
+
+static void vs_plane_atomic_update(struct drm_plane *plane,
+				   struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
+									   plane);
+	unsigned char i, num_planes;
+	struct drm_framebuffer *fb;
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+	//struct drm_plane_state *state = plane->state;
+	struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
+	struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
+	//struct drm_format_name_buf *name = &plane_state->status.format_name;
+
+	if (!new_state->fb || !new_state->crtc)
+		return;
+
+	fb = new_state->fb;
+
+	num_planes = vs_get_plane_number(fb);
+
+	for (i = 0; i < num_planes; i++) {
+		struct vs_gem_object *vs_obj;
+
+		vs_obj = vs_fb_get_gem_obj(fb, i);
+		vs_plane->dma_addr[i] = vs_obj->iova + fb->offsets[i];
+	}
+
+	plane_state->status.src = drm_plane_state_src(new_state);
+	plane_state->status.dest = drm_plane_state_dest(new_state);
+
+	vs_plane->funcs->update(vs_crtc->dev, vs_plane, plane, state);
+}
+
+static void vs_plane_atomic_disable(struct drm_plane *plane,
+				    struct drm_atomic_state *state)
+{
+	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
+										   plane);
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+	struct vs_crtc *vs_crtc = to_vs_crtc(old_state->crtc);
+
+	vs_plane->funcs->disable(vs_crtc->dev, vs_plane, old_state);
+}
+
+const struct drm_plane_helper_funcs vs_plane_helper_funcs = {
+	.atomic_check	= vs_plane_atomic_check,
+	.atomic_update	= vs_plane_atomic_update,
+	.atomic_disable = vs_plane_atomic_disable,
+};
+
+static const struct drm_prop_enum_list vs_degamma_mode_enum_list[] = {
+	{ VS_DEGAMMA_DISABLE,	"disabled" },
+	{ VS_DEGAMMA_BT709, "preset degamma for BT709" },
+	{ VS_DEGAMMA_BT2020,	"preset degamma for BT2020" },
+};
+
+struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
+				 struct vs_plane_info *info,
+				 unsigned int layer_num,
+				 unsigned int possible_crtcs)
+{
+	struct vs_plane *plane;
+	int ret;
+
+	if (!info)
+		return NULL;
+
+	plane = kzalloc(sizeof(*plane), GFP_KERNEL);
+	if (!plane)
+		return NULL;
+
+	ret = drm_universal_plane_init(drm_dev, &plane->base, possible_crtcs,
+				       &vs_plane_funcs, info->formats,
+				       info->num_formats, info->modifiers, info->type,
+				       info->name ? info->name : NULL);
+	if (ret)
+		goto err_free_plane;
+
+	drm_plane_helper_add(&plane->base, &vs_plane_helper_funcs);
+
+	/* Set up the plane properties */
+	if (info->degamma_size) {
+		plane->degamma_mode =
+		drm_property_create_enum(drm_dev, 0,
+					 "DEGAMMA_MODE",
+					 vs_degamma_mode_enum_list,
+					 ARRAY_SIZE(vs_degamma_mode_enum_list));
+
+		if (!plane->degamma_mode)
+			goto error_cleanup_plane;
+
+		drm_object_attach_property(&plane->base.base,
+					   plane->degamma_mode,
+					   VS_DEGAMMA_DISABLE);
+	}
+
+	if (info->rotation) {
+		ret = drm_plane_create_rotation_property(&plane->base,
+							 DRM_MODE_ROTATE_0,
+							 info->rotation);
+		if (ret)
+			goto error_cleanup_plane;
+	}
+
+	if (info->blend_mode) {
+		ret = drm_plane_create_blend_mode_property(&plane->base,
+							   info->blend_mode);
+		if (ret)
+			goto error_cleanup_plane;
+		ret = drm_plane_create_alpha_property(&plane->base);
+		if (ret)
+			goto error_cleanup_plane;
+	}
+
+	if (info->color_encoding) {
+		ret = drm_plane_create_color_properties(&plane->base,
+							info->color_encoding,
+							BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
+							DRM_COLOR_YCBCR_BT709,
+							DRM_COLOR_YCBCR_LIMITED_RANGE);
+		if (ret)
+			goto error_cleanup_plane;
+	}
+
+	if (info->zpos != 255) {
+		ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0,
+						     layer_num - 1);
+		if (ret)
+			goto error_cleanup_plane;
+	} else {
+		ret = drm_plane_create_zpos_immutable_property(&plane->base,
+							       info->zpos);
+		if (ret)
+			goto error_cleanup_plane;
+	}
+
+	if (info->watermark) {
+		plane->watermark_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
+							    "WATERMARK", 0);
+		if (!plane->watermark_prop)
+			goto error_cleanup_plane;
+
+		drm_object_attach_property(&plane->base.base, plane->watermark_prop, 0);
+	}
+
+	if (info->color_mgmt) {
+		plane->color_mgmt_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
+							     "COLOR_CONFIG", 0);
+		if (!plane->color_mgmt_prop)
+			goto error_cleanup_plane;
+
+		drm_object_attach_property(&plane->base.base, plane->color_mgmt_prop, 0);
+	}
+
+	if (info->roi) {
+		plane->roi_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
+						      "ROI", 0);
+		if (!plane->roi_prop)
+			goto error_cleanup_plane;
+
+		drm_object_attach_property(&plane->base.base, plane->roi_prop, 0);
+	}
+
+	return plane;
+
+error_cleanup_plane:
+	drm_plane_cleanup(&plane->base);
+err_free_plane:
+	kfree(plane);
+	return NULL;
+}
diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h
new file mode 100644
index 000000000000..76ef3c3de045
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_plane.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_PLANE_H__
+#define __VS_PLANE_H__
+
+#include <drm/drm_fourcc.h>
+#include <drm/drm_plane_helper.h>
+
+#include "vs_fb.h"
+#include "vs_type.h"
+
+struct vs_plane;
+
+struct vs_plane_funcs {
+	void (*update)(struct device *dev, struct vs_plane *plane, struct drm_plane *drm_plane,
+		       struct drm_atomic_state *state);
+	void (*disable)(struct device *dev, struct vs_plane *plane,
+			struct drm_plane_state *old_state);
+	int (*check)(struct device *dev, struct drm_plane *plane,
+		     struct drm_atomic_state *state);
+};
+
+struct vs_plane_status {
+	u32 tile_mode;
+	struct drm_rect src;
+	struct drm_rect dest;
+};
+
+struct vs_plane_state {
+	struct drm_plane_state base;
+	struct vs_plane_status status; /* for debugfs */
+
+	struct drm_property_blob *watermark;
+	struct drm_property_blob *color_mgmt;
+	struct drm_property_blob *roi;
+
+	u32 degamma;
+	bool degamma_changed;
+};
+
+struct vs_plane {
+	struct drm_plane base;
+	u8 id;
+	dma_addr_t dma_addr[MAX_NUM_PLANES];
+
+	struct drm_property *degamma_mode;
+	struct drm_property *watermark_prop;
+	struct drm_property *color_mgmt_prop;
+	struct drm_property *roi_prop;
+
+	const struct vs_plane_funcs *funcs;
+};
+
+void vs_plane_destory(struct drm_plane *plane);
+
+struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
+				 struct vs_plane_info *info,
+				 unsigned int layer_num,
+				 unsigned int possible_crtcs);
+
+static inline struct vs_plane *to_vs_plane(struct drm_plane *plane)
+{
+	return container_of(plane, struct vs_plane, base);
+}
+
+static inline struct vs_plane_state *
+to_vs_plane_state(struct drm_plane_state *state)
+{
+	return container_of(state, struct vs_plane_state, base);
+}
+#endif /* __VS_PLANE_H__ */
-- 
2.34.1


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

* [PATCH 8/9] drm/verisilicon: Add verisilicon dc controller driver
  2023-06-02  7:40 [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Keith Zhao
                   ` (6 preceding siblings ...)
  2023-06-02  7:40 ` [PATCH 7/9] drm/verisilicon: Add drm plane funcs Keith Zhao
@ 2023-06-02  7:40 ` Keith Zhao
  2023-06-30 12:36   ` Thomas Zimmermann
  2023-06-02  7:40 ` [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver Keith Zhao
  2023-06-22 18:19 ` [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Palmer Dabbelt
  9 siblings, 1 reply; 46+ messages in thread
From: Keith Zhao @ 2023-06-02  7:40 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Keith Zhao, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Add DC8200 display controller driver for StarFive JH7110 SoC.

Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
---
 drivers/gpu/drm/verisilicon/Makefile   |    4 +-
 drivers/gpu/drm/verisilicon/vs_dc.c    | 1040 ++++++++++++
 drivers/gpu/drm/verisilicon/vs_dc.h    |   62 +
 drivers/gpu/drm/verisilicon/vs_dc_hw.c | 2008 ++++++++++++++++++++++++
 drivers/gpu/drm/verisilicon/vs_dc_hw.h |  496 ++++++
 drivers/gpu/drm/verisilicon/vs_drv.c   |    2 +
 6 files changed, 3611 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h

diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index d96ad9399fc7..0ed25b5e3062 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -1,7 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0
 
-vs_drm-objs := vs_drv.o \
+vs_drm-objs := vs_dc_hw.o \
+		vs_dc.o \
 		vs_crtc.o \
+		vs_drv.o \
 		vs_fb.o \
 		vs_gem.o \
 		vs_plane.o
diff --git a/drivers/gpu/drm/verisilicon/vs_dc.c b/drivers/gpu/drm/verisilicon/vs_dc.c
new file mode 100644
index 000000000000..a512aaa57f2f
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_dc.c
@@ -0,0 +1,1040 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#include <linux/component.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/media-bus-format.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_vblank.h>
+#include <drm/vs_drm.h>
+
+#include "vs_crtc.h"
+#include "vs_dc_hw.h"
+#include "vs_dc.h"
+#include "vs_drv.h"
+#include "vs_type.h"
+
+static const char * const vout_clocks[] = {
+	"clk_vout_noc_disp",
+	"clk_vout_pix0",
+	"clk_vout_pix1",
+	"clk_vout_axi",
+	"clk_vout_core",
+	"clk_vout_vout_ahb",
+	"hdmitx0_pixel",
+	"clk_vout_dc8200",
+
+};
+
+static const char * const vout_resets[] = {
+	"rst_vout_axi",
+	"rst_vout_ahb",
+	"rst_vout_core",
+};
+
+static inline void update_format(u32 format, u64 mod, struct dc_hw_fb *fb)
+{
+	u8 f = FORMAT_A8R8G8B8;
+
+	switch (format) {
+	case DRM_FORMAT_XRGB4444:
+	case DRM_FORMAT_RGBX4444:
+	case DRM_FORMAT_XBGR4444:
+	case DRM_FORMAT_BGRX4444:
+		f = FORMAT_X4R4G4B4;
+		break;
+	case DRM_FORMAT_ARGB4444:
+	case DRM_FORMAT_RGBA4444:
+	case DRM_FORMAT_ABGR4444:
+	case DRM_FORMAT_BGRA4444:
+		f = FORMAT_A4R4G4B4;
+		break;
+	case DRM_FORMAT_XRGB1555:
+	case DRM_FORMAT_RGBX5551:
+	case DRM_FORMAT_XBGR1555:
+	case DRM_FORMAT_BGRX5551:
+		f = FORMAT_X1R5G5B5;
+		break;
+	case DRM_FORMAT_ARGB1555:
+	case DRM_FORMAT_RGBA5551:
+	case DRM_FORMAT_ABGR1555:
+	case DRM_FORMAT_BGRA5551:
+		f = FORMAT_A1R5G5B5;
+		break;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		f = FORMAT_R5G6B5;
+		break;
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_RGBX8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_BGRX8888:
+		f = FORMAT_X8R8G8B8;
+		break;
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_BGRA8888:
+		f = FORMAT_A8R8G8B8;
+		break;
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_YVYU:
+		f = FORMAT_YUY2;
+		break;
+	case DRM_FORMAT_UYVY:
+	case DRM_FORMAT_VYUY:
+		f = FORMAT_UYVY;
+		break;
+	case DRM_FORMAT_YUV420:
+	case DRM_FORMAT_YVU420:
+		f = FORMAT_YV12;
+		break;
+	case DRM_FORMAT_NV21:
+		f = FORMAT_NV12;
+		break;
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
+		f = FORMAT_NV16;
+		break;
+	case DRM_FORMAT_P010:
+		f = FORMAT_P010;
+		break;
+	case DRM_FORMAT_ARGB2101010:
+	case DRM_FORMAT_RGBA1010102:
+	case DRM_FORMAT_ABGR2101010:
+	case DRM_FORMAT_BGRA1010102:
+		f = FORMAT_A2R10G10B10;
+		break;
+	case DRM_FORMAT_NV12:
+		if (fourcc_mod_vs_get_type(mod) ==
+			DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT)
+			f = FORMAT_NV12_10BIT;
+		else
+			f = FORMAT_NV12;
+		break;
+	case DRM_FORMAT_YUV444:
+		if (fourcc_mod_vs_get_type(mod) ==
+			DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT)
+			f = FORMAT_YUV444_10BIT;
+		else
+			f = FORMAT_YUV444;
+		break;
+	default:
+		break;
+	}
+
+	fb->format = f;
+}
+
+static inline void update_swizzle(u32 format, struct dc_hw_fb *fb)
+{
+	fb->swizzle = SWIZZLE_ARGB;
+	fb->uv_swizzle = 0;
+
+	switch (format) {
+	case DRM_FORMAT_RGBX4444:
+	case DRM_FORMAT_RGBA4444:
+	case DRM_FORMAT_RGBX5551:
+	case DRM_FORMAT_RGBA5551:
+	case DRM_FORMAT_RGBX8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_RGBA1010102:
+		fb->swizzle = SWIZZLE_RGBA;
+		break;
+	case DRM_FORMAT_XBGR4444:
+	case DRM_FORMAT_ABGR4444:
+	case DRM_FORMAT_XBGR1555:
+	case DRM_FORMAT_ABGR1555:
+	case DRM_FORMAT_BGR565:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_ABGR2101010:
+		fb->swizzle = SWIZZLE_ABGR;
+		break;
+	case DRM_FORMAT_BGRX4444:
+	case DRM_FORMAT_BGRA4444:
+	case DRM_FORMAT_BGRX5551:
+	case DRM_FORMAT_BGRA5551:
+	case DRM_FORMAT_BGRX8888:
+	case DRM_FORMAT_BGRA8888:
+	case DRM_FORMAT_BGRA1010102:
+		fb->swizzle = SWIZZLE_BGRA;
+		break;
+	case DRM_FORMAT_YVYU:
+	case DRM_FORMAT_VYUY:
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV61:
+		fb->uv_swizzle = 1;
+		break;
+	default:
+		break;
+	}
+}
+
+static inline void update_watermark(struct drm_property_blob *watermark,
+				    struct dc_hw_fb *fb)
+{
+	struct drm_vs_watermark *data;
+
+	fb->water_mark = 0;
+
+	if (watermark) {
+		data = watermark->data;
+		fb->water_mark = data->watermark & 0xFFFFF;
+	}
+}
+
+static inline u8 to_vs_rotation(unsigned int rotation)
+{
+	u8 rot;
+
+	switch (rotation & DRM_MODE_REFLECT_MASK) {
+	case DRM_MODE_REFLECT_X:
+		rot = FLIP_X;
+		return rot;
+	case DRM_MODE_REFLECT_Y:
+		rot = FLIP_Y;
+		return rot;
+	case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
+		rot = FLIP_XY;
+		return rot;
+	default:
+		break;
+	}
+
+	switch (rotation & DRM_MODE_ROTATE_MASK) {
+	case DRM_MODE_ROTATE_0:
+		rot = ROT_0;
+		break;
+	case DRM_MODE_ROTATE_90:
+		rot = ROT_90;
+		break;
+	case DRM_MODE_ROTATE_180:
+		rot = ROT_180;
+		break;
+	case DRM_MODE_ROTATE_270:
+		rot = ROT_270;
+		break;
+	default:
+		rot = ROT_0;
+		break;
+	}
+
+	return rot;
+}
+
+static inline u8 to_vs_yuv_color_space(u32 color_space)
+{
+	u8 cs;
+
+	switch (color_space) {
+	case DRM_COLOR_YCBCR_BT601:
+		cs = COLOR_SPACE_601;
+		break;
+	case DRM_COLOR_YCBCR_BT709:
+		cs = COLOR_SPACE_709;
+		break;
+	case DRM_COLOR_YCBCR_BT2020:
+		cs = COLOR_SPACE_2020;
+		break;
+	default:
+		cs = COLOR_SPACE_601;
+		break;
+	}
+
+	return cs;
+}
+
+static inline u8 to_vs_tile_mode(u64 modifier)
+{
+	return (u8)(modifier & DRM_FORMAT_MOD_VS_NORM_MODE_MASK);
+}
+
+static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc)
+{
+	u8 panel_num = dc->hw.info->panel_num;
+	u32 index = drm_crtc_index(crtc);
+	int i;
+
+	for (i = 0; i < panel_num; i++) {
+		if (index == dc->crtc[i]->base.index)
+			return i;
+	}
+
+	return 0;
+}
+
+static int plda_clk_rst_init(struct device *dev)
+{
+	int ret = 0;
+	struct vs_dc *dc = dev_get_drvdata(dev);
+
+	ret = clk_bulk_prepare_enable(dc->nclks, dc->clk_vout);
+	if (ret) {
+		dev_err(dev, "failed to enable clocks\n");
+		return ret;
+	}
+
+	ret = reset_control_bulk_deassert(dc->nrsts, dc->rst_vout);
+	return ret;
+}
+
+static void plda_clk_rst_deinit(struct device *dev)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+
+	reset_control_bulk_assert(dc->nrsts, dc->rst_vout);
+	clk_bulk_disable_unprepare(dc->nclks, dc->clk_vout);
+}
+
+static void dc_deinit(struct device *dev)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+
+	dc_hw_enable_interrupt(&dc->hw, 0);
+	dc_hw_deinit(&dc->hw);
+	plda_clk_rst_deinit(dev);
+}
+
+static int dc_init(struct device *dev)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+	int ret;
+
+	dc->first_frame = true;
+
+	ret = plda_clk_rst_init(dev);
+	if (ret < 0) {
+		dev_err(dev, "failed to init dc clk reset: %d\n", ret);
+		return ret;
+	}
+
+	ret = dc_hw_init(&dc->hw);
+	if (ret) {
+		dev_err(dev, "failed to init DC HW\n");
+		return ret;
+	}
+	return 0;
+}
+
+static void vs_dc_enable(struct device *dev, struct drm_crtc *crtc)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+	struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct dc_hw_display display;
+
+	display.bus_format = crtc_state->output_fmt;
+	display.h_active = mode->hdisplay;
+	display.h_total = mode->htotal;
+	display.h_sync_start = mode->hsync_start;
+	display.h_sync_end = mode->hsync_end;
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		display.h_sync_polarity = true;
+	else
+		display.h_sync_polarity = false;
+
+	display.v_active = mode->vdisplay;
+	display.v_total = mode->vtotal;
+	display.v_sync_start = mode->vsync_start;
+	display.v_sync_end = mode->vsync_end;
+
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		display.v_sync_polarity = true;
+	else
+		display.v_sync_polarity = false;
+
+	display.sync_mode = crtc_state->sync_mode;
+	display.bg_color = crtc_state->bg_color;
+
+	display.id = to_vs_display_id(dc, crtc);
+	display.sync_enable = crtc_state->sync_enable;
+	display.dither_enable = crtc_state->dither_enable;
+
+	display.enable = true;
+
+	if (crtc_state->encoder_type == DRM_MODE_ENCODER_DSI) {
+		dc_hw_set_out(&dc->hw, OUT_DPI, display.id);
+		clk_set_rate(dc->clk_vout[CLK_VOUT_SOC_PIX].clk, mode->clock * 1000);
+		clk_set_parent(dc->clk_vout[CLK_VOUT_PIX1].clk,
+			       dc->clk_vout[CLK_VOUT_SOC_PIX].clk);
+	} else {
+		dc_hw_set_out(&dc->hw, OUT_DP, display.id);
+		clk_set_parent(dc->clk_vout[CLK_VOUT_PIX0].clk,
+			       dc->clk_vout[CLK_VOUT_HDMI_PIX].clk);
+	}
+
+	dc_hw_setup_display(&dc->hw, &display);
+}
+
+static void vs_dc_disable(struct device *dev, struct drm_crtc *crtc)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+	struct dc_hw_display display;
+
+	display.id = to_vs_display_id(dc, crtc);
+	display.enable = false;
+
+	dc_hw_setup_display(&dc->hw, &display);
+}
+
+static bool vs_dc_mode_fixup(struct device *dev,
+			     const struct drm_display_mode *mode,
+			     struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void vs_dc_set_gamma(struct device *dev, struct drm_crtc *crtc,
+			    struct drm_color_lut *lut, unsigned int size)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+	u16 i, r, g, b;
+	u8 bits, id;
+
+	if (size != dc->hw.info->gamma_size) {
+		dev_err(dev, "gamma size does not match!\n");
+		return;
+	}
+
+	id = to_vs_display_id(dc, crtc);
+
+	bits = dc->hw.info->gamma_bits;
+	for (i = 0; i < size; i++) {
+		r = drm_color_lut_extract(lut[i].red, bits);
+		g = drm_color_lut_extract(lut[i].green, bits);
+		b = drm_color_lut_extract(lut[i].blue, bits);
+		dc_hw_update_gamma(&dc->hw, id, i, r, g, b);
+	}
+}
+
+static void vs_dc_enable_gamma(struct device *dev, struct drm_crtc *crtc,
+			       bool enable)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+	u8 id;
+
+	id = to_vs_display_id(dc, crtc);
+	dc_hw_enable_gamma(&dc->hw, id, enable);
+}
+
+static void vs_dc_enable_vblank(struct device *dev, bool enable)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+
+	dc_hw_enable_interrupt(&dc->hw, enable);
+}
+
+static u32 calc_factor(u32 src, u32 dest)
+{
+	u32 factor = 1 << 16;
+
+	if (src > 1 && dest > 1)
+		factor = ((src - 1) << 16) / (dest - 1);
+
+	return factor;
+}
+
+static void update_scale(struct drm_plane_state *state, struct dc_hw_roi *roi,
+			 struct dc_hw_scale *scale)
+{
+	int dst_w = drm_rect_width(&state->dst);
+	int dst_h = drm_rect_height(&state->dst);
+	int src_w, src_h, temp;
+
+	scale->enable = false;
+
+	if (roi->enable) {
+		src_w = roi->width;
+		src_h = roi->height;
+	} else {
+		src_w = drm_rect_width(&state->src) >> 16;
+		src_h = drm_rect_height(&state->src) >> 16;
+	}
+
+	if (drm_rotation_90_or_270(state->rotation)) {
+		temp = src_w;
+		src_w = src_h;
+		src_h = temp;
+	}
+
+	if (src_w != dst_w) {
+		scale->scale_factor_x = calc_factor(src_w, dst_w);
+		scale->enable = true;
+	} else {
+		scale->scale_factor_x = 1 << 16;
+	}
+	if (src_h != dst_h) {
+		scale->scale_factor_y = calc_factor(src_h, dst_h);
+		scale->enable = true;
+	} else {
+		scale->scale_factor_y = 1 << 16;
+	}
+}
+
+static void update_fb(struct vs_plane *plane, u8 display_id,
+		      struct dc_hw_fb *fb, struct drm_plane_state *state)
+{
+	struct vs_plane_state *plane_state = to_vs_plane_state(state);
+	struct drm_framebuffer *drm_fb = state->fb;
+	struct drm_rect *src = &state->src;
+
+	fb->display_id = display_id;
+	fb->y_address = plane->dma_addr[0];
+	fb->y_stride = drm_fb->pitches[0];
+	if (drm_fb->format->format == DRM_FORMAT_YVU420) {
+		fb->u_address = plane->dma_addr[2];
+		fb->v_address = plane->dma_addr[1];
+		fb->u_stride = drm_fb->pitches[2];
+		fb->v_stride = drm_fb->pitches[1];
+	} else {
+		fb->u_address = plane->dma_addr[1];
+		fb->v_address = plane->dma_addr[2];
+		fb->u_stride = drm_fb->pitches[1];
+		fb->v_stride = drm_fb->pitches[2];
+	}
+	fb->width = drm_rect_width(src) >> 16;
+	fb->height = drm_rect_height(src) >> 16;
+	fb->tile_mode = to_vs_tile_mode(drm_fb->modifier);
+	fb->rotation = to_vs_rotation(state->rotation);
+	fb->yuv_color_space = to_vs_yuv_color_space(state->color_encoding);
+	fb->zpos = state->zpos;
+	fb->enable = state->visible;
+	update_format(drm_fb->format->format, drm_fb->modifier, fb);
+	update_swizzle(drm_fb->format->format, fb);
+	update_watermark(plane_state->watermark, fb);
+	plane_state->status.tile_mode = fb->tile_mode;
+}
+
+static void update_degamma(struct vs_dc *dc, struct vs_plane *plane,
+			   struct vs_plane_state *plane_state)
+{
+	dc_hw_update_degamma(&dc->hw, plane->id, plane_state->degamma);
+	plane_state->degamma_changed = false;
+}
+
+static void update_roi(struct vs_dc *dc, u8 id,
+		       struct vs_plane_state *plane_state,
+		       struct dc_hw_roi *roi,
+		       struct drm_plane_state *state)
+{
+	struct drm_vs_roi *data;
+	struct drm_rect *src = &state->src;
+	u16 src_w = drm_rect_width(src) >> 16;
+	u16 src_h = drm_rect_height(src) >> 16;
+
+	if (plane_state->roi) {
+		data = plane_state->roi->data;
+
+		if (data->enable) {
+			roi->x = data->roi_x;
+			roi->y = data->roi_y;
+			roi->width = (data->roi_x + data->roi_w > src_w) ?
+						 (src_w - data->roi_x) : data->roi_w;
+			roi->height = (data->roi_y + data->roi_h > src_h) ?
+						  (src_h - data->roi_y) : data->roi_h;
+			roi->enable = true;
+		} else {
+			roi->enable = false;
+		}
+
+		dc_hw_update_roi(&dc->hw, id, roi);
+	} else {
+		roi->enable = false;
+	}
+}
+
+static void update_color_mgmt(struct vs_dc *dc, u8 id,
+			      struct dc_hw_fb *fb,
+			      struct vs_plane_state *plane_state)
+{
+	struct drm_vs_color_mgmt *data;
+	struct dc_hw_colorkey colorkey;
+
+	if (plane_state->color_mgmt) {
+		data = plane_state->color_mgmt->data;
+
+		fb->clear_enable = data->clear_enable;
+		fb->clear_value = data->clear_value;
+
+		if (data->colorkey > data->colorkey_high)
+			data->colorkey = data->colorkey_high;
+
+		colorkey.colorkey = data->colorkey;
+		colorkey.colorkey_high = data->colorkey_high;
+		colorkey.transparency = (data->transparency) ?
+				DC_TRANSPARENCY_KEY : DC_TRANSPARENCY_OPAQUE;
+		dc_hw_update_colorkey(&dc->hw, id, &colorkey);
+	}
+}
+
+static void update_plane(struct vs_dc *dc, struct vs_plane *plane,
+			 struct drm_plane *drm_plane,
+			 struct drm_atomic_state *drm_state)
+{
+	struct dc_hw_fb fb = {0};
+	struct dc_hw_scale scale;
+	struct dc_hw_position pos;
+	struct dc_hw_blend blend;
+	struct dc_hw_roi roi;
+	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
+									   drm_plane);
+	struct vs_plane_state *plane_state = to_vs_plane_state(state);
+	struct drm_rect *dest = &state->dst;
+	bool dec_enable = false;
+	u8 display_id = 0;
+
+	display_id = to_vs_display_id(dc, state->crtc);
+	update_fb(plane, display_id, &fb, state);
+	fb.dec_enable = dec_enable;
+
+	update_roi(dc, plane->id, plane_state, &roi, state);
+
+	update_scale(state, &roi, &scale);
+
+	if (plane_state->degamma_changed)
+		update_degamma(dc, plane, plane_state);
+
+	pos.start_x = dest->x1;
+	pos.start_y = dest->y1;
+	pos.end_x = dest->x2;
+	pos.end_y = dest->y2;
+
+	blend.alpha = (u8)(state->alpha >> 8);
+	blend.blend_mode = (u8)(state->pixel_blend_mode);
+
+	update_color_mgmt(dc, plane->id, &fb, plane_state);
+
+	dc_hw_update_plane(&dc->hw, plane->id, &fb, &scale, &pos, &blend);
+}
+
+static void update_qos(struct vs_dc *dc, struct vs_plane *plane,
+		       struct drm_plane *drm_plane,
+		       struct drm_atomic_state *drm_state)
+{
+	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
+									   drm_plane);
+	struct vs_plane_state *plane_state = to_vs_plane_state(state);
+	struct drm_vs_watermark *data;
+	struct dc_hw_qos qos;
+
+	if (plane_state->watermark) {
+		data = plane_state->watermark->data;
+
+		if (data->qos_high) {
+			if (data->qos_low > data->qos_high)
+				data->qos_low = data->qos_high;
+
+			qos.low_value = data->qos_low & 0x0F;
+			qos.high_value = data->qos_high & 0x0F;
+			dc_hw_update_qos(&dc->hw, &qos);
+		}
+	}
+}
+
+static void update_cursor_size(struct drm_plane_state *state, struct dc_hw_cursor *cursor)
+{
+	u8 size_type;
+
+	switch (state->crtc_w) {
+	case 32:
+		size_type = CURSOR_SIZE_32X32;
+		break;
+	case 64:
+		size_type = CURSOR_SIZE_64X64;
+		break;
+	default:
+		size_type = CURSOR_SIZE_32X32;
+		break;
+	}
+
+	cursor->size = size_type;
+}
+
+static void update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
+				struct drm_plane *drm_plane,
+				struct drm_atomic_state *drm_state)
+{
+	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
+								       drm_plane);
+	struct drm_framebuffer *drm_fb = state->fb;
+	struct dc_hw_cursor cursor;
+
+	cursor.address = plane->dma_addr[0];
+	cursor.x = state->crtc_x;
+	cursor.y = state->crtc_y;
+	cursor.hot_x = drm_fb->hot_x;
+	cursor.hot_y = drm_fb->hot_y;
+	cursor.display_id = to_vs_display_id(dc, state->crtc);
+	update_cursor_size(state, &cursor);
+	cursor.enable = true;
+
+	dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
+}
+
+static void vs_dc_update_plane(struct device *dev, struct vs_plane *plane,
+			       struct drm_plane *drm_plane,
+			       struct drm_atomic_state *drm_state)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+	enum drm_plane_type type = plane->base.type;
+
+	switch (type) {
+	case DRM_PLANE_TYPE_PRIMARY:
+	case DRM_PLANE_TYPE_OVERLAY:
+		update_plane(dc, plane, drm_plane, drm_state);
+		update_qos(dc, plane, drm_plane, drm_state);
+		break;
+	case DRM_PLANE_TYPE_CURSOR:
+		update_cursor_plane(dc, plane, drm_plane, drm_state);
+		break;
+	default:
+		break;
+	}
+}
+
+static void vs_dc_disable_plane(struct device *dev, struct vs_plane *plane,
+				struct drm_plane_state *old_state)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+	enum drm_plane_type type = plane->base.type;
+	struct dc_hw_fb fb = {0};
+	struct dc_hw_cursor cursor = {0};
+
+	switch (type) {
+	case DRM_PLANE_TYPE_PRIMARY:
+	case DRM_PLANE_TYPE_OVERLAY:
+		fb.enable = false;
+		dc_hw_update_plane(&dc->hw, plane->id, &fb, NULL, NULL, NULL);
+		break;
+
+	case DRM_PLANE_TYPE_CURSOR:
+		cursor.enable = false;
+		cursor.display_id = to_vs_display_id(dc, old_state->crtc);
+		dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
+		break;
+	default:
+		break;
+	}
+}
+
+static bool vs_dc_mod_supported(const struct vs_plane_info *plane_info,
+				u64 modifier)
+{
+	const u64 *mods;
+
+	if (!plane_info->modifiers)
+		return false;
+
+	for (mods = plane_info->modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) {
+		if (*mods == modifier)
+			return true;
+	}
+
+	return false;
+}
+
+static int vs_dc_check_plane(struct device *dev, struct drm_plane *plane,
+			     struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
+										 plane);
+	struct vs_dc *dc = dev_get_drvdata(dev);
+	struct drm_framebuffer *fb = new_plane_state->fb;
+	const struct vs_plane_info *plane_info;
+	struct drm_crtc *crtc = new_plane_state->crtc;
+	struct drm_crtc_state *crtc_state;
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+
+	plane_info = &dc->hw.info->planes[vs_plane->id];
+	if (!plane_info)
+		return -EINVAL;
+
+	if (fb->width < plane_info->min_width ||
+	    fb->width > plane_info->max_width ||
+	    fb->height < plane_info->min_height ||
+	    fb->height > plane_info->max_height)
+		dev_err_once(dev, "buffer size may not support on plane%d.\n",
+			     vs_plane->id);
+
+	if (vs_plane->base.type != DRM_PLANE_TYPE_CURSOR &&
+	    (!vs_dc_mod_supported(plane_info, fb->modifier))) {
+		dev_err(dev, "unsupported modifier on plane%d.\n", vs_plane->id);
+		return -EINVAL;
+	}
+
+	crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state))
+		return -EINVAL;
+
+	return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
+						  plane_info->min_scale,
+						  plane_info->max_scale,
+						  true, true);
+}
+
+static irqreturn_t dc_isr(int irq, void *data)
+{
+	struct vs_dc *dc = data;
+	struct vs_dc_info *dc_info = dc->hw.info;
+	u32 i, ret;
+
+	ret = dc_hw_get_interrupt(&dc->hw);
+
+	for (i = 0; i < dc_info->panel_num; i++)
+		vs_crtc_handle_vblank(&dc->crtc[i]->base, dc_hw_check_underflow(&dc->hw));
+
+	return IRQ_HANDLED;
+}
+
+static void vs_dc_commit(struct device *dev)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+
+	dc_hw_enable_shadow_register(&dc->hw, false);
+
+	dc_hw_commit(&dc->hw);
+
+	if (dc->first_frame)
+		dc->first_frame = false;
+
+	dc_hw_enable_shadow_register(&dc->hw, true);
+}
+
+static const struct vs_crtc_funcs dc_crtc_funcs = {
+	.enable			= vs_dc_enable,
+	.disable		= vs_dc_disable,
+	.mode_fixup		= vs_dc_mode_fixup,
+	.set_gamma		= vs_dc_set_gamma,
+	.enable_gamma	= vs_dc_enable_gamma,
+	.enable_vblank	= vs_dc_enable_vblank,
+	.commit			= vs_dc_commit,
+};
+
+static const struct vs_plane_funcs dc_plane_funcs = {
+	.update			= vs_dc_update_plane,
+	.disable		= vs_dc_disable_plane,
+	.check			= vs_dc_check_plane,
+};
+
+static int dc_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm_dev = data;
+	struct vs_dc *dc = dev_get_drvdata(dev);
+	struct device_node *port;
+	struct vs_crtc *crtc;
+	struct drm_crtc *drm_crtc;
+	struct vs_dc_info *dc_info;
+	struct vs_plane *plane;
+	struct drm_plane *drm_plane, *tmp;
+	struct vs_plane_info *plane_info;
+	int i, ret;
+	u32 ctrc_mask = 0;
+
+	if (!drm_dev || !dc) {
+		dev_err(dev, "devices are not created.\n");
+		return -ENODEV;
+	}
+
+	ret = dc_init(dev);
+	if (ret < 0) {
+		dev_err(dev, "Failed to initialize DC hardware.\n");
+		return ret;
+	}
+
+	port = of_get_child_by_name(dev->of_node, "port");
+	if (!port) {
+		dev_err(dev, "no port node found\n");
+		return -ENODEV;
+	}
+	of_node_put(port);
+
+	dc_info = dc->hw.info;
+
+	for (i = 0; i < dc_info->panel_num; i++) {
+		crtc = vs_crtc_create(drm_dev, dc_info);
+		if (!crtc) {
+			dev_err(dev, "Failed to create CRTC.\n");
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		crtc->base.port = port;
+		crtc->dev = dev;
+		crtc->funcs = &dc_crtc_funcs;
+		dc->crtc[i] = crtc;
+		ctrc_mask |= drm_crtc_mask(&crtc->base);
+	}
+
+	for (i = 0; i < dc_info->plane_num; i++) {
+		plane_info = (struct vs_plane_info *)&dc_info->planes[i];
+
+		if (!strcmp(plane_info->name, "Primary") || !strcmp(plane_info->name, "Cursor")) {
+			plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
+						drm_crtc_mask(&dc->crtc[0]->base));
+		} else if (!strcmp(plane_info->name, "Primary_1") ||
+				   !strcmp(plane_info->name, "Cursor_1")) {
+			plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
+						drm_crtc_mask(&dc->crtc[1]->base));
+		} else {
+			plane = vs_plane_create(drm_dev, plane_info,
+						dc_info->layer_num, ctrc_mask);
+		}
+
+		if (!plane)
+			goto err_cleanup_planes;
+
+		plane->id = i;
+		dc->planes[i].id = plane_info->id;
+
+		plane->funcs = &dc_plane_funcs;
+
+		if (plane_info->type == DRM_PLANE_TYPE_PRIMARY) {
+			if (!strcmp(plane_info->name, "Primary"))
+				dc->crtc[0]->base.primary = &plane->base;
+			else
+				dc->crtc[1]->base.primary = &plane->base;
+			drm_dev->mode_config.min_width = plane_info->min_width;
+			drm_dev->mode_config.min_height =
+							plane_info->min_height;
+			drm_dev->mode_config.max_width = plane_info->max_width;
+			drm_dev->mode_config.max_height =
+							plane_info->max_height;
+		}
+
+		if (plane_info->type == DRM_PLANE_TYPE_CURSOR) {
+			if (!strcmp(plane_info->name, "Cursor"))
+				dc->crtc[0]->base.cursor = &plane->base;
+			else
+				dc->crtc[1]->base.cursor = &plane->base;
+			drm_dev->mode_config.cursor_width =
+							plane_info->max_width;
+			drm_dev->mode_config.cursor_height =
+							plane_info->max_height;
+		}
+	}
+
+	vs_drm_update_pitch_alignment(drm_dev, dc_info->pitch_alignment);
+
+	return 0;
+
+err_cleanup_planes:
+	list_for_each_entry_safe(drm_plane, tmp,
+				 &drm_dev->mode_config.plane_list, head)
+		if (drm_plane->possible_crtcs & ctrc_mask)
+			vs_plane_destory(drm_plane);
+
+	drm_for_each_crtc(drm_crtc, drm_dev)
+		vs_crtc_destroy(drm_crtc);
+
+	return ret;
+}
+
+static void dc_unbind(struct device *dev, struct device *master, void *data)
+{
+	dc_deinit(dev);
+}
+
+const struct component_ops dc_component_ops = {
+	.bind = dc_bind,
+	.unbind = dc_unbind,
+};
+
+static const struct of_device_id dc_driver_dt_match[] = {
+	{ .compatible = "verisilicon,dc8200", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dc_driver_dt_match);
+
+static int dc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct vs_dc *dc;
+	int irq, ret, i;
+
+	dc = devm_kzalloc(dev, sizeof(*dc), GFP_KERNEL);
+	if (!dc)
+		return -ENOMEM;
+
+	dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(dc->hw.hi_base))
+		return PTR_ERR(dc->hw.hi_base);
+
+	dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(dc->hw.reg_base))
+		return PTR_ERR(dc->hw.reg_base);
+
+	dc->dss_reg = devm_platform_ioremap_resource(pdev, 2);
+	if (IS_ERR(dc->dss_reg))
+		return PTR_ERR(dc->dss_reg);
+
+	dc->nclks = ARRAY_SIZE(dc->clk_vout);
+	for (i = 0; i < dc->nclks; ++i)
+		dc->clk_vout[i].id = vout_clocks[i];
+	ret = devm_clk_bulk_get(dev, dc->nclks, dc->clk_vout);
+	if (ret) {
+		dev_err(dev, "Failed to get clk controls\n");
+		return ret;
+	}
+
+	dc->nrsts = ARRAY_SIZE(dc->rst_vout);
+	for (i = 0; i < dc->nrsts; ++i)
+		dc->rst_vout[i].id = vout_resets[i];
+	ret = devm_reset_control_bulk_get_shared(dev, dc->nrsts,
+						 dc->rst_vout);
+	if (ret) {
+		dev_err(dev, "Failed to get reset controls\n");
+		return ret;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+
+	ret = devm_request_irq(dev, irq, dc_isr, 0, dev_name(dev), dc);
+	if (ret < 0) {
+		dev_err(dev, "Failed to install irq:%u.\n", irq);
+		return ret;
+	}
+
+	dev_set_drvdata(dev, dc);
+
+	return component_add(dev, &dc_component_ops);
+}
+
+static int dc_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	component_del(dev, &dc_component_ops);
+
+	dev_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+struct platform_driver dc_platform_driver = {
+	.probe = dc_probe,
+	.remove = dc_remove,
+	.driver = {
+		.name = "vs-dc",
+		.of_match_table = of_match_ptr(dc_driver_dt_match),
+	},
+};
+
+MODULE_AUTHOR("StarFive Corporation");
+MODULE_AUTHOR("Verisilicon Corporation");
+MODULE_DESCRIPTION("VeriSilicon DC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/verisilicon/vs_dc.h b/drivers/gpu/drm/verisilicon/vs_dc.h
new file mode 100644
index 000000000000..ab76ac1e9943
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_dc.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_DC_H__
+#define __VS_DC_H__
+
+#include <linux/clk.h>
+#include <linux/mm_types.h>
+#include <linux/reset.h>
+#include <linux/version.h>
+
+#include <drm/drm_fourcc.h>
+#include <drm/drm_modes.h>
+
+#include "vs_crtc.h"
+#include "vs_dc_hw.h"
+#include "vs_plane.h"
+
+#define fourcc_mod_vs_get_type(val) \
+			(((val) & DRM_FORMAT_MOD_VS_TYPE_MASK) >> 54)
+
+struct vs_dc_plane {
+	enum dc_hw_plane_id id;
+};
+
+enum vout_clk {
+	CLK_VOUT_NOC_DISP = 0,
+	CLK_VOUT_PIX0,
+	CLK_VOUT_PIX1,
+	CLK_VOUT_AXI,
+	CLK_VOUT_CORE,
+	CLK_VOUT_AHB,
+	CLK_VOUT_HDMI_PIX,
+	CLK_VOUT_SOC_PIX,
+	CLK_VOUT_NUM
+};
+
+enum rst_vout {
+	RST_VOUT_AXI = 0,
+	RST_VOUT_AHB,
+	RST_VOUT_CORE,
+	RST_VOUT_NUM
+};
+
+struct vs_dc {
+	struct vs_crtc		*crtc[DC_DISPLAY_NUM];
+	struct dc_hw		hw;
+	void __iomem        *dss_reg;
+	bool			    first_frame;
+
+	struct vs_dc_plane  planes[PLANE_NUM];
+	struct clk_bulk_data clk_vout[CLK_VOUT_NUM];
+	int nclks;
+	struct reset_control_bulk_data rst_vout[RST_VOUT_NUM];
+	int nrsts;
+};
+
+extern struct platform_driver dc_platform_driver;
+
+#endif /* __VS_DC_H__ */
diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.c b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
new file mode 100644
index 000000000000..d370dd401084
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
@@ -0,0 +1,2008 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#include <linux/bits.h>
+#include <linux/io.h>
+#include <linux/media-bus-format.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_fourcc.h>
+#include <drm/vs_drm.h>
+
+#include "vs_dc_hw.h"
+#include "vs_type.h"
+
+static const u32 horkernel[] = {
+	0x00000000, 0x20000000, 0x00002000, 0x00000000,
+	0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
+	0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
+	0x00000000, 0x00000000, 0x00000000, 0x2b981468,
+	0x00000000, 0x00000000, 0x00000000, 0x10f00000,
+	0x00002f10, 0x00000000, 0x00000000, 0x00000000,
+	0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
+	0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
+	0x00000000, 0x3781087f, 0x00000000, 0x00000000,
+	0x00000000, 0x06660000, 0x0000399a, 0x00000000,
+	0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
+	0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
+	0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
+	0x00000000, 0x00000000, 0x00000000, 0x01470000,
+	0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
+	0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
+	0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
+	0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00004000, 0x00000000,
+	0x00000000, 0x00000000, 0x20002000, 0x00000000,
+	0x00000000, 0x00000000, 0x1c030000, 0x000023fd,
+	0x00000000, 0x00000000, 0x00000000, 0x27e1181f,
+	0x00000000, 0x00000000, 0x00000000, 0x14680000,
+	0x00002b98, 0x00000000, 0x00000000, 0x00000000,
+	0x2f1010f0, 0x00000000, 0x00000000, 0x00000000,
+	0x0dc70000, 0x00003239, 0x00000000, 0x00000000,
+	0x00000000, 0x350b0af5, 0x00000000, 0x00000000,
+	0x00000000, 0x087f0000, 0x00003781, 0x00000000,
+	0x00000000, 0x00000000, 0x399a0666, 0x00000000,
+	0x00000000, 0x00000000, 0x04a70000, 0x00003b59,
+	0x00000000, 0x00000000, 0x00000000, 0x3cc4033c,
+	0x00000000, 0x00000000, 0x00000000, 0x021f0000,
+};
+
+#define H_COEF_SIZE (sizeof(horkernel) / sizeof(u32))
+
+static const u32 verkernel[] = {
+	0x00000000, 0x20000000, 0x00002000, 0x00000000,
+	0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
+	0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
+	0x00000000, 0x00000000, 0x00000000, 0x2b981468,
+	0x00000000, 0x00000000, 0x00000000, 0x10f00000,
+	0x00002f10, 0x00000000, 0x00000000, 0x00000000,
+	0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
+	0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
+	0x00000000, 0x3781087f, 0x00000000, 0x00000000,
+	0x00000000, 0x06660000, 0x0000399a, 0x00000000,
+	0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
+	0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
+	0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
+	0x00000000, 0x00000000, 0x00000000, 0x01470000,
+	0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
+	0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
+	0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
+	0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00004000, 0x00000000,
+	0xcdcd0000, 0xfdfdfdfd, 0xabababab, 0xabababab,
+	0x00000000, 0x00000000, 0x5ff5f456, 0x000f5f58,
+	0x02cc6c78, 0x02cc0c28, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+};
+
+#define V_COEF_SIZE (sizeof(verkernel) / sizeof(u32))
+
+/*
+ * RGB 709->2020 conversion parameters
+ */
+static u16 RGB2RGB[RGB_TO_RGB_TABLE_SIZE] = {
+	10279,	5395,	709,
+	1132,	15065,	187,
+	269,	1442,	14674
+};
+
+/*
+ * YUV601 to RGB conversion parameters
+ * YUV2RGB[0]  - [8] : C0 - C8;
+ * YUV2RGB[9]  - [11]: D0 - D2;
+ * YUV2RGB[12] - [13]: Y clamp min & max calue;
+ * YUV2RGB[14] - [15]: UV clamp min & max calue;
+ */
+static s32 YUV601_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
+	1196,	0,			1640,	1196,
+	-404,	-836,		1196,	2076,
+	0,		-916224,	558336,	-1202944,
+	64,		 940,		64,		960
+};
+
+/*
+ * YUV709 to RGB conversion parameters
+ * YUV2RGB[0]  - [8] : C0 - C8;
+ * YUV2RGB[9]  - [11]: D0 - D2;
+ * YUV2RGB[12] - [13]: Y clamp min & max calue;
+ * YUV2RGB[14] - [15]: UV clamp min & max calue;
+ */
+static s32 YUV709_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
+	1196,		0,		1844,	1196,
+	-220,		-548,	1196,	2172,
+	0,			-1020672, 316672,  -1188608,
+	64,			940,		64,		960
+};
+
+/*
+ * YUV2020 to RGB conversion parameters
+ * YUV2RGB[0]  - [8] : C0 - C8;
+ * YUV2RGB[9]  - [11]: D0 - D2;
+ * YUV2RGB[12] - [13]: Y clamp min & max calue;
+ * YUV2RGB[14] - [15]: UV clamp min & max calue;
+ */
+static s32 YUV2020_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
+	1196, 0, 1724, 1196,
+	-192, -668, 1196, 2200,
+	0, -959232, 363776, -1202944,
+	64, 940, 64, 960
+};
+
+/*
+ * RGB to YUV2020 conversion parameters
+ * RGB2YUV[0] - [8] : C0 - C8;
+ * RGB2YUV[9] - [11]: D0 - D2;
+ */
+static s16 RGB2YUV[RGB_TO_YUV_TABLE_SIZE] = {
+	230,	594,	52,
+	-125,  -323,	448,
+	448,   -412,   -36,
+	64,		512,	512
+};
+
+/*
+ * Degamma table for 709 color space data.
+ */
+static u16 DEGAMMA_709[DEGAMMA_SIZE] = {
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0005,
+	0x0007, 0x000a, 0x000d, 0x0011, 0x0015, 0x0019, 0x001e, 0x0024,
+	0x002a, 0x0030, 0x0038, 0x003f, 0x0048, 0x0051, 0x005a, 0x0064,
+	0x006f, 0x007b, 0x0087, 0x0094, 0x00a1, 0x00af, 0x00be, 0x00ce,
+	0x00de, 0x00ef, 0x0101, 0x0114, 0x0127, 0x013b, 0x0150, 0x0166,
+	0x017c, 0x0193, 0x01ac, 0x01c4, 0x01de, 0x01f9, 0x0214, 0x0230,
+	0x024d, 0x026b, 0x028a, 0x02aa, 0x02ca, 0x02ec, 0x030e, 0x0331,
+	0x0355, 0x037a, 0x03a0, 0x03c7, 0x03ef, 0x0418, 0x0441, 0x046c,
+	0x0498, 0x04c4, 0x04f2, 0x0520, 0x0550, 0x0581, 0x05b2, 0x05e5,
+	0x0618, 0x064d, 0x0682, 0x06b9, 0x06f0, 0x0729, 0x0763, 0x079d,
+	0x07d9, 0x0816, 0x0854, 0x0893, 0x08d3, 0x0914, 0x0956, 0x0999,
+	0x09dd, 0x0a23, 0x0a69, 0x0ab1, 0x0afa, 0x0b44, 0x0b8f, 0x0bdb,
+	0x0c28, 0x0c76, 0x0cc6, 0x0d17, 0x0d69, 0x0dbb, 0x0e10, 0x0e65,
+	0x0ebb, 0x0f13, 0x0f6c, 0x0fc6, 0x1021, 0x107d, 0x10db, 0x113a,
+	0x119a, 0x11fb, 0x125d, 0x12c1, 0x1325, 0x138c, 0x13f3, 0x145b,
+	0x14c5, 0x1530, 0x159c, 0x160a, 0x1678, 0x16e8, 0x175a, 0x17cc,
+	0x1840, 0x18b5, 0x192b, 0x19a3, 0x1a1c, 0x1a96, 0x1b11, 0x1b8e,
+	0x1c0c, 0x1c8c, 0x1d0c, 0x1d8e, 0x1e12, 0x1e96, 0x1f1c, 0x1fa3,
+	0x202c, 0x20b6, 0x2141, 0x21ce, 0x225c, 0x22eb, 0x237c, 0x240e,
+	0x24a1, 0x2536, 0x25cc, 0x2664, 0x26fc, 0x2797, 0x2832, 0x28cf,
+	0x296e, 0x2a0e, 0x2aaf, 0x2b51, 0x2bf5, 0x2c9b, 0x2d41, 0x2dea,
+	0x2e93, 0x2f3e, 0x2feb, 0x3099, 0x3148, 0x31f9, 0x32ab, 0x335f,
+	0x3414, 0x34ca, 0x3582, 0x363c, 0x36f7, 0x37b3, 0x3871, 0x3930,
+	0x39f1, 0x3ab3, 0x3b77, 0x3c3c, 0x3d02, 0x3dcb, 0x3e94, 0x3f5f,
+	0x402c, 0x40fa, 0x41ca, 0x429b, 0x436d, 0x4442, 0x4517, 0x45ee,
+	0x46c7, 0x47a1, 0x487d, 0x495a, 0x4a39, 0x4b19, 0x4bfb, 0x4cde,
+	0x4dc3, 0x4eaa, 0x4f92, 0x507c, 0x5167, 0x5253, 0x5342, 0x5431,
+	0x5523, 0x5616, 0x570a, 0x5800, 0x58f8, 0x59f1, 0x5aec, 0x5be9,
+	0x5ce7, 0x5de6, 0x5ee7, 0x5fea, 0x60ef, 0x61f5, 0x62fc, 0x6406,
+	0x6510, 0x661d, 0x672b, 0x683b, 0x694c, 0x6a5f, 0x6b73, 0x6c8a,
+	0x6da2, 0x6ebb, 0x6fd6, 0x70f3, 0x7211, 0x7331, 0x7453, 0x7576,
+	0x769b, 0x77c2, 0x78ea, 0x7a14, 0x7b40, 0x7c6d, 0x7d9c, 0x7ecd,
+	0x3f65, 0x3f8c, 0x3fb2, 0x3fd8
+};
+
+/*
+ * Degamma table for 2020 color space data.
+ */
+static u16 DEGAMMA_2020[DEGAMMA_SIZE] = {
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003,
+	0x0003, 0x0003, 0x0004, 0x0004, 0x0004, 0x0005, 0x0005, 0x0006,
+	0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, 0x0009, 0x000a,
+	0x000a, 0x000b, 0x000c, 0x000c, 0x000d, 0x000e, 0x000f, 0x000f,
+	0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0016, 0x0017, 0x0018,
+	0x0019, 0x001b, 0x001c, 0x001e, 0x001f, 0x0021, 0x0022, 0x0024,
+	0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, 0x0033, 0x0035,
+	0x0038, 0x003a, 0x003d, 0x0040, 0x0043, 0x0046, 0x0049, 0x004d,
+	0x0050, 0x0054, 0x0057, 0x005b, 0x005f, 0x0064, 0x0068, 0x006d,
+	0x0071, 0x0076, 0x007c, 0x0081, 0x0086, 0x008c, 0x0092, 0x0098,
+	0x009f, 0x00a5, 0x00ac, 0x00b4, 0x00bb, 0x00c3, 0x00cb, 0x00d3,
+	0x00dc, 0x00e5, 0x00ee, 0x00f8, 0x0102, 0x010c, 0x0117, 0x0123,
+	0x012e, 0x013a, 0x0147, 0x0154, 0x0161, 0x016f, 0x017e, 0x018d,
+	0x019c, 0x01ac, 0x01bd, 0x01ce, 0x01e0, 0x01f3, 0x0206, 0x021a,
+	0x022f, 0x0244, 0x025a, 0x0272, 0x0289, 0x02a2, 0x02bc, 0x02d6,
+	0x02f2, 0x030f, 0x032c, 0x034b, 0x036b, 0x038b, 0x03ae, 0x03d1,
+	0x03f5, 0x041b, 0x0443, 0x046b, 0x0495, 0x04c1, 0x04ee, 0x051d,
+	0x054e, 0x0580, 0x05b4, 0x05ea, 0x0622, 0x065c, 0x0698, 0x06d6,
+	0x0717, 0x075a, 0x079f, 0x07e7, 0x0831, 0x087e, 0x08cd, 0x0920,
+	0x0976, 0x09ce, 0x0a2a, 0x0a89, 0x0aec, 0x0b52, 0x0bbc, 0x0c2a,
+	0x0c9b, 0x0d11, 0x0d8b, 0x0e0a, 0x0e8d, 0x0f15, 0x0fa1, 0x1033,
+	0x10ca, 0x1167, 0x120a, 0x12b2, 0x1360, 0x1415, 0x14d1, 0x1593,
+	0x165d, 0x172e, 0x1806, 0x18e7, 0x19d0, 0x1ac1, 0x1bbb, 0x1cbf,
+	0x1dcc, 0x1ee3, 0x2005, 0x2131, 0x2268, 0x23ab, 0x24fa, 0x2656,
+	0x27be, 0x2934, 0x2ab8, 0x2c4a, 0x2dec, 0x2f9d, 0x315f, 0x3332,
+	0x3516, 0x370d, 0x3916, 0x3b34, 0x3d66, 0x3fad, 0x420b, 0x4480,
+	0x470d, 0x49b3, 0x4c73, 0x4f4e, 0x5246, 0x555a, 0x588e, 0x5be1,
+	0x5f55, 0x62eb, 0x66a6, 0x6a86, 0x6e8c, 0x72bb, 0x7714, 0x7b99,
+	0x3dcb, 0x3e60, 0x3ef5, 0x3f8c
+};
+
+/* one is for primary plane and the other is for all overlay planes */
+static const struct dc_hw_plane_reg dc_plane_reg[] = {
+	{
+	.y_address		= DC_FRAMEBUFFER_ADDRESS,
+	.u_address		= DC_FRAMEBUFFER_U_ADDRESS,
+	.v_address		= DC_FRAMEBUFFER_V_ADDRESS,
+	.y_stride		= DC_FRAMEBUFFER_STRIDE,
+	.u_stride		= DC_FRAMEBUFFER_U_STRIDE,
+	.v_stride		= DC_FRAMEBUFFER_V_STRIDE,
+	.size			= DC_FRAMEBUFFER_SIZE,
+	.top_left		= DC_FRAMEBUFFER_TOP_LEFT,
+	.bottom_right	= DC_FRAMEBUFFER_BOTTOM_RIGHT,
+	.scale_factor_x			= DC_FRAMEBUFFER_SCALE_FACTOR_X,
+	.scale_factor_y			= DC_FRAMEBUFFER_SCALE_FACTOR_Y,
+	.h_filter_coef_index	= DC_FRAMEBUFFER_H_FILTER_COEF_INDEX,
+	.h_filter_coef_data		= DC_FRAMEBUFFER_H_FILTER_COEF_DATA,
+	.v_filter_coef_index	= DC_FRAMEBUFFER_V_FILTER_COEF_INDEX,
+	.v_filter_coef_data		= DC_FRAMEBUFFER_V_FILTER_COEF_DATA,
+	.init_offset			= DC_FRAMEBUFFER_INIT_OFFSET,
+	.color_key				= DC_FRAMEBUFFER_COLOR_KEY,
+	.color_key_high			= DC_FRAMEBUFFER_COLOR_KEY_HIGH,
+	.clear_value			= DC_FRAMEBUFFER_CLEAR_VALUE,
+	.color_table_index		= DC_FRAMEBUFFER_COLOR_TABLE_INDEX,
+	.color_table_data		= DC_FRAMEBUFFER_COLOR_TABLE_DATA,
+	.scale_config			= DC_FRAMEBUFFER_SCALE_CONFIG,
+	.water_mark				= DC_FRAMEBUFFER_WATER_MARK,
+	.degamma_index			= DC_FRAMEBUFFER_DEGAMMA_INDEX,
+	.degamma_data			= DC_FRAMEBUFFER_DEGAMMA_DATA,
+	.degamma_ex_data		= DC_FRAMEBUFFER_DEGAMMA_EX_DATA,
+	.src_global_color		= DC_FRAMEBUFFER_SRC_GLOBAL_COLOR,
+	.dst_global_color		= DC_FRAMEBUFFER_DST_GLOBAL_COLOR,
+	.blend_config			= DC_FRAMEBUFFER_BLEND_CONFIG,
+	.roi_origin				= DC_FRAMEBUFFER_ROI_ORIGIN,
+	.roi_size				= DC_FRAMEBUFFER_ROI_SIZE,
+	.yuv_to_rgb_coef0			= DC_FRAMEBUFFER_YUVTORGB_COEF0,
+	.yuv_to_rgb_coef1			= DC_FRAMEBUFFER_YUVTORGB_COEF1,
+	.yuv_to_rgb_coef2			= DC_FRAMEBUFFER_YUVTORGB_COEF2,
+	.yuv_to_rgb_coef3			= DC_FRAMEBUFFER_YUVTORGB_COEF3,
+	.yuv_to_rgb_coef4			= DC_FRAMEBUFFER_YUVTORGB_COEF4,
+	.yuv_to_rgb_coefd0			= DC_FRAMEBUFFER_YUVTORGB_COEFD0,
+	.yuv_to_rgb_coefd1			= DC_FRAMEBUFFER_YUVTORGB_COEFD1,
+	.yuv_to_rgb_coefd2			= DC_FRAMEBUFFER_YUVTORGB_COEFD2,
+	.y_clamp_bound				= DC_FRAMEBUFFER_Y_CLAMP_BOUND,
+	.uv_clamp_bound				= DC_FRAMEBUFFER_UV_CLAMP_BOUND,
+	.rgb_to_rgb_coef0			= DC_FRAMEBUFFER_RGBTORGB_COEF0,
+	.rgb_to_rgb_coef1			= DC_FRAMEBUFFER_RGBTORGB_COEF1,
+	.rgb_to_rgb_coef2			= DC_FRAMEBUFFER_RGBTORGB_COEF2,
+	.rgb_to_rgb_coef3			= DC_FRAMEBUFFER_RGBTORGB_COEF3,
+	.rgb_to_rgb_coef4			= DC_FRAMEBUFFER_RGBTORGB_COEF4,
+	},
+	{
+	.y_address		= DC_OVERLAY_ADDRESS,
+	.u_address		= DC_OVERLAY_U_ADDRESS,
+	.v_address		= DC_OVERLAY_V_ADDRESS,
+	.y_stride		= DC_OVERLAY_STRIDE,
+	.u_stride		= DC_OVERLAY_U_STRIDE,
+	.v_stride		= DC_OVERLAY_V_STRIDE,
+	.size			= DC_OVERLAY_SIZE,
+	.top_left		= DC_OVERLAY_TOP_LEFT,
+	.bottom_right	= DC_OVERLAY_BOTTOM_RIGHT,
+	.scale_factor_x	= DC_OVERLAY_SCALE_FACTOR_X,
+	.scale_factor_y	= DC_OVERLAY_SCALE_FACTOR_Y,
+	.h_filter_coef_index = DC_OVERLAY_H_FILTER_COEF_INDEX,
+	.h_filter_coef_data  = DC_OVERLAY_H_FILTER_COEF_DATA,
+	.v_filter_coef_index = DC_OVERLAY_V_FILTER_COEF_INDEX,
+	.v_filter_coef_data  = DC_OVERLAY_V_FILTER_COEF_DATA,
+	.init_offset		 = DC_OVERLAY_INIT_OFFSET,
+	.color_key			 = DC_OVERLAY_COLOR_KEY,
+	.color_key_high			= DC_OVERLAY_COLOR_KEY_HIGH,
+	.clear_value		 = DC_OVERLAY_CLEAR_VALUE,
+	.color_table_index	 = DC_OVERLAY_COLOR_TABLE_INDEX,
+	.color_table_data	 = DC_OVERLAY_COLOR_TABLE_DATA,
+	.scale_config		 = DC_OVERLAY_SCALE_CONFIG,
+	.water_mark				= DC_OVERLAY_WATER_MARK,
+	.degamma_index		 = DC_OVERLAY_DEGAMMA_INDEX,
+	.degamma_data		 = DC_OVERLAY_DEGAMMA_DATA,
+	.degamma_ex_data	 = DC_OVERLAY_DEGAMMA_EX_DATA,
+	.src_global_color	 = DC_OVERLAY_SRC_GLOBAL_COLOR,
+	.dst_global_color	 = DC_OVERLAY_DST_GLOBAL_COLOR,
+	.blend_config		 = DC_OVERLAY_BLEND_CONFIG,
+	.roi_origin				= DC_OVERLAY_ROI_ORIGIN,
+	.roi_size				= DC_OVERLAY_ROI_SIZE,
+	.yuv_to_rgb_coef0		 = DC_OVERLAY_YUVTORGB_COEF0,
+	.yuv_to_rgb_coef1		 = DC_OVERLAY_YUVTORGB_COEF1,
+	.yuv_to_rgb_coef2		 = DC_OVERLAY_YUVTORGB_COEF2,
+	.yuv_to_rgb_coef3		 = DC_OVERLAY_YUVTORGB_COEF3,
+	.yuv_to_rgb_coef4			= DC_OVERLAY_YUVTORGB_COEF4,
+	.yuv_to_rgb_coefd0			= DC_OVERLAY_YUVTORGB_COEFD0,
+	.yuv_to_rgb_coefd1			= DC_OVERLAY_YUVTORGB_COEFD1,
+	.yuv_to_rgb_coefd2			= DC_OVERLAY_YUVTORGB_COEFD2,
+	.y_clamp_bound		 = DC_OVERLAY_Y_CLAMP_BOUND,
+	.uv_clamp_bound		 = DC_OVERLAY_UV_CLAMP_BOUND,
+	.rgb_to_rgb_coef0		 = DC_OVERLAY_RGBTORGB_COEF0,
+	.rgb_to_rgb_coef1		 = DC_OVERLAY_RGBTORGB_COEF1,
+	.rgb_to_rgb_coef2		 = DC_OVERLAY_RGBTORGB_COEF2,
+	.rgb_to_rgb_coef3		 = DC_OVERLAY_RGBTORGB_COEF3,
+	.rgb_to_rgb_coef4		 = DC_OVERLAY_RGBTORGB_COEF4,
+	},
+};
+
+static const u32 primary_overlay_format0[] = {
+	DRM_FORMAT_XRGB4444,
+	DRM_FORMAT_XBGR4444,
+	DRM_FORMAT_RGBX4444,
+	DRM_FORMAT_BGRX4444,
+	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_ABGR4444,
+	DRM_FORMAT_RGBA4444,
+	DRM_FORMAT_BGRA4444,
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_XBGR1555,
+	DRM_FORMAT_RGBX5551,
+	DRM_FORMAT_BGRX5551,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_ABGR1555,
+	DRM_FORMAT_RGBA5551,
+	DRM_FORMAT_BGRA5551,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_BGRX8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_BGRA8888,
+	DRM_FORMAT_ARGB2101010,
+	DRM_FORMAT_ABGR2101010,
+	DRM_FORMAT_RGBA1010102,
+	DRM_FORMAT_BGRA1010102,
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_VYUY,
+	DRM_FORMAT_YVU420,
+	DRM_FORMAT_YUV420,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV21,
+	DRM_FORMAT_NV16,
+	DRM_FORMAT_NV61,
+	DRM_FORMAT_P010,
+};
+
+static const u32 primary_overlay_format1[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_BGRX8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_BGRA8888,
+	DRM_FORMAT_ARGB2101010,
+	DRM_FORMAT_ABGR2101010,
+	DRM_FORMAT_RGBA1010102,
+	DRM_FORMAT_BGRA1010102,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV21,
+	DRM_FORMAT_YUV444,
+};
+
+static const u32 cursor_formats[] = {
+	DRM_FORMAT_ARGB8888
+};
+
+static const u64 format_modifier0[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_LINEAR),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_TILE_8X8),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_TILE_8X4),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8),
+	DRM_FORMAT_MOD_INVALID
+};
+
+static const u64 format_modifier1[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_LINEAR),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_TILE_8X8),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_TILE_8X4),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_TILE_MODE4X4),
+	fourcc_mod_vs_custom_code(DRM_FORMAT_MOD_VS_TILE_MODE4X4),
+	DRM_FORMAT_MOD_INVALID
+};
+
+static const u64 secondary_format_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
+#define FRAC_16_16(mult, div)	 (((mult) << 16) / (div))
+
+static const struct vs_plane_info dc_hw_planes[][PLANE_NUM] = {
+	{
+		/* DC_REV_0 */
+		{
+		.name			= "Primary",
+		.id				= PRIMARY_PLANE_0,
+		.type			= DRM_PLANE_TYPE_PRIMARY,
+		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
+		.formats		= primary_overlay_format0,
+		.num_modifiers	= ARRAY_SIZE(format_modifier0),
+		.modifiers		= format_modifier0,
+		.min_width		= 0,
+		.min_height		= 0,
+		.max_width		= 4096,
+		.max_height		= 4096,
+		.rotation		= DRM_MODE_ROTATE_0 |
+							DRM_MODE_ROTATE_90 |
+							DRM_MODE_ROTATE_180 |
+							DRM_MODE_ROTATE_270 |
+							DRM_MODE_REFLECT_X |
+							DRM_MODE_REFLECT_Y,
+		.blend_mode		= BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+							BIT(DRM_MODE_BLEND_PREMULTI) |
+							BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 0,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name			= "Overlay",
+		.id				= OVERLAY_PLANE_0,
+		.type			= DRM_PLANE_TYPE_OVERLAY,
+		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
+		.formats		= primary_overlay_format0,
+		.num_modifiers	= ARRAY_SIZE(format_modifier0),
+		.modifiers		= format_modifier0,
+		.min_width		= 0,
+		.min_height		= 0,
+		.max_width		= 4096,
+		.max_height		= 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 1,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name			= "Overlay_1",
+		.id				= OVERLAY_PLANE_1,
+		.type			= DRM_PLANE_TYPE_OVERLAY,
+		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
+		.formats		= primary_overlay_format0,
+		.num_modifiers	= ARRAY_SIZE(secondary_format_modifiers),
+		.modifiers		= secondary_format_modifiers,
+		.min_width		= 0,
+		.min_height		= 0,
+		.max_width		= 4096,
+		.max_height		= 4096,
+		.rotation		= 0,
+		.blend_mode		= BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+							BIT(DRM_MODE_BLEND_PREMULTI) |
+							BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 2,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Primary_1",
+		.id				= PRIMARY_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_PRIMARY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 3,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_2",
+		.id				= OVERLAY_PLANE_2,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 4,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_3",
+		.id			= OVERLAY_PLANE_3,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
+		.modifiers	 = secondary_format_modifiers,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = 0,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 5,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Cursor",
+		.id				= CURSOR_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+		{
+		.name		 = "Cursor_1",
+		.id				= CURSOR_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+	},
+	{
+		/* DC_REV_1 */
+		{
+		.name		 = "Primary",
+		.id				= PRIMARY_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_PRIMARY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 0,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay",
+		.id				= OVERLAY_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 1,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Primary_1",
+		.id				= PRIMARY_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_PRIMARY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 2,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_2",
+		.id				= OVERLAY_PLANE_2,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 3,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Cursor",
+		.id				= CURSOR_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+		{
+		.name		 = "Cursor_1",
+		.id				= CURSOR_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+	},
+	{
+		/* DC_REV_2 */
+		{
+		.name		 = "Primary",
+		.id				= PRIMARY_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_PRIMARY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(format_modifier1),
+		.modifiers	 = format_modifier1,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 0,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay",
+		.id				= OVERLAY_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(format_modifier1),
+		.modifiers	 = format_modifier1,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 1,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_1",
+		.id				= OVERLAY_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
+		.modifiers	 = secondary_format_modifiers,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = 0,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 2,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Primary_1",
+		.id				= PRIMARY_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_PRIMARY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(format_modifier1),
+		.modifiers	 = format_modifier1,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 3,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_2",
+		.id				= OVERLAY_PLANE_2,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(format_modifier1),
+		.modifiers	 = format_modifier1,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 4,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_3",
+		.id				= OVERLAY_PLANE_3,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
+		.modifiers	 = secondary_format_modifiers,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = 0,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 5,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Cursor",
+		.id				= CURSOR_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+		{
+		.name		 = "Cursor_1",
+		.id				= CURSOR_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+	},
+};
+
+static const struct vs_dc_info dc_info[] = {
+	{
+		/* DC_REV_0 */
+		.name			= "DC8200",
+		.panel_num		= 2,
+		.plane_num		= 8,
+		.planes			= dc_hw_planes[DC_REV_0],
+		.layer_num		= 6,
+		.max_bpc		= 10,
+		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
+						  DRM_COLOR_FORMAT_YCBCR444 |
+						  DRM_COLOR_FORMAT_YCBCR422 |
+						  DRM_COLOR_FORMAT_YCBCR420,
+		.gamma_size		= GAMMA_EX_SIZE,
+		.gamma_bits		= 12,
+		.pitch_alignment	= 128,
+		.pipe_sync		= false,
+		.mmu_prefetch	= false,
+		.background		= true,
+		.panel_sync		= true,
+		.cap_dec		= true,
+	},
+	{
+		/* DC_REV_1 */
+		.name			= "DC8200",
+		.panel_num		= 2,
+		.plane_num		= 6,
+		.planes			= dc_hw_planes[DC_REV_1],
+		.layer_num		= 4,
+		.max_bpc		= 10,
+		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
+						  DRM_COLOR_FORMAT_YCBCR444 |
+						  DRM_COLOR_FORMAT_YCBCR422 |
+						  DRM_COLOR_FORMAT_YCBCR420,
+		.gamma_size		= GAMMA_EX_SIZE,
+		.gamma_bits		= 12,
+		.pitch_alignment	= 128,
+		.pipe_sync		= false,
+		.mmu_prefetch	= false,
+		.background		= true,
+		.panel_sync		= true,
+		.cap_dec		= true,
+	},
+	{
+		/* DC_REV_2 */
+		.name			= "DC8200",
+		.panel_num		= 2,
+		.plane_num		= 8,
+		.planes			= dc_hw_planes[DC_REV_2],
+		.layer_num		= 6,
+		.max_bpc		= 10,
+		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
+						  DRM_COLOR_FORMAT_YCBCR444 |
+						  DRM_COLOR_FORMAT_YCBCR422 |
+						  DRM_COLOR_FORMAT_YCBCR420,
+		.gamma_size		= GAMMA_EX_SIZE,
+		.gamma_bits		= 12,
+		.pitch_alignment	= 128,
+		.pipe_sync		= false,
+		.mmu_prefetch	= false,
+		.background		= true,
+		.panel_sync		= true,
+		.cap_dec		= false,
+	},
+};
+
+static const struct dc_hw_funcs hw_func;
+
+static inline u32 hi_read(struct dc_hw *hw, u32 reg)
+{
+	return readl(hw->hi_base + reg);
+}
+
+static inline void hi_write(struct dc_hw *hw, u32 reg, u32 value)
+{
+	writel(value, hw->hi_base + reg);
+}
+
+static inline void dc_write(struct dc_hw *hw, u32 reg, u32 value)
+{
+	writel(value, hw->reg_base + reg - DC_REG_BASE);
+}
+
+static inline u32 dc_read(struct dc_hw *hw, u32 reg)
+{
+	u32 value = readl(hw->reg_base + reg - DC_REG_BASE);
+
+	return value;
+}
+
+static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32 set, u32 clear)
+{
+	u32 value = dc_read(hw, reg);
+
+	value &= ~clear;
+	value |= set;
+	dc_write(hw, reg, value);
+}
+
+static void load_default_filter(struct dc_hw *hw,
+				const struct dc_hw_plane_reg *reg, u32 offset)
+{
+	u8 i;
+
+	dc_write(hw, reg->scale_config + offset, 0x33);
+	dc_write(hw, reg->init_offset + offset, 0x80008000);
+	dc_write(hw, reg->h_filter_coef_index + offset, 0x00);
+	for (i = 0; i < H_COEF_SIZE; i++)
+		dc_write(hw, reg->h_filter_coef_data + offset, horkernel[i]);
+
+	dc_write(hw, reg->v_filter_coef_index + offset, 0x00);
+	for (i = 0; i < V_COEF_SIZE; i++)
+		dc_write(hw, reg->v_filter_coef_data + offset, verkernel[i]);
+}
+
+static void load_rgb_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
+			    u32 offset, u16 *table)
+{
+	dc_write(hw, reg->rgb_to_rgb_coef0 + offset, table[0] | (table[1] << 16));
+	dc_write(hw, reg->rgb_to_rgb_coef1 + offset, table[2] | (table[3] << 16));
+	dc_write(hw, reg->rgb_to_rgb_coef2 + offset, table[4] | (table[5] << 16));
+	dc_write(hw, reg->rgb_to_rgb_coef3 + offset, table[6] | (table[7] << 16));
+	dc_write(hw, reg->rgb_to_rgb_coef4 + offset, table[8]);
+}
+
+static void load_yuv_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
+			    u32 offset, s32 *table)
+{
+	dc_write(hw, reg->yuv_to_rgb_coef0 + offset,
+		 (0xFFFF & table[0]) | (table[1] << 16));
+	dc_write(hw, reg->yuv_to_rgb_coef1 + offset,
+		 (0xFFFF & table[2]) | (table[3] << 16));
+	dc_write(hw, reg->yuv_to_rgb_coef2 + offset,
+		 (0xFFFF & table[4]) | (table[5] << 16));
+	dc_write(hw, reg->yuv_to_rgb_coef3 + offset,
+		 (0xFFFF & table[6]) | (table[7] << 16));
+	dc_write(hw, reg->yuv_to_rgb_coef4 + offset, table[8]);
+	dc_write(hw, reg->yuv_to_rgb_coefd0 + offset, table[9]);
+	dc_write(hw, reg->yuv_to_rgb_coefd1 + offset, table[10]);
+	dc_write(hw, reg->yuv_to_rgb_coefd2 + offset, table[11]);
+	dc_write(hw, reg->y_clamp_bound + offset, table[12] | (table[13] << 16));
+	dc_write(hw, reg->uv_clamp_bound + offset, table[14] | (table[15] << 16));
+}
+
+static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16 *table)
+{
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF0 + offset,
+		 table[0] | (table[1] << 16));
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF1 + offset,
+		 table[2] | (table[3] << 16));
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF2 + offset,
+		 table[4] | (table[5] << 16));
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF3 + offset,
+		 table[6] | (table[7] << 16));
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF4 + offset, table[8]);
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD0 + offset, table[9]);
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD1 + offset, table[10]);
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD2 + offset, table[11]);
+}
+
+static bool is_rgb(enum dc_hw_color_format format)
+{
+	switch (format) {
+	case FORMAT_X4R4G4B4:
+	case FORMAT_A4R4G4B4:
+	case FORMAT_X1R5G5B5:
+	case FORMAT_A1R5G5B5:
+	case FORMAT_R5G6B5:
+	case FORMAT_X8R8G8B8:
+	case FORMAT_A8R8G8B8:
+	case FORMAT_A2R10G10B10:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void load_degamma_table(struct dc_hw *hw,
+			       const struct dc_hw_plane_reg *reg,
+			       u32 offset, u16 *table)
+{
+	u16 i;
+	u32 value;
+
+	dc_write(hw, reg->degamma_index + offset, 0);
+
+	for (i = 0; i < DEGAMMA_SIZE; i++) {
+		value = table[i] | (table[i] << 16);
+		dc_write(hw, reg->degamma_data + offset, value);
+		dc_write(hw, reg->degamma_ex_data + offset, table[i]);
+	}
+}
+
+static u32 get_addr_offset(u32 id)
+{
+	u32 offset = 0;
+
+	switch (id) {
+	case PRIMARY_PLANE_1:
+	case OVERLAY_PLANE_1:
+		offset = 0x04;
+		break;
+	case OVERLAY_PLANE_2:
+		offset = 0x08;
+		break;
+	case OVERLAY_PLANE_3:
+		offset = 0x0C;
+		break;
+	default:
+		break;
+	}
+
+	return offset;
+}
+
+int dc_hw_init(struct dc_hw *hw)
+{
+	u8 i, id, panel_num, layer_num;
+	u32 offset;
+	u32 revision = hi_read(hw, DC_HW_REVISION);
+	u32 cid = hi_read(hw, DC_HW_CHIP_CID);
+	const struct dc_hw_plane_reg *reg;
+
+	switch (revision) {
+	case 0x5720:
+		hw->rev = DC_REV_0;
+		break;
+	case 0x5721:
+		switch (cid) {
+		case 0x30B:
+			hw->rev = DC_REV_1;
+			break;
+		case 0x310:
+			hw->rev = DC_REV_2;
+			break;
+		default:
+			hw->rev = DC_REV_0;
+			break;
+		}
+		break;
+	default:
+		return -ENXIO;
+	}
+
+	hw->info = (struct vs_dc_info *)&dc_info[hw->rev];
+	hw->func = (struct dc_hw_funcs *)&hw_func;
+
+	layer_num = hw->info->layer_num;
+	for (i = 0; i < layer_num; i++) {
+		id = hw->info->planes[i].id;
+		offset = get_addr_offset(id);
+		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+			reg = &dc_plane_reg[0];
+		else
+			reg = &dc_plane_reg[1];
+
+		load_default_filter(hw, reg, offset);
+		load_rgb_to_rgb(hw, reg, offset, RGB2RGB);
+	}
+
+	panel_num = hw->info->panel_num;
+	for (i = 0; i < panel_num; i++) {
+		offset = i << 2;
+
+		load_rgb_to_yuv(hw, offset, RGB2YUV);
+		dc_write(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0x111);
+
+		offset = i ? DC_CURSOR_OFFSET : 0;
+		dc_write(hw, DC_CURSOR_BACKGROUND + offset, 0x00FFFFFF);
+		dc_write(hw, DC_CURSOR_FOREGROUND + offset, 0x00AAAAAA);
+	}
+
+	return 0;
+}
+
+void dc_hw_deinit(struct dc_hw *hw)
+{
+	/* Nothing to do */
+}
+
+void dc_hw_update_plane(struct dc_hw *hw, u8 id,
+			struct dc_hw_fb *fb, struct dc_hw_scale *scale,
+			struct dc_hw_position *pos, struct dc_hw_blend *blend)
+{
+	struct dc_hw_plane *plane = &hw->plane[id];
+
+	if (plane) {
+		if (fb) {
+			if (!fb->enable)
+				plane->fb.enable = false;
+			else
+				memcpy(&plane->fb, fb,
+				       sizeof(*fb) - sizeof(fb->dirty));
+			plane->fb.dirty = true;
+		}
+		if (scale) {
+			memcpy(&plane->scale, scale,
+			       sizeof(*scale) - sizeof(scale->dirty));
+			plane->scale.dirty = true;
+		}
+		if (pos) {
+			memcpy(&plane->pos, pos,
+			       sizeof(*pos) - sizeof(pos->dirty));
+			plane->pos.dirty = true;
+		}
+		if (blend) {
+			memcpy(&plane->blend, blend,
+			       sizeof(*blend) - sizeof(blend->dirty));
+			plane->blend.dirty = true;
+		}
+	}
+}
+
+void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode)
+{
+	struct dc_hw_plane *plane = &hw->plane[id];
+
+	if (plane) {
+		if (hw->info->planes[id].degamma_size) {
+			plane->degamma.mode = mode;
+			plane->degamma.dirty = true;
+		} else {
+			plane->degamma.dirty = false;
+		}
+	}
+}
+
+void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi)
+{
+	struct dc_hw_plane *plane = &hw->plane[id];
+
+	if (plane) {
+		memcpy(&plane->roi, roi, sizeof(*roi) - sizeof(roi->dirty));
+		plane->roi.dirty = true;
+	}
+}
+
+void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
+			   struct dc_hw_colorkey *colorkey)
+{
+	struct dc_hw_plane *plane = &hw->plane[id];
+
+	if (plane) {
+		memcpy(&plane->colorkey, colorkey,
+		       sizeof(*colorkey) - sizeof(colorkey->dirty));
+		plane->colorkey.dirty = true;
+	}
+}
+
+void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos)
+{
+	memcpy(&hw->qos, qos, sizeof(*qos) - sizeof(qos->dirty));
+	hw->qos.dirty = true;
+}
+
+void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor)
+{
+	memcpy(&hw->cursor[id], cursor, sizeof(*cursor) - sizeof(cursor->dirty));
+	hw->cursor[id].dirty = true;
+}
+
+void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
+			u16 r, u16 g, u16 b)
+{
+	if (index >= hw->info->gamma_size)
+		return;
+
+	hw->gamma[id].gamma[index][0] = r;
+	hw->gamma[id].gamma[index][1] = g;
+	hw->gamma[id].gamma[index][2] = b;
+	hw->gamma[id].dirty = true;
+}
+
+void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable)
+{
+	hw->gamma[id].enable = enable;
+	hw->gamma[id].dirty = true;
+}
+
+void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display)
+{
+	u8 id = display->id;
+
+	memcpy(&hw->display[id], display, sizeof(*display));
+
+	hw->func->display(hw, display);
+}
+
+void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable)
+{
+	if (enable)
+		hi_write(hw, AQ_INTR_ENBL, 0xFFFFFFFF);
+	else
+		hi_write(hw, AQ_INTR_ENBL, 0);
+}
+
+u32 dc_hw_get_interrupt(struct dc_hw *hw)
+{
+	return hi_read(hw, AQ_INTR_ACKNOWLEDGE);
+}
+
+bool dc_hw_check_underflow(struct dc_hw *hw)
+{
+	return dc_read(hw, DC_FRAMEBUFFER_CONFIG) & BIT(5);
+}
+
+void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable)
+{
+	u32 i, offset;
+	u8 id, layer_num = hw->info->layer_num;
+	u8 panel_num = hw->info->panel_num;
+
+	for (i = 0; i < layer_num; i++) {
+		id = hw->info->planes[i].id;
+		offset = get_addr_offset(id);
+		if (enable) {
+			if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, BIT(12), 0);
+			else
+				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, BIT(31), 0);
+		} else {
+			if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, 0, BIT(12));
+			else
+				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, 0, BIT(31));
+		}
+	}
+
+	for (i = 0; i < panel_num; i++) {
+		offset = i << 2;
+		if (enable)
+			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, 0, BIT(0));
+		else
+			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, BIT(0), 0);
+	}
+}
+
+void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id)
+{
+	if (out <= OUT_DP)
+		hw->out[id] = out;
+}
+
+static void gamma_ex_commit(struct dc_hw *hw)
+{
+	u8 panel_num = hw->info->panel_num;
+	u16 i, j;
+	u32 value;
+
+	for (j = 0; j < panel_num; j++) {
+		if (hw->gamma[j].dirty) {
+			if (hw->gamma[j].enable) {
+				dc_write(hw, DC_DISPLAY_GAMMA_EX_INDEX + (j << 2), 0x00);
+				for (i = 0; i < GAMMA_EX_SIZE; i++) {
+					value = hw->gamma[j].gamma[i][2] |
+						(hw->gamma[j].gamma[i][1] << 12);
+					dc_write(hw, DC_DISPLAY_GAMMA_EX_DATA + (j << 2), value);
+					dc_write(hw, DC_DISPLAY_GAMMA_EX_ONE_DATA + (j << 2),
+						 hw->gamma[j].gamma[i][0]);
+				}
+				dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
+					     BIT(13), 0);
+			} else {
+				dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
+					     0, BIT(13));
+			}
+			hw->gamma[j].dirty = false;
+		}
+	}
+}
+
+static void plane_commit(struct dc_hw *hw)
+{
+	struct dc_hw_plane *plane;
+	const struct dc_hw_plane_reg *reg;
+	bool primary = false;
+	u8 id, layer_num = hw->info->layer_num;
+	u32 i, offset;
+
+	for (i = 0; i < layer_num; i++) {
+		plane = &hw->plane[i];
+		id = hw->info->planes[i].id;
+		offset = get_addr_offset(id);
+		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
+			reg = &dc_plane_reg[0];
+			primary = true;
+		} else {
+			reg = &dc_plane_reg[1];
+			primary = false;
+		}
+
+		if (plane->fb.dirty) {
+			if (plane->fb.enable) {
+				dc_write(hw, reg->y_address + offset,
+					 plane->fb.y_address);
+				dc_write(hw, reg->u_address + offset,
+					 plane->fb.u_address);
+				dc_write(hw, reg->v_address + offset,
+					 plane->fb.v_address);
+				dc_write(hw, reg->y_stride + offset,
+					 plane->fb.y_stride);
+				dc_write(hw, reg->u_stride + offset,
+					 plane->fb.u_stride);
+				dc_write(hw, reg->v_stride + offset,
+					 plane->fb.v_stride);
+				dc_write(hw, reg->size + offset,
+					 plane->fb.width |
+					 (plane->fb.height << 15));
+				dc_write(hw, reg->water_mark + offset,
+					 plane->fb.water_mark);
+
+				if (plane->fb.clear_enable)
+					dc_write(hw, reg->clear_value + offset,
+						 plane->fb.clear_value);
+			}
+
+			if (primary) {
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
+					     (plane->fb.format << 26) |
+					     (plane->fb.uv_swizzle << 25) |
+					     (plane->fb.swizzle << 23) |
+					     (plane->fb.tile_mode << 17) |
+					     (plane->fb.yuv_color_space << 14) |
+					     (plane->fb.rotation << 11) |
+					     (plane->fb.clear_enable << 8),
+					     (0x1F << 26) |
+					     BIT(25) |
+					     (0x03 << 23) |
+					     (0x1F << 17) |
+					     (0x07 << 14) |
+					     (0x07 << 11) |
+					     BIT(8));
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
+					     (plane->fb.dec_enable << 1) |
+					     (plane->fb.enable << 13) |
+					     (plane->fb.zpos << 16) |
+					     (plane->fb.display_id << 19),
+					     BIT(1) | BIT(13) | (0x07 << 16) | BIT(19));
+			} else {
+				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+					     (plane->fb.dec_enable << 27) |
+					     (plane->fb.clear_enable << 25) |
+					     (plane->fb.enable << 24) |
+					     (plane->fb.format << 16) |
+					     (plane->fb.uv_swizzle << 15) |
+					     (plane->fb.swizzle << 13) |
+					     (plane->fb.tile_mode << 8) |
+					     (plane->fb.yuv_color_space << 5) |
+					     (plane->fb.rotation << 2),
+					     BIT(27) |
+					     BIT(25) |
+					     BIT(24) |
+					     (0x1F << 16) |
+					     BIT(15) |
+					     (0x03 << 13) |
+					     (0x1F << 8) |
+					     (0x07 << 5) |
+					     (0x07 << 2));
+				dc_set_clear(hw, DC_OVERLAY_CONFIG_EX + offset,
+					     plane->fb.zpos | (plane->fb.display_id << 3),
+					     0x07 | BIT(3));
+			}
+			plane->fb.dirty = false;
+		}
+
+		if (plane->scale.dirty) {
+			if (plane->scale.enable) {
+				dc_write(hw, reg->scale_factor_x + offset,
+					 plane->scale.scale_factor_x);
+				dc_write(hw, reg->scale_factor_y + offset,
+					 plane->scale.scale_factor_y);
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG + offset,
+						     BIT(22), 0);
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_SCALE_CONFIG + offset,
+						     BIT(8), 0);
+			} else {
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG + offset,
+						     0, BIT(22));
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_SCALE_CONFIG + offset,
+						     0, BIT(8));
+			}
+			plane->scale.dirty = false;
+		}
+
+		if (plane->pos.dirty) {
+			dc_write(hw, reg->top_left + offset,
+				 plane->pos.start_x |
+				 (plane->pos.start_y << 15));
+			dc_write(hw, reg->bottom_right + offset,
+				 plane->pos.end_x |
+				 (plane->pos.end_y << 15));
+			plane->pos.dirty = false;
+		}
+
+		if (plane->blend.dirty) {
+			dc_write(hw, reg->src_global_color + offset,
+				 plane->blend.alpha << 24);
+			dc_write(hw, reg->dst_global_color + offset,
+				 plane->blend.alpha << 24);
+			switch (plane->blend.blend_mode) {
+			case BLEND_PREMULTI:
+				dc_write(hw, reg->blend_config + offset, 0x3450);
+				break;
+			case BLEND_COVERAGE:
+				dc_write(hw, reg->blend_config + offset, 0x3950);
+				break;
+			case BLEND_PIXEL_NONE:
+				dc_write(hw, reg->blend_config + offset, 0x3548);
+				break;
+			default:
+				break;
+			}
+			plane->blend.dirty = false;
+		}
+
+		if (plane->colorkey.dirty) {
+			dc_write(hw, reg->color_key + offset, plane->colorkey.colorkey);
+			dc_write(hw, reg->color_key_high + offset,
+				 plane->colorkey.colorkey_high);
+
+			if (primary)
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
+					     plane->colorkey.transparency << 9, 0x03 << 9);
+			else
+				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+					     plane->colorkey.transparency, 0x03);
+
+			plane->colorkey.dirty = false;
+		}
+
+		if (plane->roi.dirty) {
+			if (plane->roi.enable) {
+				dc_write(hw, reg->roi_origin + offset,
+					 plane->roi.x | (plane->roi.y << 16));
+				dc_write(hw, reg->roi_size + offset,
+					 plane->roi.width | (plane->roi.height << 16));
+				if (primary)
+					dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     BIT(0), 0);
+				else
+					dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+						     BIT(22), 0);
+			} else {
+				if (primary)
+					dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     0, BIT(0));
+				else
+					dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+						     0, BIT(22));
+			}
+			plane->roi.dirty = false;
+		}
+	}
+}
+
+static void plane_ex_commit(struct dc_hw *hw)
+{
+	struct dc_hw_plane *plane;
+	const struct dc_hw_plane_reg *reg;
+	bool primary = false;
+	u8 id, layer_num = hw->info->layer_num;
+	u32 i, offset;
+
+	for (i = 0; i < layer_num; i++) {
+		plane = &hw->plane[i];
+		id = hw->info->planes[i].id;
+		offset = get_addr_offset(id);
+		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
+			reg = &dc_plane_reg[0];
+			primary = true;
+		} else {
+			reg = &dc_plane_reg[1];
+			primary = false;
+		}
+
+		if (plane->fb.dirty) {
+			if (is_rgb(plane->fb.format)) {
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     BIT(6), BIT(8));
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_CONFIG + offset,
+						     BIT(29), BIT(30));
+			} else {
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     BIT(8), BIT(6));
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_CONFIG + offset,
+						     BIT(30), BIT(29));
+				switch (plane->fb.yuv_color_space) {
+				case COLOR_SPACE_601:
+					load_yuv_to_rgb(hw, reg, offset, YUV601_2RGB);
+					break;
+				case COLOR_SPACE_709:
+					load_yuv_to_rgb(hw, reg, offset, YUV709_2RGB);
+					break;
+				case COLOR_SPACE_2020:
+					load_yuv_to_rgb(hw, reg, offset, YUV2020_2RGB);
+					break;
+				default:
+					break;
+				}
+			}
+		}
+		if (plane->degamma.dirty) {
+			switch (plane->degamma.mode) {
+			case VS_DEGAMMA_DISABLE:
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     0, BIT(5));
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_CONFIG + offset,
+						     0, BIT(28));
+				break;
+			case VS_DEGAMMA_BT709:
+				load_degamma_table(hw, reg, offset, DEGAMMA_709);
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     BIT(5), 0);
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_CONFIG + offset,
+						     BIT(28), 0);
+				break;
+			case VS_DEGAMMA_BT2020:
+				load_degamma_table(hw, reg, offset, DEGAMMA_2020);
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     BIT(5), 0);
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_CONFIG + offset,
+						     BIT(28), 0);
+				break;
+			default:
+				break;
+			}
+			plane->degamma.dirty = false;
+		}
+	}
+	plane_commit(hw);
+}
+
+static void setup_display(struct dc_hw *hw, struct dc_hw_display *display)
+{
+	u8 id = display->id;
+	u32 dpi_cfg, offset = id << 2;
+
+	if (hw->display[id].enable) {
+		switch (display->bus_format) {
+		case MEDIA_BUS_FMT_RGB565_1X16:
+			dpi_cfg = 0;
+			break;
+		case MEDIA_BUS_FMT_RGB666_1X18:
+			dpi_cfg = 3;
+			break;
+		case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+			dpi_cfg = 4;
+			break;
+		case MEDIA_BUS_FMT_RGB888_1X24:
+			dpi_cfg = 5;
+			break;
+		case MEDIA_BUS_FMT_RGB101010_1X30:
+			dpi_cfg = 6;
+			break;
+		default:
+			dpi_cfg = 5;
+			break;
+		}
+		dc_write(hw, DC_DISPLAY_DPI_CONFIG + offset, dpi_cfg);
+
+		if (id == 0)
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
+		else
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
+
+		dc_write(hw, DC_DISPLAY_H + offset, hw->display[id].h_active |
+			 (hw->display[id].h_total << 16));
+		dc_write(hw, DC_DISPLAY_H_SYNC + offset,
+			 hw->display[id].h_sync_start |
+			 (hw->display[id].h_sync_end << 15) |
+			 (hw->display[id].h_sync_polarity ? 0 : BIT(31)) |
+			 BIT(30));
+		dc_write(hw, DC_DISPLAY_V + offset, hw->display[id].v_active |
+				(hw->display[id].v_total << 16));
+		dc_write(hw, DC_DISPLAY_V_SYNC + offset,
+			 hw->display[id].v_sync_start |
+			 (hw->display[id].v_sync_end << 15) |
+			 (hw->display[id].v_sync_polarity ? 0 : BIT(31)) |
+			 BIT(30));
+
+		if (hw->info->pipe_sync) {
+			switch (display->sync_mode) {
+			case VS_SINGLE_DC:
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX,
+					     0, BIT(3) | BIT(4));
+				break;
+			case VS_MULTI_DC_PRIMARY:
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX,
+					     BIT(3) | BIT(4), 0);
+				break;
+			case VS_MULTI_DC_SECONDARY:
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX,
+					     BIT(3), BIT(4));
+				break;
+			default:
+				break;
+			}
+		}
+
+		if (hw->info->background)
+			dc_write(hw, DC_FRAMEBUFFER_BG_COLOR + offset,
+				 hw->display[id].bg_color);
+
+		if (hw->display[id].dither_enable) {
+			dc_write(hw, DC_DISPLAY_DITHER_TABLE_LOW + offset,
+				 DC_DISPLAY_DITHERTABLE_LOW);
+			dc_write(hw, DC_DISPLAY_DITHER_TABLE_HIGH + offset,
+				 DC_DISPLAY_DITHERTABLE_HIGH);
+			dc_write(hw, DC_DISPLAY_DITHER_CONFIG + offset, BIT(31));
+		} else {
+			dc_write(hw, DC_DISPLAY_DITHER_CONFIG + offset, 0);
+		}
+
+		dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(12), 0);
+		if (hw->display[id].sync_enable)
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(2) | BIT(3), 0);
+		else if (id == 0)
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(0), BIT(3));
+		else
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(1), BIT(3));
+	} else {
+		dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(12));
+		if (id == 0)
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
+		else
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
+	}
+}
+
+static void setup_display_ex(struct dc_hw *hw, struct dc_hw_display *display)
+{
+	u8 id = display->id;
+	u32 dp_cfg, offset = id << 2;
+	bool is_yuv = false;
+
+	if (hw->display[id].enable && hw->out[id] == OUT_DP) {
+		switch (display->bus_format) {
+		case MEDIA_BUS_FMT_RGB565_1X16:
+			dp_cfg = 0;
+			break;
+		case MEDIA_BUS_FMT_RGB666_1X18:
+			dp_cfg = 1;
+			break;
+		case MEDIA_BUS_FMT_RGB888_1X24:
+			dp_cfg = 2;
+			break;
+		case MEDIA_BUS_FMT_RGB101010_1X30:
+			dp_cfg = 3;
+			break;
+		case MEDIA_BUS_FMT_UYVY8_1X16:
+			dp_cfg = 2 << 4;
+			is_yuv = true;
+			break;
+		case MEDIA_BUS_FMT_YUV8_1X24:
+			dp_cfg = 4 << 4;
+			is_yuv = true;
+			break;
+		case MEDIA_BUS_FMT_UYVY10_1X20:
+			dp_cfg = 8 << 4;
+			is_yuv = true;
+			break;
+		case MEDIA_BUS_FMT_YUV10_1X30:
+			dp_cfg = 10 << 4;
+			is_yuv = true;
+			break;
+		case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+			dp_cfg = 12 << 4;
+			is_yuv = true;
+			break;
+		case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+			dp_cfg = 13 << 4;
+			is_yuv = true;
+			break;
+		default:
+			dp_cfg = 2;
+			break;
+		}
+		if (is_yuv)
+			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(16), 0);
+		else
+			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(16));
+		dc_write(hw, DC_DISPLAY_DP_CONFIG + offset, dp_cfg | BIT(3));
+	}
+
+	if (hw->out[id] == OUT_DPI)
+		dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, BIT(3));
+
+	setup_display(hw, display);
+}
+
+static const struct dc_hw_funcs hw_func = {
+	.gamma = &gamma_ex_commit,
+	.plane = &plane_ex_commit,
+	.display = setup_display_ex,
+};
+
+void dc_hw_commit(struct dc_hw *hw)
+{
+	u32 i, offset = 0;
+	u8 plane_num = hw->info->plane_num;
+	u8 layer_num = hw->info->layer_num;
+	u8 cursor_num = plane_num - layer_num;
+
+	hw->func->gamma(hw);
+	hw->func->plane(hw);
+
+	for (i = 0; i < cursor_num; i++) {
+		if (hw->cursor[i].dirty) {
+			offset = hw->cursor[i].display_id ? DC_CURSOR_OFFSET : 0;
+			if (hw->cursor[i].enable) {
+				dc_write(hw, DC_CURSOR_ADDRESS + offset,
+					 hw->cursor[i].address);
+				dc_write(hw, DC_CURSOR_LOCATION + offset, hw->cursor[i].x |
+					 (hw->cursor[i].y << 16));
+				dc_set_clear(hw, DC_CURSOR_CONFIG + offset,
+					     (hw->cursor[i].hot_x << 16) |
+					     (hw->cursor[i].hot_y << 8) |
+					     (hw->cursor[i].size << 5) |
+					     BIT(3) | BIT(2) | 0x02,
+					     (0xFF << 16) |
+					     (0xFF << 8) |
+					     (0x07 << 5) | 0x1F);
+			} else {
+				dc_set_clear(hw, DC_CURSOR_CONFIG + offset, BIT(3), 0x03);
+			}
+			hw->cursor[i].dirty = false;
+		}
+	}
+
+	if (hw->qos.dirty) {
+		dc_set_clear(hw, DC_QOS_CONFIG, (hw->qos.high_value << 4) |
+					 hw->qos.low_value, 0xFF);
+		hw->qos.dirty = false;
+	}
+}
+
diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.h b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
new file mode 100644
index 000000000000..cd037718ecd5
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
@@ -0,0 +1,496 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_DC_HW_H__
+#define __VS_DC_HW_H__
+
+#include <linux/version.h>
+
+#define AQ_INTR_ACKNOWLEDGE				0x0010
+#define AQ_INTR_ENBL					0x0014
+#define DC_HW_REVISION					0x0024
+#define DC_HW_CHIP_CID					0x0030
+
+#define DC_REG_BASE					0x0800
+#define DC_REG_RANGE					0x2000
+#define DC_SEC_REG_OFFSET				0x100000
+
+#define DC_FRAMEBUFFER_CONFIG				0x1518
+#define DC_FRAMEBUFFER_CONFIG_EX			0x1cc0
+#define DC_FRAMEBUFFER_SCALE_CONFIG			0x1520
+#define DC_FRAMEBUFFER_TOP_LEFT				0x24d8
+#define DC_FRAMEBUFFER_BOTTOM_RIGHT			0x24e0
+#define DC_FRAMEBUFFER_ADDRESS				0x1400
+#define DC_FRAMEBUFFER_U_ADDRESS			0x1530
+#define DC_FRAMEBUFFER_V_ADDRESS			0x1538
+#define DC_FRAMEBUFFER_STRIDE				0x1408
+#define DC_FRAMEBUFFER_U_STRIDE				0x1800
+#define DC_FRAMEBUFFER_V_STRIDE				0x1808
+#define DC_FRAMEBUFFER_SIZE				0x1810
+#define DC_FRAMEBUFFER_SCALE_FACTOR_X			0x1828
+#define DC_FRAMEBUFFER_SCALE_FACTOR_Y			0x1830
+#define DC_FRAMEBUFFER_H_FILTER_COEF_INDEX		0x1838
+#define DC_FRAMEBUFFER_H_FILTER_COEF_DATA		0x1a00
+#define DC_FRAMEBUFFER_V_FILTER_COEF_INDEX		0x1a08
+#define DC_FRAMEBUFFER_V_FILTER_COEF_DATA		0x1a10
+#define DC_FRAMEBUFFER_INIT_OFFSET			0x1a20
+#define DC_FRAMEBUFFER_COLOR_KEY			0x1508
+#define DC_FRAMEBUFFER_COLOR_KEY_HIGH			0x1510
+#define DC_FRAMEBUFFER_CLEAR_VALUE			0x1a18
+#define DC_FRAMEBUFFER_COLOR_TABLE_INDEX		0x1818
+#define DC_FRAMEBUFFER_COLOR_TABLE_DATA			0x1820
+#define DC_FRAMEBUFFER_BG_COLOR				0x1528
+#define DC_FRAMEBUFFER_ROI_ORIGIN			0x1cb0
+#define DC_FRAMEBUFFER_ROI_SIZE				0x1cb8
+#define DC_FRAMEBUFFER_WATER_MARK			0x1ce8
+#define DC_FRAMEBUFFER_DEGAMMA_INDEX			0x1d88
+#define DC_FRAMEBUFFER_DEGAMMA_DATA			0x1d90
+#define DC_FRAMEBUFFER_DEGAMMA_EX_DATA			0x1d98
+#define DC_FRAMEBUFFER_YUVTORGB_COEF0			0x1da0
+#define DC_FRAMEBUFFER_YUVTORGB_COEF1			0x1da8
+#define DC_FRAMEBUFFER_YUVTORGB_COEF2			0x1db0
+#define DC_FRAMEBUFFER_YUVTORGB_COEF3			0x1db8
+#define DC_FRAMEBUFFER_YUVTORGB_COEF4			0x1e00
+#define DC_FRAMEBUFFER_YUVTORGB_COEFD0			0x1e08
+#define DC_FRAMEBUFFER_YUVTORGB_COEFD1			0x1e10
+#define DC_FRAMEBUFFER_YUVTORGB_COEFD2			0x1e18
+#define DC_FRAMEBUFFER_Y_CLAMP_BOUND			0x1e88
+#define DC_FRAMEBUFFER_UV_CLAMP_BOUND			0x1e90
+#define DC_FRAMEBUFFER_RGBTORGB_COEF0			0x1e20
+#define DC_FRAMEBUFFER_RGBTORGB_COEF1			0x1e28
+#define DC_FRAMEBUFFER_RGBTORGB_COEF2			0x1e30
+#define DC_FRAMEBUFFER_RGBTORGB_COEF3			0x1e38
+#define DC_FRAMEBUFFER_RGBTORGB_COEF4			0x1e40
+#define DC_FRAMEBUFFER_BLEND_CONFIG			0x2510
+#define DC_FRAMEBUFFER_SRC_GLOBAL_COLOR			0x2500
+#define DC_FRAMEBUFFER_DST_GLOBAL_COLOR			0x2508
+
+#define DC_OVERLAY_CONFIG				0x1540
+#define DC_OVERLAY_CONFIG_EX				0x2540
+#define DC_OVERLAY_SCALE_CONFIG				0x1c00
+#define DC_OVERLAY_BLEND_CONFIG				0x1580
+#define DC_OVERLAY_TOP_LEFT				0x1640
+#define DC_OVERLAY_BOTTOM_RIGHT				0x1680
+#define DC_OVERLAY_ADDRESS				0x15c0
+#define DC_OVERLAY_U_ADDRESS				0x1840
+#define DC_OVERLAY_V_ADDRESS				0x1880
+#define DC_OVERLAY_STRIDE				0x1600
+#define DC_OVERLAY_U_STRIDE				0x18c0
+#define DC_OVERLAY_V_STRIDE				0x1900
+#define DC_OVERLAY_SIZE					0x17c0
+#define DC_OVERLAY_SCALE_FACTOR_X			0x1a40
+#define DC_OVERLAY_SCALE_FACTOR_Y			0x1a80
+#define DC_OVERLAY_H_FILTER_COEF_INDEX			0x1aC0
+#define DC_OVERLAY_H_FILTER_COEF_DATA			0x1b00
+#define DC_OVERLAY_V_FILTER_COEF_INDEX			0x1b40
+#define DC_OVERLAY_V_FILTER_COEF_DATA			0x1b80
+#define DC_OVERLAY_INIT_OFFSET				0x1bC0
+#define DC_OVERLAY_COLOR_KEY				0x1740
+#define DC_OVERLAY_COLOR_KEY_HIGH			0x1780
+#define DC_OVERLAY_CLEAR_VALUE				0x1940
+#define DC_OVERLAY_COLOR_TABLE_INDEX			0x1980
+#define DC_OVERLAY_COLOR_TABLE_DATA			0x19c0
+#define DC_OVERLAY_SRC_GLOBAL_COLOR			0x16c0
+#define DC_OVERLAY_DST_GLOBAL_COLOR			0x1700
+#define DC_OVERLAY_ROI_ORIGIN				0x1d00
+#define DC_OVERLAY_ROI_SIZE				0x1d40
+#define DC_OVERLAY_WATER_MARK				0x1dc0
+#define DC_OVERLAY_DEGAMMA_INDEX			0x2200
+#define DC_OVERLAY_DEGAMMA_DATA				0x2240
+#define DC_OVERLAY_DEGAMMA_EX_DATA			0x2280
+#define DC_OVERLAY_YUVTORGB_COEF0			0x1ec0
+#define DC_OVERLAY_YUVTORGB_COEF1			0x1f00
+#define DC_OVERLAY_YUVTORGB_COEF2			0x1f40
+#define DC_OVERLAY_YUVTORGB_COEF3			0x1f80
+#define DC_OVERLAY_YUVTORGB_COEF4			0x1fc0
+#define DC_OVERLAY_YUVTORGB_COEFD0			0x2000
+#define DC_OVERLAY_YUVTORGB_COEFD1			0x2040
+#define DC_OVERLAY_YUVTORGB_COEFD2			0x2080
+#define DC_OVERLAY_Y_CLAMP_BOUND			0x22c0
+#define DC_OVERLAY_UV_CLAMP_BOUND			0x2300
+#define DC_OVERLAY_RGBTORGB_COEF0			0x20c0
+#define DC_OVERLAY_RGBTORGB_COEF1			0x2100
+#define DC_OVERLAY_RGBTORGB_COEF2			0x2140
+#define DC_OVERLAY_RGBTORGB_COEF3			0x2180
+#define DC_OVERLAY_RGBTORGB_COEF4			0x21c0
+
+#define DC_CURSOR_CONFIG				0x1468
+#define DC_CURSOR_ADDRESS				0x146c
+#define DC_CURSOR_LOCATION				0x1470
+#define DC_CURSOR_BACKGROUND				0x1474
+#define DC_CURSOR_FOREGROUND				0x1478
+#define DC_CURSOR_CLK_GATING				0x1484
+#define DC_CURSOR_CONFIG_EX				0x24e8
+#define DC_CURSOR_OFFSET				0x1080
+
+#define DC_DISPLAY_DITHER_CONFIG			0x1410
+#define DC_DISPLAY_PANEL_CONFIG				0x1418
+#define DC_DISPLAY_PANEL_CONFIG_EX			0x2518
+#define DC_DISPLAY_DITHER_TABLE_LOW			0x1420
+#define DC_DISPLAY_DITHER_TABLE_HIGH			0x1428
+#define DC_DISPLAY_H					0x1430
+#define DC_DISPLAY_H_SYNC				0x1438
+#define DC_DISPLAY_V					0x1440
+#define DC_DISPLAY_V_SYNC				0x1448
+#define DC_DISPLAY_CURRENT_LOCATION			0x1450
+#define DC_DISPLAY_GAMMA_INDEX				0x1458
+#define DC_DISPLAY_GAMMA_DATA				0x1460
+#define DC_DISPLAY_INT					0x147c
+#define DC_DISPLAY_INT_ENABLE				0x1480
+#define DC_DISPLAY_DBI_CONFIG				0x1488
+#define DC_DISPLAY_GENERAL_CONFIG			0x14b0
+#define DC_DISPLAY_DPI_CONFIG				0x14b8
+#define DC_DISPLAY_PANEL_START				0x1ccc
+#define DC_DISPLAY_DEBUG_COUNTER_SELECT			0x14d0
+#define DC_DISPLAY_DEBUG_COUNTER_VALUE			0x14d8
+#define DC_DISPLAY_DP_CONFIG				0x1cd0
+#define DC_DISPLAY_GAMMA_EX_INDEX			0x1cf0
+#define DC_DISPLAY_GAMMA_EX_DATA			0x1cf8
+#define DC_DISPLAY_GAMMA_EX_ONE_DATA			0x1d80
+#define DC_DISPLAY_RGBTOYUV_COEF0			0x1e48
+#define DC_DISPLAY_RGBTOYUV_COEF1			0x1e50
+#define DC_DISPLAY_RGBTOYUV_COEF2			0x1e58
+#define DC_DISPLAY_RGBTOYUV_COEF3			0x1e60
+#define DC_DISPLAY_RGBTOYUV_COEF4			0x1e68
+#define DC_DISPLAY_RGBTOYUV_COEFD0			0x1e70
+#define DC_DISPLAY_RGBTOYUV_COEFD1			0x1e78
+#define DC_DISPLAY_RGBTOYUV_COEFD2			0x1e80
+
+#define DC_CLK_GATTING					0x1a28
+#define DC_QOS_CONFIG					0x1a38
+
+#define DC_TRANSPARENCY_OPAQUE				0x00
+#define DC_TRANSPARENCY_KEY				0x02
+#define DC_DISPLAY_DITHERTABLE_LOW			0x7b48f3c0
+#define DC_DISPLAY_DITHERTABLE_HIGH			0x596ad1e2
+
+#define GAMMA_SIZE					256
+#define GAMMA_EX_SIZE					300
+#define DEGAMMA_SIZE					260
+
+#define RGB_TO_RGB_TABLE_SIZE				9
+#define YUV_TO_RGB_TABLE_SIZE				16
+#define RGB_TO_YUV_TABLE_SIZE				12
+
+#define DC_LAYER_NUM					6
+#define DC_DISPLAY_NUM					2
+#define DC_CURSOR_NUM					2
+
+enum dc_chip_rev {
+	DC_REV_0,/* For HW_REV_5720,HW_REV_5721_311 */
+	DC_REV_1,/* For HW_REV_5721_30B */
+	DC_REV_2,/* For HW_REV_5721_310 */
+};
+
+enum dc_hw_plane_id {
+	PRIMARY_PLANE_0,
+	OVERLAY_PLANE_0,
+	OVERLAY_PLANE_1,
+	PRIMARY_PLANE_1,
+	OVERLAY_PLANE_2,
+	OVERLAY_PLANE_3,
+	CURSOR_PLANE_0,
+	CURSOR_PLANE_1,
+	PLANE_NUM
+};
+
+enum dc_hw_color_format {
+	FORMAT_X4R4G4B4,//0
+	FORMAT_A4R4G4B4,//1
+	FORMAT_X1R5G5B5,//2
+	FORMAT_A1R5G5B5,//3
+	FORMAT_R5G6B5,//4
+	FORMAT_X8R8G8B8,//5
+	FORMAT_A8R8G8B8,//6
+	FORMAT_YUY2,//7
+	FORMAT_UYVY,//8
+	FORMAT_INDEX8,//9
+	FORMAT_MONOCHROME,//10
+	FORMAT_YV12 = 0xf,
+	FORMAT_A8,//16
+	FORMAT_NV12,//17
+	FORMAT_NV16,//18
+	FORMAT_RG16,//19
+	FORMAT_R8,//20
+	FORMAT_NV12_10BIT,//21
+	FORMAT_A2R10G10B10,//22
+	FORMAT_NV16_10BIT,//23
+	FORMAT_INDEX1,//24
+	FORMAT_INDEX2,//25
+	FORMAT_INDEX4,//26
+	FORMAT_P010,//27
+	FORMAT_YUV444,//28
+	FORMAT_YUV444_10BIT,//29
+};
+
+enum dc_hw_yuv_color_space {
+	COLOR_SPACE_601 = 0,
+	COLOR_SPACE_709 = 1,
+	COLOR_SPACE_2020 = 3,
+};
+
+enum dc_hw_rotation {
+	ROT_0 = 0,
+	ROT_90 = 4,
+	ROT_180 = 5,
+	ROT_270 = 6,
+	FLIP_X = 1,
+	FLIP_Y = 2,
+	FLIP_XY = 3,
+};
+
+enum dc_hw_swizzle {
+	SWIZZLE_ARGB = 0,
+	SWIZZLE_RGBA,
+	SWIZZLE_ABGR,
+	SWIZZLE_BGRA,
+};
+
+enum dc_hw_out {
+	OUT_DPI,
+	OUT_DP,
+};
+
+enum dc_hw_cursor_size {
+	CURSOR_SIZE_32X32 = 0,
+	CURSOR_SIZE_64X64,
+};
+
+enum dc_hw_blend_mode {
+	/* out.rgb = plane_alpha * fg.rgb +
+	 *		(1 - (plane_alpha * fg.alpha)) * bg.rgb
+	 */
+	BLEND_PREMULTI,
+	/* out.rgb = plane_alpha * fg.alpha * fg.rgb +
+	 *		(1 - (plane_alpha * fg.alpha)) * bg.rgb
+	 */
+	BLEND_COVERAGE,
+	/* out.rgb = plane_alpha * fg.rgb +
+	 *		(1 - plane_alpha) * bg.rgb
+	 */
+	BLEND_PIXEL_NONE,
+};
+
+struct dc_hw_plane_reg {
+	u32 y_address;
+	u32 u_address;
+	u32 v_address;
+	u32 y_stride;
+	u32 u_stride;
+	u32 v_stride;
+	u32 size;
+	u32 top_left;
+	u32 bottom_right;
+	u32 scale_factor_x;
+	u32 scale_factor_y;
+	u32 h_filter_coef_index;
+	u32 h_filter_coef_data;
+	u32 v_filter_coef_index;
+	u32 v_filter_coef_data;
+	u32 init_offset;
+	u32 color_key;
+	u32 color_key_high;
+	u32 clear_value;
+	u32 color_table_index;
+	u32 color_table_data;
+	u32 scale_config;
+	u32 water_mark;
+	u32 degamma_index;
+	u32 degamma_data;
+	u32 degamma_ex_data;
+	u32 src_global_color;
+	u32 dst_global_color;
+	u32 blend_config;
+	u32 roi_origin;
+	u32 roi_size;
+	u32 yuv_to_rgb_coef0;
+	u32 yuv_to_rgb_coef1;
+	u32 yuv_to_rgb_coef2;
+	u32 yuv_to_rgb_coef3;
+	u32 yuv_to_rgb_coef4;
+	u32 yuv_to_rgb_coefd0;
+	u32 yuv_to_rgb_coefd1;
+	u32 yuv_to_rgb_coefd2;
+	u32 y_clamp_bound;
+	u32 uv_clamp_bound;
+	u32 rgb_to_rgb_coef0;
+	u32 rgb_to_rgb_coef1;
+	u32 rgb_to_rgb_coef2;
+	u32 rgb_to_rgb_coef3;
+	u32 rgb_to_rgb_coef4;
+};
+
+struct dc_hw_fb {
+	u32 y_address;
+	u32 u_address;
+	u32 v_address;
+	u32 clear_value;
+	u32 water_mark;
+	u16 y_stride;
+	u16 u_stride;
+	u16 v_stride;
+	u16 width;
+	u16 height;
+	u8	format;
+	u8	tile_mode;
+	u8	rotation;
+	u8	yuv_color_space;
+	u8	swizzle;
+	u8	uv_swizzle;
+	u8	zpos;
+	u8	display_id;
+	bool	clear_enable;
+	bool	dec_enable;
+	bool	enable;
+	bool	dirty;
+};
+
+struct dc_hw_scale {
+	u32 scale_factor_x;
+	u32 scale_factor_y;
+	bool	enable;
+	bool	dirty;
+};
+
+struct dc_hw_position {
+	u16 start_x;
+	u16 start_y;
+	u16 end_x;
+	u16 end_y;
+	bool	dirty;
+};
+
+struct dc_hw_blend {
+	u8	alpha;
+	u8	blend_mode;
+	bool	dirty;
+};
+
+struct dc_hw_colorkey {
+	u32 colorkey;
+	u32 colorkey_high;
+	u8	transparency;
+	bool dirty;
+};
+
+struct dc_hw_roi {
+	u16 x;
+	u16 y;
+	u16 width;
+	u16 height;
+	bool enable;
+	bool dirty;
+};
+
+struct dc_hw_cursor {
+	u32 address;
+	u16 x;
+	u16 y;
+	u16 hot_x;
+	u16 hot_y;
+	u8	size;
+	u8	display_id;
+	bool	enable;
+	bool	dirty;
+};
+
+struct dc_hw_display {
+	u32 bus_format;
+	u16 h_active;
+	u16 h_total;
+	u16 h_sync_start;
+	u16 h_sync_end;
+	u16 v_active;
+	u16 v_total;
+	u16 v_sync_start;
+	u16 v_sync_end;
+	u16 sync_mode;
+	u32 bg_color;
+	u8	id;
+	bool	h_sync_polarity;
+	bool	v_sync_polarity;
+	bool	enable;
+	bool	sync_enable;
+	bool	dither_enable;
+};
+
+struct dc_hw_gamma {
+	u16 gamma[GAMMA_EX_SIZE][3];
+	bool	enable;
+	bool	dirty;
+};
+
+struct dc_hw_degamma {
+	u16 degamma[DEGAMMA_SIZE][3];
+	u32 mode;
+	bool	dirty;
+};
+
+struct dc_hw_plane {
+	struct dc_hw_fb			fb;
+	struct dc_hw_position	pos;
+	struct dc_hw_scale		scale;
+	struct dc_hw_blend		blend;
+	struct dc_hw_roi		roi;
+	struct dc_hw_colorkey	colorkey;
+	struct dc_hw_degamma	degamma;
+};
+
+struct dc_hw_qos {
+	u8	  low_value;
+	u8	  high_value;
+	bool  dirty;
+};
+
+struct dc_hw_read {
+	u32			reg;
+	u32			value;
+};
+
+struct dc_hw;
+struct dc_hw_funcs {
+	void (*gamma)(struct dc_hw *hw);
+	void (*plane)(struct dc_hw *hw);
+	void (*display)(struct dc_hw *hw, struct dc_hw_display *display);
+};
+
+struct dc_hw {
+	enum dc_chip_rev rev;
+	enum dc_hw_out		out[DC_DISPLAY_NUM];
+	void			*hi_base;
+	void			*reg_base;
+
+	struct dc_hw_display display[DC_DISPLAY_NUM];
+	struct dc_hw_gamma	 gamma[DC_DISPLAY_NUM];
+	struct dc_hw_plane	 plane[DC_LAYER_NUM];
+	struct dc_hw_cursor  cursor[DC_CURSOR_NUM];
+	struct dc_hw_qos	 qos;
+	struct dc_hw_funcs	 *func;
+	struct vs_dc_info	 *info;
+};
+
+int dc_hw_init(struct dc_hw *hw);
+void dc_hw_deinit(struct dc_hw *hw);
+void dc_hw_update_plane(struct dc_hw *hw, u8 id,
+			struct dc_hw_fb *fb, struct dc_hw_scale *scale,
+			struct dc_hw_position *pos, struct dc_hw_blend *blend);
+void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode);
+void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi);
+void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
+			   struct dc_hw_colorkey *colorkey);
+void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos);
+void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor);
+void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
+			u16 r, u16 g, u16 b);
+void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable);
+void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display);
+void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable);
+u32 dc_hw_get_interrupt(struct dc_hw *hw);
+bool dc_hw_check_underflow(struct dc_hw *hw);
+void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable);
+void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id);
+void dc_hw_commit(struct dc_hw *hw);
+
+#endif /* __VS_DC_HW_H__ */
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
index d84aacd751bc..c28bfd74ffc9 100644
--- a/drivers/gpu/drm/verisilicon/vs_drv.c
+++ b/drivers/gpu/drm/verisilicon/vs_drv.c
@@ -32,6 +32,7 @@
 #include "vs_drv.h"
 #include "vs_fb.h"
 #include "vs_gem.h"
+#include "vs_dc.h"
 
 #define DRV_NAME	"starfive"
 #define DRV_DESC	"Starfive DRM driver"
@@ -181,6 +182,7 @@ static const struct component_master_ops vs_drm_ops = {
 };
 
 static struct platform_driver *drm_sub_drivers[] = {
+	&dc_platform_driver,
 };
 
 #define NUM_DRM_DRIVERS \
-- 
2.34.1


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

* [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver
  2023-06-02  7:40 [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Keith Zhao
                   ` (7 preceding siblings ...)
  2023-06-02  7:40 ` [PATCH 8/9] drm/verisilicon: Add verisilicon dc controller driver Keith Zhao
@ 2023-06-02  7:40 ` Keith Zhao
  2023-06-05  8:08   ` Philipp Zabel
                     ` (2 more replies)
  2023-06-22 18:19 ` [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Palmer Dabbelt
  9 siblings, 3 replies; 46+ messages in thread
From: Keith Zhao @ 2023-06-02  7:40 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Keith Zhao, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Add HDMI dirver for StarFive SoC JH7110.

Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
---
 drivers/gpu/drm/verisilicon/Kconfig         |  11 +
 drivers/gpu/drm/verisilicon/Makefile        |   1 +
 drivers/gpu/drm/verisilicon/starfive_hdmi.c | 928 ++++++++++++++++++++
 drivers/gpu/drm/verisilicon/starfive_hdmi.h | 296 +++++++
 drivers/gpu/drm/verisilicon/vs_drv.c        |   6 +
 drivers/gpu/drm/verisilicon/vs_drv.h        |   4 +
 6 files changed, 1246 insertions(+)
 create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.c
 create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.h

diff --git a/drivers/gpu/drm/verisilicon/Kconfig b/drivers/gpu/drm/verisilicon/Kconfig
index 89d12185f73b..35e85ac41b10 100644
--- a/drivers/gpu/drm/verisilicon/Kconfig
+++ b/drivers/gpu/drm/verisilicon/Kconfig
@@ -11,3 +11,14 @@ config DRM_VERISILICON
 	  This driver provides VeriSilicon kernel mode
 	  setting and buffer management. It does not
 	  provide 2D or 3D acceleration.
+
+config STARFIVE_HDMI
+	bool "Starfive specific extensions HDMI"
+	help
+	   This selects support for StarFive SoC specific extensions
+	   for the Innosilicon HDMI driver. If you want to enable
+	   HDMI on JH7110 based SoC, you should select this option.
+
+	   To compile this driver as a module, choose M here.
+
+
diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index 0ed25b5e3062..ebe2c94f529a 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -8,5 +8,6 @@ vs_drm-objs := vs_dc_hw.o \
 		vs_gem.o \
 		vs_plane.o
 
+vs_drm-$(CONFIG_STARFIVE_HDMI) += starfive_hdmi.o
 obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
 
diff --git a/drivers/gpu/drm/verisilicon/starfive_hdmi.c b/drivers/gpu/drm/verisilicon/starfive_hdmi.c
new file mode 100644
index 000000000000..128ecca03309
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/starfive_hdmi.c
@@ -0,0 +1,928 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hdmi.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <drm/bridge/dw_hdmi.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include "starfive_hdmi.h"
+#include "vs_drv.h"
+
+static struct starfive_hdmi *encoder_to_hdmi(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct starfive_hdmi, encoder);
+}
+
+static struct starfive_hdmi *connector_to_hdmi(struct drm_connector *connector)
+{
+	return container_of(connector, struct starfive_hdmi, connector);
+}
+
+struct starfive_hdmi_i2c {
+	struct i2c_adapter adap;
+
+	u8 ddc_addr;
+	u8 segment_addr;
+	/* protects the edid data when use i2c cmd to read edid */
+	struct mutex lock;
+	struct completion cmp;
+};
+
+static const struct pre_pll_config pre_pll_cfg_table[] = {
+	{ 25175000,  25175000, 1,  100, 2, 3, 3, 12, 3, 3, 4, 0, 0xf55555},
+	{ 25200000,  25200000, 1,  100, 2, 3, 3, 12, 3, 3, 4, 0, 0},
+	{ 27000000,  27000000, 1,  90, 3, 2, 2, 10, 3, 3, 4, 0, 0},
+	{ 27027000,  27027000, 1,  90, 3, 2, 2, 10, 3, 3, 4, 0, 0x170a3d},
+	{ 28320000,  28320000, 1,  28, 2, 1, 1,  3, 0, 3, 4, 0, 0x51eb85},
+	{ 30240000,  30240000, 1,  30, 2, 1, 1,  3, 0, 3, 4, 0, 0x3d70a3},
+	{ 31500000,  31500000, 1,  31, 2, 1, 1,  3, 0, 3, 4, 0, 0x7fffff},
+	{ 33750000,  33750000, 1,  33, 2, 1, 1,  3, 0, 3, 4, 0, 0xcfffff},
+	{ 36000000,  36000000, 1,  36, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{ 40000000,  40000000, 1,  80, 2, 2, 2, 12, 2, 2, 2, 0, 0},
+	{ 46970000,  46970000, 1,  46, 2, 1, 1,  3, 0, 3, 4, 0, 0xf851eb},
+	{ 49500000,  49500000, 1,  49, 2, 1, 1,  3, 0, 3, 4, 0, 0x7fffff},
+	{ 49000000,  49000000, 1,  49, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{ 50000000,  50000000, 1,  50, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{ 54000000,  54000000, 1,  54, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{ 54054000,  54054000, 1,  54, 2, 1, 1,  3, 0, 3, 4, 0, 0x0dd2f1},
+	{ 57284000,  57284000, 1,  57, 2, 1, 1,  3, 0, 3, 4, 0, 0x48b439},
+	{ 58230000,  58230000, 1,  58, 2, 1, 1,  3, 0, 3, 4, 0, 0x3ae147},
+	{ 59341000,  59341000, 1,  59, 2, 1, 1,  3, 0, 3, 4, 0, 0x574bc6},
+	{ 59400000,  59400000, 1,  99, 3, 1, 1,  1, 3, 3, 4, 0, 0},
+	{ 65000000,  65000000, 1, 130, 2, 2, 2,  12, 0, 2, 2, 0, 0},
+	{ 68250000,  68250000, 1, 68,  2, 1, 1,  3,  0, 3, 4, 0, 0x3fffff},
+	{ 71000000,  71000000, 1,  71, 2, 1, 1,  3, 0, 3,  4, 0, 0},
+	{ 74176000,  74176000, 1,  98, 1, 2, 2,  1, 2, 3, 4, 0, 0xe6ae6b},
+	{ 74250000,  74250000, 1,  99, 1, 2, 2,  1, 2, 3, 4, 0, 0},
+	{ 75000000,  75000000, 1,  75, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{ 78750000,  78750000, 1,  78, 2, 1, 1,  3, 0, 3, 4, 0, 0xcfffff},
+	{ 79500000,  79500000, 1,  79, 2, 1, 1,  3, 0, 3, 4, 0, 0x7fffff},
+	{ 83500000,  83500000, 2, 167, 2, 1, 1,  1, 0, 0,  6, 0, 0},
+	{ 83500000, 104375000, 1, 104, 2, 1, 1,  1, 1, 0,  5, 0, 0x600000},
+	{ 84858000,  84858000, 1,  85, 2, 1, 1,  3, 0, 3,  4, 0, 0xdba5e2},
+	{ 85500000,  85500000, 1,  85, 2, 1, 1,  3, 0, 3,  4, 0, 0x7fffff},
+	{ 85750000,  85750000, 1,  85, 2, 1, 1,  3, 0, 3,  4, 0, 0xcfffff},
+	{ 85800000,  85800000, 1,  85, 2, 1, 1,  3, 0, 3,  4, 0, 0xcccccc},
+	{ 88750000,  88750000, 1,  88, 2, 1, 1,  3, 0, 3,  4, 0, 0xcfffff},
+	{ 89910000,  89910000, 1,  89, 2, 1, 1,  3, 0, 3, 4, 0, 0xe8f5c1},
+	{ 90000000,  90000000, 1,  90, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{101000000, 101000000, 1, 101, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{102250000, 102250000, 1, 102, 2, 1, 1,  3, 0, 3, 4, 0, 0x3fffff},
+	{106500000, 106500000, 1, 106, 2, 1, 1,  3, 0, 3, 4, 0, 0x7fffff},
+	{108000000, 108000000, 1,  90, 3, 0, 0,  5, 0, 2,  2, 0, 0},
+	{119000000, 119000000, 1, 119, 2, 1, 1,  3, 0, 3,  4, 0, 0},
+	{131481000, 131481000, 1,  131, 2, 1, 1,  3, 0, 3,  4, 0, 0x7b22d1},
+	{135000000, 135000000, 1,  135, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{136750000, 136750000, 1,  136, 2, 1, 1,  3, 0, 3, 4, 0, 0xcfffff},
+	{147180000, 147180000, 1,  147, 2, 1, 1,  3, 0, 3, 4, 0, 0x2e147a},
+	{148352000, 148352000, 1,  98, 1, 1, 1,  1, 2, 2, 2, 0, 0xe6ae6b},
+	{148500000, 148500000, 1,  99, 1, 1, 1,  1, 2, 2, 2, 0, 0},
+	{154000000, 154000000, 1, 154, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{156000000, 156000000, 1, 156, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{157000000, 157000000, 1, 157, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{162000000, 162000000, 1, 162, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{174250000, 174250000, 1, 145, 3, 0, 0,  5, 0, 2, 2, 0, 0x355555},
+	{174500000, 174500000, 1, 174, 2, 1, 1,  3, 0, 3, 4, 0, 0x7fffff},
+	{174570000, 174570000, 1, 174, 2, 1, 1,  3, 0, 3, 4, 0, 0x91eb84},
+	{175500000, 175500000, 1, 175, 2, 1, 1,  3, 0, 3, 4, 0, 0x7fffff},
+	{185590000, 185590000, 1, 185, 2, 1, 1,  3, 0, 3, 4, 0, 0x970a3c},
+	{187000000, 187000000, 1, 187, 2, 1, 1,  3, 0, 3, 4, 0, 0},
+	{241500000, 241500000, 1, 161, 1, 1, 1,  4, 0, 2,  2, 0, 0},
+	{241700000, 241700000, 1, 241, 2, 1, 1,  3, 0, 3,  4, 0, 0xb33332},
+	{262750000, 262750000, 1, 262, 2, 1, 1,  3, 0, 3,  4, 0, 0xcfffff},
+	{296500000, 296500000, 1, 296, 2, 1, 1,  3, 0, 3,  4, 0, 0x7fffff},
+	{296703000, 296703000, 1,  98, 0, 1, 1,  1, 0, 2,  2, 0, 0xe6ae6b},
+	{297000000, 297000000, 1,  99, 0, 1, 1,  1, 0, 2,  2, 0, 0},
+	{594000000, 594000000, 1,  99, 0, 2, 0,  1, 0, 1,  1, 0, 0},
+	{0, 0, 0,  0, 0, 0, 0,  0, 0, 0,  0, 0, 0},
+};
+
+static const struct post_pll_config post_pll_cfg_table[] = {
+	{25200000,	1, 80, 13, 3, 1},
+	{27000000,	1, 40, 11, 3, 1},
+	{33750000,	1, 40, 11, 3, 1},
+	{49000000,	1, 20, 1, 3, 3},
+	{241700000, 1, 20, 1, 3, 3},
+	{297000000, 4, 20, 0, 0, 3},
+	{594000000, 4, 20, 0, 0, 0},
+	{ /* sentinel */ }
+};
+
+inline u8 hdmi_readb(struct starfive_hdmi *hdmi, u16 offset)
+{
+	return readl_relaxed(hdmi->regs + (offset) * 0x04);
+}
+
+inline void hdmi_writeb(struct starfive_hdmi *hdmi, u16 offset, u32 val)
+{
+	writel_relaxed(val, hdmi->regs + (offset) * 0x04);
+}
+
+inline void hdmi_modb(struct starfive_hdmi *hdmi, u16 offset,
+			     u32 msk, u32 val)
+{
+	u8 temp = hdmi_readb(hdmi, offset) & ~msk;
+
+	temp |= val & msk;
+	hdmi_writeb(hdmi, offset, temp);
+}
+
+static int starfive_hdmi_enable_clk_deassert_rst(struct device *dev, struct starfive_hdmi *hdmi)
+{
+	int ret;
+
+	ret = clk_prepare_enable(hdmi->sys_clk);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "Cannot enable HDMI sys clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdmi->mclk);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "Cannot enable HDMI mclk clock: %d\n", ret);
+		return ret;
+	}
+	ret = clk_prepare_enable(hdmi->bclk);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "Cannot enable HDMI bclk clock: %d\n", ret);
+		return ret;
+	}
+	ret = reset_control_deassert(hdmi->tx_rst);
+	if (ret < 0) {
+		dev_err(dev, "failed to deassert tx_rst\n");
+		return ret;
+	}
+	return 0;
+}
+
+static void starfive_hdmi_disable_clk_assert_rst(struct device *dev, struct starfive_hdmi *hdmi)
+{
+	int ret;
+
+	ret = reset_control_assert(hdmi->tx_rst);
+	if (ret < 0)
+		dev_err(dev, "failed to assert tx_rst\n");
+
+	clk_disable_unprepare(hdmi->sys_clk);
+	clk_disable_unprepare(hdmi->mclk);
+	clk_disable_unprepare(hdmi->bclk);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int hdmi_system_pm_suspend(struct device *dev)
+{
+	return pm_runtime_force_suspend(dev);
+}
+
+static int hdmi_system_pm_resume(struct device *dev)
+{
+	return pm_runtime_force_resume(dev);
+}
+#endif
+
+#ifdef CONFIG_PM
+static int hdmi_runtime_suspend(struct device *dev)
+{
+	struct starfive_hdmi *hdmi = dev_get_drvdata(dev);
+
+	starfive_hdmi_disable_clk_assert_rst(dev, hdmi);
+
+	return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+	struct starfive_hdmi *hdmi = dev_get_drvdata(dev);
+
+	return starfive_hdmi_enable_clk_deassert_rst(dev, hdmi);
+}
+#endif
+
+static void starfive_hdmi_tx_phy_power_down(struct starfive_hdmi *hdmi)
+{
+	hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_OFF);
+}
+
+static void starfive_hdmi_tx_phy_power_on(struct starfive_hdmi *hdmi)
+{
+	hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_ON);
+}
+
+static void starfive_hdmi_config_pll(struct starfive_hdmi *hdmi)
+{
+	u32 val;
+	u8 reg_1ad_value = hdmi->post_cfg->post_div_en ?
+		 hdmi->post_cfg->postdiv : 0x00;
+	u8 reg_1aa_value = hdmi->post_cfg->post_div_en ?
+		 0x0e : 0x02;
+
+	hdmi_writeb(hdmi, STARFIVE_PRE_PLL_CONTROL, STARFIVE_PRE_PLL_POWER_DOWN);
+	hdmi_writeb(hdmi, STARFIVE_POST_PLL_DIV_1,
+		    STARFIVE_POST_PLL_POST_DIV_ENABLE |
+		    STARFIVE_POST_PLL_REFCLK_SEL_TMDS |
+		    STARFIVE_POST_PLL_POWER_DOWN);
+	hdmi_writeb(hdmi, STARFIVE_PRE_PLL_DIV_1, STARFIVE_PRE_PLL_PRE_DIV(hdmi->pre_cfg->prediv));
+
+	val = STARFIVE_SPREAD_SPECTRUM_MOD_DISABLE | STARFIVE_SPREAD_SPECTRUM_MOD_DOWN;
+	if (!hdmi->pre_cfg->fracdiv)
+		val |= STARFIVE_PRE_PLL_FRAC_DIV_DISABLE;
+	hdmi_writeb(hdmi, STARFIVE_PRE_PLL_DIV_2,
+		    STARFIVE_PRE_PLL_FB_DIV_11_8(hdmi->pre_cfg->fbdiv) | val);
+	hdmi_writeb(hdmi, STARFIVE_PRE_PLL_DIV_3,
+		    STARFIVE_PRE_PLL_FB_DIV_7_0(hdmi->pre_cfg->fbdiv));
+	hdmi_writeb(hdmi, STARFIVE_PRE_PLL_DIV_4,
+		    STARFIVE_PRE_PLL_TMDSCLK_DIV_C(hdmi->pre_cfg->tmds_div_c) |
+		    STARFIVE_PRE_PLL_TMDSCLK_DIV_A(hdmi->pre_cfg->tmds_div_a) |
+		    STARFIVE_PRE_PLL_TMDSCLK_DIV_B(hdmi->pre_cfg->tmds_div_b));
+
+	if (hdmi->pre_cfg->fracdiv) {
+		hdmi_writeb(hdmi, STARFIVE_PRE_PLL_FRAC_DIV_L,
+			    STARFIVE_PRE_PLL_FRAC_DIV_7_0(hdmi->pre_cfg->fracdiv));
+		hdmi_writeb(hdmi, STARFIVE_PRE_PLL_FRAC_DIV_M,
+			    STARFIVE_PRE_PLL_FRAC_DIV_15_8(hdmi->pre_cfg->fracdiv));
+		hdmi_writeb(hdmi, STARFIVE_PRE_PLL_FRAC_DIV_H,
+			    STARFIVE_PRE_PLL_FRAC_DIV_23_16(hdmi->pre_cfg->fracdiv));
+	}
+
+	hdmi_writeb(hdmi, STARFIVE_PRE_PLL_DIV_5,
+		    STARFIVE_PRE_PLL_PCLK_DIV_A(hdmi->pre_cfg->pclk_div_a) |
+		    STARFIVE_PRE_PLL_PCLK_DIV_B(hdmi->pre_cfg->pclk_div_b));
+	hdmi_writeb(hdmi, STARFIVE_PRE_PLL_DIV_6,
+		    STARFIVE_PRE_PLL_PCLK_DIV_C(hdmi->pre_cfg->pclk_div_c) |
+		    STARFIVE_PRE_PLL_PCLK_DIV_D(hdmi->pre_cfg->pclk_div_d));
+
+	/*pre-pll power down*/
+	hdmi_modb(hdmi, STARFIVE_PRE_PLL_CONTROL, STARFIVE_PRE_PLL_POWER_DOWN, 0);
+
+	hdmi_modb(hdmi, STARFIVE_POST_PLL_DIV_2, STARFIVE_POST_PLL_Pre_DIV_MASK,
+		  STARFIVE_POST_PLL_PRE_DIV(hdmi->post_cfg->prediv));
+	hdmi_writeb(hdmi, STARFIVE_POST_PLL_DIV_3, hdmi->post_cfg->fbdiv & 0xff);
+	hdmi_writeb(hdmi, STARFIVE_POST_PLL_DIV_4, reg_1ad_value);
+	hdmi_writeb(hdmi, STARFIVE_POST_PLL_DIV_1, reg_1aa_value);
+}
+
+static void starfive_hdmi_tmds_driver_on(struct starfive_hdmi *hdmi)
+{
+	hdmi_modb(hdmi, STARFIVE_TMDS_CONTROL,
+		  STARFIVE_TMDS_DRIVER_ENABLE, STARFIVE_TMDS_DRIVER_ENABLE);
+}
+
+static void starfive_hdmi_sync_tmds(struct starfive_hdmi *hdmi)
+{
+	/*first send 0 to this bit, then send 1 and keep 1 into this bit*/
+	hdmi_writeb(hdmi, HDMI_SYNC, 0x0);
+	hdmi_writeb(hdmi, HDMI_SYNC, 0x1);
+}
+
+static void starfive_hdmi_i2c_init(struct starfive_hdmi *hdmi)
+{
+	int ddc_bus_freq;
+
+	ddc_bus_freq = (hdmi->tmds_rate >> 2) / HDMI_SCL_RATE;
+
+	hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
+	hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
+
+	/* Clear the EDID interrupt flag and mute the interrupt */
+	hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0);
+	hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
+}
+
+static const
+struct pre_pll_config *starfive_hdmi_phy_get_pre_pll_cfg(struct starfive_hdmi *hdmi,
+							 unsigned long rate)
+{
+	const struct pre_pll_config *cfg = pre_pll_cfg_table;
+
+	rate = (rate / 1000) * 1000;
+	for (; cfg->pixclock != 0; cfg++)
+		if (cfg->tmdsclock == rate && cfg->pixclock == rate)
+			break;
+
+	if (cfg->pixclock == 0)
+		return ERR_PTR(-EINVAL);
+
+	return cfg;
+}
+
+static int starfive_hdmi_phy_clk_set_rate(struct starfive_hdmi *hdmi)
+{
+	hdmi->post_cfg = post_pll_cfg_table;
+
+	hdmi->pre_cfg = starfive_hdmi_phy_get_pre_pll_cfg(hdmi, hdmi->tmds_rate);
+	if (IS_ERR(hdmi->pre_cfg))
+		return PTR_ERR(hdmi->pre_cfg);
+
+	for (; hdmi->post_cfg->tmdsclock != 0; hdmi->post_cfg++)
+		if (hdmi->tmds_rate <= hdmi->post_cfg->tmdsclock)
+			break;
+
+	starfive_hdmi_config_pll(hdmi);
+
+	return 0;
+}
+
+static int starfive_hdmi_config_video_timing(struct starfive_hdmi *hdmi,
+					     struct drm_display_mode *mode)
+{
+	int value;
+	/* Set detail external video timing */
+	value = mode->htotal;
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_L, value & 0xFF);
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF);
+
+	value = mode->htotal - mode->hdisplay;
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF);
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);
+
+	value = mode->htotal - mode->hsync_start;
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF);
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);
+
+	value = mode->hsync_end - mode->hsync_start;
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_L, value & 0xFF);
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF);
+
+	value = mode->vtotal;
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_L, value & 0xFF);
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF);
+
+	value = mode->vtotal - mode->vdisplay;
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF);
+
+	value = mode->vtotal - mode->vsync_start;
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF);
+
+	value = mode->vsync_end - mode->vsync_start;
+	hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDURATION, value & 0xFF);
+
+	/* Set detail external video timing polarity and interlace mode */
+	value = v_EXTERANL_VIDEO(1);
+	value |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
+		v_HSYNC_POLARITY(1) : v_HSYNC_POLARITY(0);
+	value |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
+		v_VSYNC_POLARITY(1) : v_VSYNC_POLARITY(0);
+	value |= mode->flags & DRM_MODE_FLAG_INTERLACE ?
+		v_INETLACE(1) : v_INETLACE(0);
+
+	hdmi_writeb(hdmi, HDMI_VIDEO_TIMING_CTL, value);
+	return 0;
+}
+
+static int starfive_hdmi_setup(struct starfive_hdmi *hdmi,
+			       struct drm_display_mode *mode)
+{
+	hdmi_modb(hdmi, STARFIVE_BIAS_CONTROL, STARFIVE_BIAS_ENABLE, STARFIVE_BIAS_ENABLE);
+	hdmi_writeb(hdmi, STARFIVE_RX_CONTROL, STARFIVE_RX_ENABLE);
+	hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
+
+	hdmi->tmds_rate = mode->clock * 1000;
+	starfive_hdmi_phy_clk_set_rate(hdmi);
+
+	while (!(hdmi_readb(hdmi, STARFIVE_PRE_PLL_LOCK_STATUS) & 0x1))
+		continue;
+	while (!(hdmi_readb(hdmi, STARFIVE_POST_PLL_LOCK_STATUS) & 0x1))
+		continue;
+
+	/*turn on LDO*/
+	hdmi_writeb(hdmi, STARFIVE_LDO_CONTROL, STARFIVE_LDO_ENABLE);
+	/*turn on serializer*/
+	hdmi_writeb(hdmi, STARFIVE_SERIALIER_CONTROL, STARFIVE_SERIALIER_ENABLE);
+
+	starfive_hdmi_tx_phy_power_down(hdmi);
+	starfive_hdmi_config_video_timing(hdmi, mode);
+	starfive_hdmi_tx_phy_power_on(hdmi);
+
+	starfive_hdmi_tmds_driver_on(hdmi);
+	starfive_hdmi_sync_tmds(hdmi);
+
+	return 0;
+}
+
+static void starfive_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+					   struct drm_display_mode *mode,
+					   struct drm_display_mode *adj_mode)
+{
+	struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
+
+	starfive_hdmi_setup(hdmi, adj_mode);
+
+	memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode));
+}
+
+static void starfive_hdmi_encoder_enable(struct drm_encoder *encoder)
+{
+	struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
+
+	pm_runtime_get_sync(hdmi->dev);
+}
+
+static void starfive_hdmi_encoder_disable(struct drm_encoder *encoder)
+{
+	struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
+
+	pm_runtime_put(hdmi->dev);
+}
+
+static bool starfive_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
+					     const struct drm_display_mode *mode,
+					     struct drm_display_mode *adj_mode)
+{
+	return true;
+}
+
+static int
+starfive_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
+				   struct drm_crtc_state *crtc_state,
+				   struct drm_connector_state *conn_state)
+{
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs starfive_hdmi_encoder_helper_funcs = {
+	.enable     = starfive_hdmi_encoder_enable,
+	.disable    = starfive_hdmi_encoder_disable,
+	.mode_fixup = starfive_hdmi_encoder_mode_fixup,
+	.mode_set   = starfive_hdmi_encoder_mode_set,
+	.atomic_check = starfive_hdmi_encoder_atomic_check,
+};
+
+static enum drm_connector_status
+starfive_hdmi_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct starfive_hdmi *hdmi = connector_to_hdmi(connector);
+	int ret;
+
+	ret = pm_runtime_get_sync(hdmi->dev);
+	if (ret < 0)
+		return ret;
+
+	ret = (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ?
+		connector_status_connected : connector_status_disconnected;
+
+	pm_runtime_put(hdmi->dev);
+
+	return ret;
+}
+
+static int starfive_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+	struct starfive_hdmi *hdmi = connector_to_hdmi(connector);
+	struct edid *edid;
+	int ret = 0;
+
+	if (!hdmi->ddc)
+		return 0;
+
+	edid = drm_get_edid(connector, hdmi->ddc);
+	if (edid) {
+		hdmi->hdmi_data.sink_is_hdmi = drm_detect_hdmi_monitor(edid);
+		hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid);
+		drm_connector_update_edid_property(connector, edid);
+		ret = drm_add_edid_modes(connector, edid);
+		kfree(edid);
+	}
+
+	return ret;
+}
+
+static enum drm_mode_status
+starfive_hdmi_connector_mode_valid(struct drm_connector *connector,
+				   struct drm_display_mode *mode)
+{
+	const struct pre_pll_config *cfg = pre_pll_cfg_table;
+	int pclk = mode->clock * 1000;
+	bool valid = false;
+	int i;
+
+	for (i = 0; cfg[i].pixclock != (~0UL); i++) {
+		if (pclk == cfg[i].pixclock) {
+			if (pclk > 297000000)
+				continue;
+
+			valid = true;
+			break;
+		}
+	}
+
+	return (valid) ? MODE_OK : MODE_BAD;
+}
+
+static int
+starfive_hdmi_probe_single_connector_modes(struct drm_connector *connector,
+					   u32 maxX, u32 maxY)
+{
+	struct starfive_hdmi *hdmi = connector_to_hdmi(connector);
+	int ret;
+
+	pm_runtime_get_sync(hdmi->dev);
+
+	ret = drm_helper_probe_single_connector_modes(connector, 3840, 2160);
+
+	pm_runtime_put(hdmi->dev);
+
+	return ret;
+}
+
+static void starfive_hdmi_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs starfive_hdmi_connector_funcs = {
+	.fill_modes = starfive_hdmi_probe_single_connector_modes,
+	.detect = starfive_hdmi_connector_detect,
+	.destroy = starfive_hdmi_connector_destroy,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static struct drm_connector_helper_funcs starfive_hdmi_connector_helper_funcs = {
+	.get_modes = starfive_hdmi_connector_get_modes,
+	.mode_valid = starfive_hdmi_connector_mode_valid,
+};
+
+static int starfive_hdmi_register(struct drm_device *drm, struct starfive_hdmi *hdmi)
+{
+	struct drm_encoder *encoder = &hdmi->encoder;
+	struct device *dev = hdmi->dev;
+
+	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+	/*
+	 * If we failed to find the CRTC(s) which this encoder is
+	 * supposed to be connected to, it's because the CRTC has
+	 * not been registered yet.  Defer probing, and hope that
+	 * the required CRTC is added later.
+	 */
+	if (encoder->possible_crtcs == 0)
+		return -EPROBE_DEFER;
+
+	drm_encoder_helper_add(encoder, &starfive_hdmi_encoder_helper_funcs);
+	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
+
+	hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+	drm_connector_helper_add(&hdmi->connector,
+				 &starfive_hdmi_connector_helper_funcs);
+	drm_connector_init_with_ddc(drm, &hdmi->connector,
+				    &starfive_hdmi_connector_funcs,
+				    DRM_MODE_CONNECTOR_HDMIA,
+				    hdmi->ddc);
+
+	drm_connector_attach_encoder(&hdmi->connector, encoder);
+
+	return 0;
+}
+
+static irqreturn_t starfive_hdmi_i2c_irq(struct starfive_hdmi *hdmi)
+{
+	struct starfive_hdmi_i2c *i2c = hdmi->i2c;
+	u8 stat;
+
+	stat = hdmi_readb(hdmi, HDMI_INTERRUPT_STATUS1);
+	if (!(stat & m_INT_EDID_READY))
+		return IRQ_NONE;
+
+	/* Clear HDMI EDID interrupt flag */
+	hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
+
+	complete(&i2c->cmp);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t starfive_hdmi_hardirq(int irq, void *dev_id)
+{
+	struct starfive_hdmi *hdmi = dev_id;
+	irqreturn_t ret = IRQ_NONE;
+	u8 interrupt;
+
+	if (hdmi->i2c)
+		ret = starfive_hdmi_i2c_irq(hdmi);
+
+	interrupt = hdmi_readb(hdmi, HDMI_STATUS);
+	if (interrupt & m_INT_HOTPLUG) {
+		hdmi_modb(hdmi, HDMI_STATUS, m_INT_HOTPLUG, m_INT_HOTPLUG);
+		ret = IRQ_WAKE_THREAD;
+	}
+
+	return ret;
+}
+
+static irqreturn_t starfive_hdmi_irq(int irq, void *dev_id)
+{
+	struct starfive_hdmi *hdmi = dev_id;
+
+	drm_helper_hpd_irq_event(hdmi->connector.dev);
+
+	return IRQ_HANDLED;
+}
+
+static int starfive_hdmi_i2c_read(struct starfive_hdmi *hdmi, struct i2c_msg *msgs)
+{
+	int length = msgs->len;
+	u8 *buf = msgs->buf;
+	int ret;
+
+	ret = wait_for_completion_timeout(&hdmi->i2c->cmp, HZ / 10);
+	if (!ret)
+		return -EAGAIN;
+
+	while (length--)
+		*buf++ = hdmi_readb(hdmi, HDMI_EDID_FIFO_ADDR);
+
+	return 0;
+}
+
+static int starfive_hdmi_i2c_write(struct starfive_hdmi *hdmi, struct i2c_msg *msgs)
+{
+	/*
+	 * The DDC module only support read EDID message, so
+	 * we assume that each word write to this i2c adapter
+	 * should be the offset of EDID word address.
+	 */
+	if (msgs->len != 1 ||
+	    (msgs->addr != DDC_ADDR && msgs->addr != DDC_SEGMENT_ADDR))
+		return -EINVAL;
+
+	reinit_completion(&hdmi->i2c->cmp);
+
+	if (msgs->addr == DDC_SEGMENT_ADDR)
+		hdmi->i2c->segment_addr = msgs->buf[0];
+	if (msgs->addr == DDC_ADDR)
+		hdmi->i2c->ddc_addr = msgs->buf[0];
+
+	/* Set edid fifo first addr */
+	hdmi_writeb(hdmi, HDMI_EDID_FIFO_OFFSET, 0x00);
+
+	/* Set edid word address 0x00/0x80 */
+	hdmi_writeb(hdmi, HDMI_EDID_WORD_ADDR, hdmi->i2c->ddc_addr);
+
+	/* Set edid segment pointer */
+	hdmi_writeb(hdmi, HDMI_EDID_SEGMENT_POINTER, hdmi->i2c->segment_addr);
+
+	return 0;
+}
+
+static int starfive_hdmi_i2c_xfer(struct i2c_adapter *adap,
+				  struct i2c_msg *msgs, int num)
+{
+	struct starfive_hdmi *hdmi = i2c_get_adapdata(adap);
+	struct starfive_hdmi_i2c *i2c = hdmi->i2c;
+	int i, ret = 0;
+
+	mutex_lock(&i2c->lock);
+
+	/* Clear the EDID interrupt flag and unmute the interrupt */
+	hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, m_INT_EDID_READY);
+	hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
+
+	for (i = 0; i < num; i++) {
+		DRM_DEV_DEBUG(hdmi->dev,
+			      "xfer: num: %d/%d, len: %d, flags: %#x\n",
+			      i + 1, num, msgs[i].len, msgs[i].flags);
+
+		if (msgs[i].flags & I2C_M_RD)
+			ret = starfive_hdmi_i2c_read(hdmi, &msgs[i]);
+		else
+			ret = starfive_hdmi_i2c_write(hdmi, &msgs[i]);
+
+		if (ret < 0)
+			break;
+	}
+
+	if (!ret)
+		ret = num;
+
+	/* Mute HDMI EDID interrupt */
+	hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0);
+
+	mutex_unlock(&i2c->lock);
+
+	return ret;
+}
+
+static u32 starfive_hdmi_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm starfive_hdmi_algorithm = {
+	.master_xfer	= starfive_hdmi_i2c_xfer,
+	.functionality	= starfive_hdmi_i2c_func,
+};
+
+static struct i2c_adapter *starfive_hdmi_i2c_adapter(struct starfive_hdmi *hdmi)
+{
+	struct i2c_adapter *adap;
+	struct starfive_hdmi_i2c *i2c;
+	int ret;
+
+	i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_init(&i2c->lock);
+	init_completion(&i2c->cmp);
+
+	adap = &i2c->adap;
+	adap->class = I2C_CLASS_DDC;
+	adap->owner = THIS_MODULE;
+	adap->dev.parent = hdmi->dev;
+	adap->algo = &starfive_hdmi_algorithm;
+	strscpy(adap->name, "Starfive HDMI", sizeof(adap->name));
+	i2c_set_adapdata(adap, hdmi);
+
+	ret = i2c_add_adapter(adap);
+	if (ret) {
+		dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name);
+		devm_kfree(hdmi->dev, i2c);
+		return ERR_PTR(ret);
+	}
+
+	hdmi->i2c = i2c;
+
+	DRM_DEV_INFO(hdmi->dev, "registered %s I2C bus driver success\n", adap->name);
+
+	return adap;
+}
+
+static int starfive_hdmi_get_clk_rst(struct device *dev, struct starfive_hdmi *hdmi)
+{
+	hdmi->sys_clk = devm_clk_get(dev, "sysclk");
+	if (IS_ERR(hdmi->sys_clk)) {
+		DRM_DEV_ERROR(dev, "Unable to get HDMI sysclk clk\n");
+		return PTR_ERR(hdmi->sys_clk);
+	}
+	hdmi->mclk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(hdmi->mclk)) {
+		DRM_DEV_ERROR(dev, "Unable to get HDMI mclk clk\n");
+		return PTR_ERR(hdmi->mclk);
+	}
+	hdmi->bclk = devm_clk_get(dev, "bclk");
+	if (IS_ERR(hdmi->bclk)) {
+		DRM_DEV_ERROR(dev, "Unable to get HDMI bclk clk\n");
+		return PTR_ERR(hdmi->bclk);
+	}
+	hdmi->tx_rst = reset_control_get_shared(dev, "hdmi_tx");
+	if (IS_ERR(hdmi->tx_rst)) {
+		DRM_DEV_ERROR(dev, "Unable to get HDMI tx rst\n");
+		return PTR_ERR(hdmi->tx_rst);
+	}
+	return 0;
+}
+
+static int starfive_hdmi_bind(struct device *dev, struct device *master,
+			      void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm = data;
+	struct starfive_hdmi *hdmi;
+	struct resource *iores;
+	int irq;
+	int ret;
+
+	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
+	if (!hdmi)
+		return -ENOMEM;
+
+	hdmi->dev = dev;
+	hdmi->drm_dev = drm;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hdmi->regs = devm_ioremap_resource(dev, iores);
+	if (IS_ERR(hdmi->regs))
+		return PTR_ERR(hdmi->regs);
+
+	ret = starfive_hdmi_get_clk_rst(dev, hdmi);
+	ret = starfive_hdmi_enable_clk_deassert_rst(dev, hdmi);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = irq;
+		goto err_disable_clk;
+	}
+
+	hdmi->ddc = starfive_hdmi_i2c_adapter(hdmi);
+	if (IS_ERR(hdmi->ddc)) {
+		ret = PTR_ERR(hdmi->ddc);
+		hdmi->ddc = NULL;
+		goto err_disable_clk;
+	}
+
+	hdmi->tmds_rate = clk_get_rate(hdmi->sys_clk);
+
+	starfive_hdmi_i2c_init(hdmi);
+
+	ret = starfive_hdmi_register(drm, hdmi);
+	if (ret)
+		goto err_put_adapter;
+
+	dev_set_drvdata(dev, hdmi);
+
+	/* Unmute hotplug interrupt */
+	hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1));
+
+	ret = devm_request_threaded_irq(dev, irq, starfive_hdmi_hardirq,
+					starfive_hdmi_irq, IRQF_SHARED,
+					dev_name(dev), hdmi);
+	if (ret < 0)
+		goto err_cleanup_hdmi;
+
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
+	pm_runtime_enable(&pdev->dev);
+
+	starfive_hdmi_disable_clk_assert_rst(dev, hdmi);
+
+	return 0;
+err_cleanup_hdmi:
+	hdmi->connector.funcs->destroy(&hdmi->connector);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
+err_put_adapter:
+	i2c_put_adapter(hdmi->ddc);
+err_disable_clk:
+	clk_disable_unprepare(hdmi->sys_clk);
+	clk_disable_unprepare(hdmi->mclk);
+	clk_disable_unprepare(hdmi->bclk);
+
+	return ret;
+}
+
+static void starfive_hdmi_unbind(struct device *dev, struct device *master,
+				 void *data)
+{
+	struct starfive_hdmi *hdmi = dev_get_drvdata(dev);
+
+	hdmi->connector.funcs->destroy(&hdmi->connector);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
+
+	i2c_put_adapter(hdmi->ddc);
+
+	starfive_hdmi_disable_clk_assert_rst(dev, hdmi);
+}
+
+static const struct component_ops starfive_hdmi_ops = {
+	.bind	= starfive_hdmi_bind,
+	.unbind	= starfive_hdmi_unbind,
+};
+
+static int starfive_hdmi_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &starfive_hdmi_ops);
+}
+
+static int starfive_hdmi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &starfive_hdmi_ops);
+
+	return 0;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+	SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(hdmi_system_pm_suspend, hdmi_system_pm_resume)
+};
+
+static const struct of_device_id starfive_hdmi_dt_ids[] = {
+	{ .compatible = "starfive,hdmi",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, starfive_hdmi_dt_ids);
+
+struct platform_driver starfive_hdmi_driver = {
+	.probe  = starfive_hdmi_probe,
+	.remove = starfive_hdmi_remove,
+	.driver = {
+		.name = "starfive-hdmi",
+		.of_match_table = starfive_hdmi_dt_ids,
+		.pm = &hdmi_pm_ops,
+	},
+};
+
+MODULE_AUTHOR("StarFive Corporation");
+MODULE_DESCRIPTION("Starfive HDMI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/verisilicon/starfive_hdmi.h b/drivers/gpu/drm/verisilicon/starfive_hdmi.h
new file mode 100644
index 000000000000..d151c61f9a3e
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/starfive_hdmi.h
@@ -0,0 +1,296 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
+ */
+
+#ifndef __STARFIVE_HDMI_H__
+#define __STARFIVE_HDMI_H__
+
+#include <drm/bridge/dw_hdmi.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#define DDC_SEGMENT_ADDR		0x30
+
+#define HDMI_SCL_RATE			(100 * 1000)
+#define DDC_BUS_FREQ_L			0x4b
+#define DDC_BUS_FREQ_H			0x4c
+
+#define HDMI_SYS_CTRL			0x00
+#define m_RST_ANALOG			BIT(6)
+#define v_RST_ANALOG			0
+#define v_NOT_RST_ANALOG		BIT(6)
+#define m_RST_DIGITAL			BIT(5)
+#define v_RST_DIGITAL			0
+#define v_NOT_RST_DIGITAL		BIT(5)
+#define m_REG_CLK_INV			BIT(4)
+#define v_REG_CLK_NOT_INV		0
+#define v_REG_CLK_INV			BIT(4)
+#define m_VCLK_INV			BIT(3)
+#define v_VCLK_NOT_INV			0
+#define v_VCLK_INV			BIT(3)
+#define m_REG_CLK_SOURCE		BIT(2)
+#define v_REG_CLK_SOURCE_TMDS		0
+#define v_REG_CLK_SOURCE_SYS		BIT(2)
+#define m_POWER				BIT(1)
+#define v_PWR_ON			0
+#define v_PWR_OFF			BIT(1)
+#define m_INT_POL			BIT(0)
+#define v_INT_POL_HIGH			1
+#define v_INT_POL_LOW			0
+
+#define HDMI_AV_MUTE			0x05
+#define m_AVMUTE_CLEAR			BIT(7)
+#define m_AVMUTE_ENABLE			BIT(6)
+#define m_AUDIO_MUTE			BIT(1)
+#define m_VIDEO_BLACK			BIT(0)
+#define v_AVMUTE_CLEAR(n)		((n) << 7)
+#define v_AVMUTE_ENABLE(n)		((n) << 6)
+#define v_AUDIO_MUTE(n)			((n) << 1)
+#define v_VIDEO_MUTE(n)			((n) << 0)
+
+#define HDMI_VIDEO_TIMING_CTL		0x08
+#define v_VSYNC_POLARITY(n)		((n) << 3)
+#define v_HSYNC_POLARITY(n)		((n) << 2)
+#define v_INETLACE(n)			((n) << 1)
+#define v_EXTERANL_VIDEO(n)		((n) << 0)
+
+#define HDMI_VIDEO_EXT_HTOTAL_L		0x09
+#define HDMI_VIDEO_EXT_HTOTAL_H		0x0a
+#define HDMI_VIDEO_EXT_HBLANK_L		0x0b
+#define HDMI_VIDEO_EXT_HBLANK_H		0x0c
+#define HDMI_VIDEO_EXT_HDELAY_L		0x0d
+#define HDMI_VIDEO_EXT_HDELAY_H		0x0e
+#define HDMI_VIDEO_EXT_HDURATION_L	0x0f
+#define HDMI_VIDEO_EXT_HDURATION_H	0x10
+#define HDMI_VIDEO_EXT_VTOTAL_L		0x11
+#define HDMI_VIDEO_EXT_VTOTAL_H		0x12
+#define HDMI_VIDEO_EXT_VBLANK		0x13
+#define HDMI_VIDEO_EXT_VDELAY		0x14
+#define HDMI_VIDEO_EXT_VDURATION	0x15
+
+#define HDMI_EDID_SEGMENT_POINTER	0x4d
+#define HDMI_EDID_WORD_ADDR			0x4e
+#define HDMI_EDID_FIFO_OFFSET		0x4f
+#define HDMI_EDID_FIFO_ADDR			0x50
+
+#define HDMI_INTERRUPT_MASK1		0xc0
+#define HDMI_INTERRUPT_STATUS1		0xc1
+#define	m_INT_ACTIVE_VSYNC			BIT(5)
+#define m_INT_EDID_READY			BIT(2)
+
+#define HDMI_STATUS					0xc8
+#define m_HOTPLUG					BIT(7)
+#define m_MASK_INT_HOTPLUG			BIT(5)
+#define m_INT_HOTPLUG				BIT(1)
+#define v_MASK_INT_HOTPLUG(n)		(((n) & 0x1) << 5)
+
+#define HDMI_SYNC					0xce
+
+#define UPDATE(x, h, l)\
+({\
+	typeof(x) x_ = (x);\
+	typeof(h) h_ = (h);\
+	typeof(l) l_ = (l);\
+	(((x_) << (l_)) & GENMASK((h_), (l_)));\
+})
+
+/* REG: 0x1a0 */
+#define STARFIVE_PRE_PLL_CONTROL			0x1a0
+#define STARFIVE_PCLK_VCO_DIV_5_MASK			BIT(1)
+#define STARFIVE_PCLK_VCO_DIV_5(x)			UPDATE(x, 1, 1)
+#define STARFIVE_PRE_PLL_POWER_DOWN			BIT(0)
+
+/* REG: 0x1a1 */
+#define STARFIVE_PRE_PLL_DIV_1				0x1a1
+#define STARFIVE_PRE_PLL_PRE_DIV_MASK			GENMASK(5, 0)
+#define STARFIVE_PRE_PLL_PRE_DIV(x)			UPDATE(x, 5, 0)
+
+/* REG: 0x1a2 */
+#define STARFIVE_PRE_PLL_DIV_2				0x1a2
+#define STARFIVE_SPREAD_SPECTRUM_MOD_DOWN		BIT(7)
+#define STARFIVE_SPREAD_SPECTRUM_MOD_DISABLE		BIT(6)
+#define STARFIVE_PRE_PLL_FRAC_DIV_DISABLE		UPDATE(3, 5, 4)
+#define STARFIVE_PRE_PLL_FB_DIV_11_8_MASK		GENMASK(3, 0)
+#define STARFIVE_PRE_PLL_FB_DIV_11_8(x)			UPDATE((x) >> 8, 3, 0)
+
+/* REG: 0x1a3 */
+#define STARFIVE_PRE_PLL_DIV_3				0x1a3
+#define STARFIVE_PRE_PLL_FB_DIV_7_0(x)			UPDATE(x, 7, 0)
+
+/* REG: 0x1a4*/
+#define STARFIVE_PRE_PLL_DIV_4				0x1a4
+#define STARFIVE_PRE_PLL_TMDSCLK_DIV_C_MASK		GENMASK(1, 0)
+#define STARFIVE_PRE_PLL_TMDSCLK_DIV_C(x)		UPDATE(x, 1, 0)
+#define STARFIVE_PRE_PLL_TMDSCLK_DIV_B_MASK		GENMASK(3, 2)
+#define STARFIVE_PRE_PLL_TMDSCLK_DIV_B(x)		UPDATE(x, 3, 2)
+#define STARFIVE_PRE_PLL_TMDSCLK_DIV_A_MASK		GENMASK(5, 4)
+#define STARFIVE_PRE_PLL_TMDSCLK_DIV_A(x)		UPDATE(x, 5, 4)
+
+/* REG: 0x1a5 */
+#define STARFIVE_PRE_PLL_DIV_5				0x1a5
+#define STARFIVE_PRE_PLL_PCLK_DIV_B_SHIFT		5
+#define STARFIVE_PRE_PLL_PCLK_DIV_B_MASK		GENMASK(6, 5)
+#define STARFIVE_PRE_PLL_PCLK_DIV_B(x)			UPDATE(x, 6, 5)
+#define STARFIVE_PRE_PLL_PCLK_DIV_A_MASK		GENMASK(4, 0)
+#define STARFIVE_PRE_PLL_PCLK_DIV_A(x)			UPDATE(x, 4, 0)
+
+/* REG: 0x1a6 */
+#define STARFIVE_PRE_PLL_DIV_6				0x1a6
+#define STARFIVE_PRE_PLL_PCLK_DIV_C_SHIFT		5
+#define STARFIVE_PRE_PLL_PCLK_DIV_C_MASK		GENMASK(6, 5)
+#define STARFIVE_PRE_PLL_PCLK_DIV_C(x)			UPDATE(x, 6, 5)
+#define STARFIVE_PRE_PLL_PCLK_DIV_D_MASK		GENMASK(4, 0)
+#define STARFIVE_PRE_PLL_PCLK_DIV_D(x)			UPDATE(x, 4, 0)
+
+/* REG: 0x1a9 */
+#define STARFIVE_PRE_PLL_LOCK_STATUS			0x1a9
+
+/* REG: 0x1aa */
+#define STARFIVE_POST_PLL_DIV_1				0x1aa
+#define STARFIVE_POST_PLL_POST_DIV_ENABLE		GENMASK(3, 2)
+#define STARFIVE_POST_PLL_REFCLK_SEL_TMDS		BIT(1)
+#define STARFIVE_POST_PLL_POWER_DOWN			BIT(0)
+#define STARFIVE_POST_PLL_FB_DIV_8(x)			UPDATE(((x) >> 8) << 4, 4, 4)
+
+/* REG:0x1ab */
+#define STARFIVE_POST_PLL_DIV_2				0x1ab
+#define STARFIVE_POST_PLL_Pre_DIV_MASK			GENMASK(5, 0)
+#define STARFIVE_POST_PLL_PRE_DIV(x)			UPDATE(x, 5, 0)
+
+/* REG: 0x1ac */
+#define STARFIVE_POST_PLL_DIV_3				0x1ac
+#define STARFIVE_POST_PLL_FB_DIV_7_0(x)			UPDATE(x, 7, 0)
+
+/* REG: 0x1ad */
+#define STARFIVE_POST_PLL_DIV_4				0x1ad
+#define STARFIVE_POST_PLL_POST_DIV_MASK			GENMASK(2, 0)
+#define STARFIVE_POST_PLL_POST_DIV_2			0x0
+#define STARFIVE_POST_PLL_POST_DIV_4			0x1
+#define STARFIVE_POST_PLL_POST_DIV_8			0x3
+
+/* REG: 0x1af */
+#define STARFIVE_POST_PLL_LOCK_STATUS			0x1af
+
+/* REG: 0x1b0 */
+#define STARFIVE_BIAS_CONTROL				0x1b0
+#define STARFIVE_BIAS_ENABLE				BIT(2)
+
+/* REG: 0x1b2 */
+#define STARFIVE_TMDS_CONTROL				0x1b2
+#define STARFIVE_TMDS_CLK_DRIVER_EN			BIT(3)
+#define STARFIVE_TMDS_D2_DRIVER_EN			BIT(2)
+#define STARFIVE_TMDS_D1_DRIVER_EN			BIT(1)
+#define STARFIVE_TMDS_D0_DRIVER_EN			BIT(0)
+#define STARFIVE_TMDS_DRIVER_ENABLE			(STARFIVE_TMDS_CLK_DRIVER_EN | \
+							 STARFIVE_TMDS_D2_DRIVER_EN | \
+							 STARFIVE_TMDS_D1_DRIVER_EN | \
+							 STARFIVE_TMDS_D0_DRIVER_EN)
+
+/* REG: 0x1b4 */
+#define STARFIVE_LDO_CONTROL				0x1b4
+#define STARFIVE_LDO_D2_EN				BIT(2)
+#define STARFIVE_LDO_D1_EN				BIT(1)
+#define STARFIVE_LDO_D0_EN				BIT(0)
+#define STARFIVE_LDO_ENABLE				(STARFIVE_LDO_D2_EN | \
+							 STARFIVE_LDO_D1_EN | \
+							 STARFIVE_LDO_D0_EN)
+
+/* REG: 0x1be */
+#define STARFIVE_SERIALIER_CONTROL			0x1be
+#define STARFIVE_SERIALIER_D2_EN			BIT(6)
+#define STARFIVE_SERIALIER_D1_EN			BIT(5)
+#define STARFIVE_SERIALIER_D0_EN			BIT(4)
+#define STARFIVE_SERIALIER_ENABLE			(STARFIVE_SERIALIER_D2_EN | \
+							 STARFIVE_SERIALIER_D1_EN | \
+							  STARFIVE_SERIALIER_D0_EN)
+
+/* REG: 0x1cc */
+#define STARFIVE_RX_CONTROL				0x1cc
+#define STARFIVE_RX_EN					BIT(3)
+#define STARFIVE_RX_CHANNEL_2_EN			BIT(2)
+#define STARFIVE_RX_CHANNEL_1_EN			BIT(1)
+#define STARFIVE_RX_CHANNEL_0_EN			BIT(0)
+#define STARFIVE_RX_ENABLE				(STARFIVE_RX_EN | \
+							 STARFIVE_RX_CHANNEL_2_EN | \
+							 STARFIVE_RX_CHANNEL_1_EN | \
+							 STARFIVE_RX_CHANNEL_0_EN)
+
+/* REG: 0x1d1 */
+#define STARFIVE_PRE_PLL_FRAC_DIV_H			0x1d1
+#define STARFIVE_PRE_PLL_FRAC_DIV_23_16(x)		UPDATE((x) >> 16, 7, 0)
+/* REG: 0x1d2 */
+#define STARFIVE_PRE_PLL_FRAC_DIV_M			0x1d2
+#define STARFIVE_PRE_PLL_FRAC_DIV_15_8(x)		UPDATE((x) >> 8, 7, 0)
+/* REG: 0x1d3 */
+#define STARFIVE_PRE_PLL_FRAC_DIV_L			0x1d3
+#define STARFIVE_PRE_PLL_FRAC_DIV_7_0(x)		UPDATE(x, 7, 0)
+
+struct pre_pll_config {
+	unsigned long pixclock;
+	unsigned long tmdsclock;
+	u8 prediv;
+	u16 fbdiv;
+	u8 tmds_div_a;
+	u8 tmds_div_b;
+	u8 tmds_div_c;
+	u8 pclk_div_a;
+	u8 pclk_div_b;
+	u8 pclk_div_c;
+	u8 pclk_div_d;
+	u8 vco_div_5_en;
+	u32 fracdiv;
+};
+
+struct post_pll_config {
+	unsigned long tmdsclock;
+	u8 prediv;
+	u16 fbdiv;
+	u8 postdiv;
+	u8 post_div_en;
+	u8 version;
+};
+
+struct phy_config {
+	unsigned long	tmdsclock;
+	u8		regs[14];
+};
+
+struct hdmi_data_info {
+	int vic;
+	bool sink_is_hdmi;
+	bool sink_has_audio;
+	unsigned int enc_in_format;
+	unsigned int enc_out_format;
+	unsigned int colorimetry;
+};
+
+struct starfive_hdmi {
+	struct device *dev;
+	struct drm_device *drm_dev;
+
+	int irq;
+	struct clk *sys_clk;
+	struct clk *mclk;
+	struct clk *bclk;
+	struct reset_control *tx_rst;
+	void __iomem *regs;
+
+	struct drm_connector	connector;
+	struct drm_encoder	encoder;
+
+	struct starfive_hdmi_i2c *i2c;
+	struct i2c_adapter *ddc;
+
+	unsigned long tmds_rate;
+
+	struct hdmi_data_info	hdmi_data;
+	struct drm_display_mode previous_mode;
+	const struct pre_pll_config	*pre_cfg;
+	const struct post_pll_config	*post_cfg;
+};
+
+#endif /* __STARFIVE_HDMI_H__ */
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
index c28bfd74ffc9..b740fe934035 100644
--- a/drivers/gpu/drm/verisilicon/vs_drv.c
+++ b/drivers/gpu/drm/verisilicon/vs_drv.c
@@ -183,6 +183,12 @@ static const struct component_master_ops vs_drm_ops = {
 
 static struct platform_driver *drm_sub_drivers[] = {
 	&dc_platform_driver,
+
+	/* connector + encoder*/
+#ifdef CONFIG_STARFIVE_HDMI
+	&starfive_hdmi_driver,
+#endif
+
 };
 
 #define NUM_DRM_DRIVERS \
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
index 0382b44e3bf0..3668e1d65b3f 100644
--- a/drivers/gpu/drm/verisilicon/vs_drv.h
+++ b/drivers/gpu/drm/verisilicon/vs_drv.h
@@ -45,4 +45,8 @@ static inline bool is_iommu_enabled(struct drm_device *dev)
 	return priv->domain ? true : false;
 }
 
+#ifdef CONFIG_STARFIVE_HDMI
+extern struct platform_driver starfive_hdmi_driver;
+#endif
+
 #endif /* __VS_DRV_H__ */
-- 
2.34.1


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

* Re: [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem
  2023-06-02  7:40 ` [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem Keith Zhao
@ 2023-06-02 18:21   ` Conor Dooley
  2023-06-06 18:41     ` Shengyu Qu
  2023-06-07  7:35   ` Krzysztof Kozlowski
  1 sibling, 1 reply; 46+ messages in thread
From: Conor Dooley @ 2023-06-02 18:21 UTC (permalink / raw)
  To: Keith Zhao
  Cc: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig, David Airlie, Daniel Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Emil Renner Berthing,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Philipp Zabel, Sumit Semwal,
	christian.koenig, Bjorn Andersson, Heiko Stuebner, Shawn Guo,
	Jagan Teki, Chris Morgan, Jack Zhu, Shengyang Chen,
	Changhuang Liang

[-- Attachment #1: Type: text/plain, Size: 6595 bytes --]

Hey Keith,

On Fri, Jun 02, 2023 at 03:40:35PM +0800, Keith Zhao wrote:
> Add bindings for JH7110 display subsystem which
> has a display controller verisilicon dc8200
> and an HDMI interface.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>  .../display/verisilicon/starfive-hdmi.yaml    |  93 +++++++++++++++
>  .../display/verisilicon/verisilicon-dc.yaml   | 110 ++++++++++++++++++
>  .../display/verisilicon/verisilicon-drm.yaml  |  42 +++++++
>  .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
>  MAINTAINERS                                   |   7 ++
>  5 files changed, 254 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml b/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
> new file mode 100644
> index 000000000000..c30b7954a355
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
> @@ -0,0 +1,93 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/verisilicon/starfive-hdmi.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: StarFive HDMI transmiter
> +
> +description:
> +  The StarFive SoC uses the HDMI signal transmiter based on innosilicon IP

Is innosilicon the same thing as verisilicon? Also
s/transmiter/transmitter/, both here and in the title.


> +  to generate HDMI signal from its input and transmit the signal to the screen.
> +
> +maintainers:
> +  - Keith Zhao <keith.zhao@starfivetech.com>
> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
> +
> +properties:
> +  compatible:
> +    const: starfive,hdmi

Is this going to work on every SoC that StarFive has ever & will ever
make? Please use soc-based compatibles ;)

> +
> +  reg:
> +    minItems: 1
> +
> +  interrupts:
> +    items:
> +      - description: The HDMI hot plug detection interrupt.
> +
> +  clocks:
> +    items:
> +      - description: System clock of HDMI module.
> +      - description: Mclk clock of HDMI audio.
> +      - description: Bclk clock of HDMI audio.
> +      - description: Pixel clock generated by HDMI module.
> +
> +  clock-names:
> +    items:
> +      - const: sysclk
> +      - const: mclk
> +      - const: bclk
> +      - const: pclk
> +
> +  resets:
> +    items:
> +      - description: Reset for HDMI module.
> +
> +  reset-names:
> +    items:
> +      - const: hdmi_tx

You only have one item here, you don't need the "items: - const:",
"const:" alone will do.


> diff --git a/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
> new file mode 100644
> index 000000000000..1322502c4cde
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
> @@ -0,0 +1,110 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-dc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: StarFive display controller
> +
> +description:
> +  The StarFive SoC uses the display controller based on Verisilicon IP
> +  to transfer the image data from a video memory
> +  buffer to an external LCD interface.

Is it based on Verisilicon IP, or is it exactly that verisilicon IP? I
ask because...

> +maintainers:
> +  - Keith Zhao <keith.zhao@starfivetech.com>
> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
> +
> +properties:
> +  compatible:
> +    const: verisilicon,dc8200

...the compatible is the verisilicon IP. I would be a lot happier if
the compatibles were set yp for something like:
"starfive,jh7110-foo", "verisilicon,dc8200"

> diff --git a/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
> new file mode 100644
> index 000000000000..aed8d4af2c55
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
> @@ -0,0 +1,42 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-drm.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Verisilicon DRM master device
> +
> +maintainers:
> +  - Keith Zhao <keith.zhao@starfivetech.com>
> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
> +
> +description: |
> +  The Verisilicon DRM master device is a virtual device needed to list all
> +  display controller or other display interface nodes that comprise the
> +  graphics subsystem.
> +
> +properties:
> +  compatible:
> +    const: verisilicon,display-subsystem

Same here.

> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> index 82d39ab0231b..52c04fd098be 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> @@ -1436,6 +1436,8 @@ patternProperties:
>      description: Variscite Ltd.
>    "^vdl,.*":
>      description: Van der Laan b.v.
> +  "^verisilicon,.*":
> +    description: Verisilicon Technologies, Inc.

This should be in it's own patch.

Cheers,
Conor.

>    "^vertexcom,.*":
>      description: Vertexcom Technologies, Inc.
>    "^via,.*":
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2a0496448b7f..293aa13d484c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7049,6 +7049,13 @@ F:	Documentation/devicetree/bindings/display/brcm,bcm2835-*.yaml
>  F:	drivers/gpu/drm/vc4/
>  F:	include/uapi/drm/vc4_drm.h
>  
> +DRM DRIVERS FOR VERISILICON
> +M:	Keith Zhao <keith.zhao@starfivetech.com>
> +L:	dri-devel@lists.freedesktop.org
> +S:	Maintained
> +T:	git git://anongit.freedesktop.org/drm/drm-misc
> +F:	Documentation/devicetree/bindings/display/verisilicon/
> +
>  DRM DRIVERS FOR VIVANTE GPU IP
>  M:	Lucas Stach <l.stach@pengutronix.de>
>  R:	Russell King <linux+etnaviv@armlinux.org.uk>
> -- 
> 2.34.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver
  2023-06-02  7:40 ` [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver Keith Zhao
@ 2023-06-05  8:08   ` Philipp Zabel
  2023-06-05  9:56   ` Maxime Ripard
  2023-06-23  2:38   ` Hoegeun Kwon
  2 siblings, 0 replies; 46+ messages in thread
From: Philipp Zabel @ 2023-06-05  8:08 UTC (permalink / raw)
  To: Keith Zhao
  Cc: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig, David Airlie, Daniel Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Emil Renner Berthing,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Jack Zhu, Shengyang Chen, Changhuang Liang

Hi Keith,

On Fri, Jun 02, 2023 at 03:40:43PM +0800, Keith Zhao wrote:
> Add HDMI dirver for StarFive SoC JH7110.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>  drivers/gpu/drm/verisilicon/Kconfig         |  11 +
>  drivers/gpu/drm/verisilicon/Makefile        |   1 +
>  drivers/gpu/drm/verisilicon/starfive_hdmi.c | 928 ++++++++++++++++++++
>  drivers/gpu/drm/verisilicon/starfive_hdmi.h | 296 +++++++
>  drivers/gpu/drm/verisilicon/vs_drv.c        |   6 +
>  drivers/gpu/drm/verisilicon/vs_drv.h        |   4 +
>  6 files changed, 1246 insertions(+)
>  create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.c
>  create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.h
> 
[...]
> diff --git a/drivers/gpu/drm/verisilicon/starfive_hdmi.c b/drivers/gpu/drm/verisilicon/starfive_hdmi.c
> new file mode 100644
> index 000000000000..128ecca03309
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/starfive_hdmi.c
> @@ -0,0 +1,928 @@
[...]
> +static int starfive_hdmi_enable_clk_deassert_rst(struct device *dev, struct starfive_hdmi *hdmi)
> +{
> +	int ret;
> +
> +	ret = clk_prepare_enable(hdmi->sys_clk);
> +	if (ret) {
> +		DRM_DEV_ERROR(dev, "Cannot enable HDMI sys clock: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(hdmi->mclk);
> +	if (ret) {
> +		DRM_DEV_ERROR(dev, "Cannot enable HDMI mclk clock: %d\n", ret);
> +		return ret;
> +	}
> +	ret = clk_prepare_enable(hdmi->bclk);
> +	if (ret) {
> +		DRM_DEV_ERROR(dev, "Cannot enable HDMI bclk clock: %d\n", ret);
> +		return ret;
> +	}
> +	ret = reset_control_deassert(hdmi->tx_rst);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to deassert tx_rst\n");

The error paths should clk_disable_unprepare() enabled clocks.

> +		return ret;
> +	}
> +	return 0;
> +}
> +
[...]
> +static int starfive_hdmi_get_clk_rst(struct device *dev, struct starfive_hdmi *hdmi)
> +{
> +	hdmi->sys_clk = devm_clk_get(dev, "sysclk");
> +	if (IS_ERR(hdmi->sys_clk)) {
> +		DRM_DEV_ERROR(dev, "Unable to get HDMI sysclk clk\n");
> +		return PTR_ERR(hdmi->sys_clk);
> +	}
> +	hdmi->mclk = devm_clk_get(dev, "mclk");
> +	if (IS_ERR(hdmi->mclk)) {
> +		DRM_DEV_ERROR(dev, "Unable to get HDMI mclk clk\n");
> +		return PTR_ERR(hdmi->mclk);
> +	}
> +	hdmi->bclk = devm_clk_get(dev, "bclk");
> +	if (IS_ERR(hdmi->bclk)) {
> +		DRM_DEV_ERROR(dev, "Unable to get HDMI bclk clk\n");
> +		return PTR_ERR(hdmi->bclk);
> +	}
> +	hdmi->tx_rst = reset_control_get_shared(dev, "hdmi_tx");

Use devm_reset_control_get_shared() for consistency, otherwise this is missing
a reset_control_put() somewhere.

regards
Philipp

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

* Re: [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver
  2023-06-02  7:40 ` [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver Keith Zhao
  2023-06-05  8:08   ` Philipp Zabel
@ 2023-06-05  9:56   ` Maxime Ripard
  2023-06-23  2:38   ` Hoegeun Kwon
  2 siblings, 0 replies; 46+ messages in thread
From: Maxime Ripard @ 2023-06-05  9:56 UTC (permalink / raw)
  To: Keith Zhao
  Cc: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig, David Airlie, Daniel Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Emil Renner Berthing,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Maarten Lankhorst,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Jack Zhu, Shengyang Chen, Changhuang Liang

[-- Attachment #1: Type: text/plain, Size: 9614 bytes --]

Hi,

On Fri, Jun 02, 2023 at 03:40:43PM +0800, Keith Zhao wrote:
> Add HDMI dirver for StarFive SoC JH7110.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>

I have a few high level comments:

> +static int starfive_hdmi_setup(struct starfive_hdmi *hdmi,
> +			       struct drm_display_mode *mode)
> +{
> +	hdmi_modb(hdmi, STARFIVE_BIAS_CONTROL, STARFIVE_BIAS_ENABLE, STARFIVE_BIAS_ENABLE);
> +	hdmi_writeb(hdmi, STARFIVE_RX_CONTROL, STARFIVE_RX_ENABLE);
> +	hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
> +
> +	hdmi->tmds_rate = mode->clock * 1000;
> +	starfive_hdmi_phy_clk_set_rate(hdmi);
> +
> +	while (!(hdmi_readb(hdmi, STARFIVE_PRE_PLL_LOCK_STATUS) & 0x1))
> +		continue;
> +	while (!(hdmi_readb(hdmi, STARFIVE_POST_PLL_LOCK_STATUS) & 0x1))
> +		continue;
> +
> +	/*turn on LDO*/
> +	hdmi_writeb(hdmi, STARFIVE_LDO_CONTROL, STARFIVE_LDO_ENABLE);
> +	/*turn on serializer*/
> +	hdmi_writeb(hdmi, STARFIVE_SERIALIER_CONTROL, STARFIVE_SERIALIER_ENABLE);
> +
> +	starfive_hdmi_tx_phy_power_down(hdmi);
> +	starfive_hdmi_config_video_timing(hdmi, mode);
> +	starfive_hdmi_tx_phy_power_on(hdmi);
> +
> +	starfive_hdmi_tmds_driver_on(hdmi);
> +	starfive_hdmi_sync_tmds(hdmi);
> +
> +	return 0;
> +}

The PHY PLL supports rate until 594MHz, but I don't see any scrambler
setup here?

> +static void starfive_hdmi_encoder_mode_set(struct drm_encoder *encoder,
> +					   struct drm_display_mode *mode,
> +					   struct drm_display_mode *adj_mode)
> +{
> +	struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
> +
> +	starfive_hdmi_setup(hdmi, adj_mode);

You should put that call into the enable callback, there's no need to
power it up at that point.

> +	memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode));

You don't seem to be using that anywhere, and it's not the previous but
the current mode.

> +}
> +
> +static void starfive_hdmi_encoder_enable(struct drm_encoder *encoder)
> +{
> +	struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
> +
> +	pm_runtime_get_sync(hdmi->dev);
> +}
> +
> +static void starfive_hdmi_encoder_disable(struct drm_encoder *encoder)
> +{
> +	struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
> +
> +	pm_runtime_put(hdmi->dev);
> +}
> +
> +static bool starfive_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
> +					     const struct drm_display_mode *mode,
> +					     struct drm_display_mode *adj_mode)
> +{
> +	return true;
> +}

You can drop that one

> +static int
> +starfive_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
> +				   struct drm_crtc_state *crtc_state,
> +				   struct drm_connector_state *conn_state)
> +{
> +	return 0;
> +}

Ditto

> +static int starfive_hdmi_connector_get_modes(struct drm_connector *connector)
> +{
> +	struct starfive_hdmi *hdmi = connector_to_hdmi(connector);
> +	struct edid *edid;
> +	int ret = 0;
> +
> +	if (!hdmi->ddc)
> +		return 0;
> +
> +	edid = drm_get_edid(connector, hdmi->ddc);
> +	if (edid) {
> +		hdmi->hdmi_data.sink_is_hdmi = drm_detect_hdmi_monitor(edid);
> +		hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid);
> +		drm_connector_update_edid_property(connector, edid);
> +		ret = drm_add_edid_modes(connector, edid);
> +		kfree(edid);
> +	}
> +
> +	return ret;
> +}

get_modes can be called while the connector is inactive, you need to
call pm_runtime_get_sync / pm_runtime_put here

> +static enum drm_mode_status
> +starfive_hdmi_connector_mode_valid(struct drm_connector *connector,
> +				   struct drm_display_mode *mode)
> +{
> +	const struct pre_pll_config *cfg = pre_pll_cfg_table;
> +	int pclk = mode->clock * 1000;
> +	bool valid = false;
> +	int i;
> +
> +	for (i = 0; cfg[i].pixclock != (~0UL); i++) {
> +		if (pclk == cfg[i].pixclock) {
> +			if (pclk > 297000000)
> +				continue;
> +
> +			valid = true;
> +			break;
> +		}
> +	}
> +
> +	return (valid) ? MODE_OK : MODE_BAD;
> +}

So I guess that's why you don't bother with the scrambler, you filter
all the modes > 297MHz?

If so, you also need to make sure it happens in atomic_check. mode_valid
will only filter the modes exposed to userspace, but the userspace is
free to send any mode it wants and that's checked by atomic_check.

> +
> +static int
> +starfive_hdmi_probe_single_connector_modes(struct drm_connector *connector,
> +					   u32 maxX, u32 maxY)
> +{
> +	struct starfive_hdmi *hdmi = connector_to_hdmi(connector);
> +	int ret;
> +
> +	pm_runtime_get_sync(hdmi->dev);
> +
> +	ret = drm_helper_probe_single_connector_modes(connector, 3840, 2160);
> +
> +	pm_runtime_put(hdmi->dev);
> +
> +	return ret;
> +}

You already have a pm_runtime_get_sync call in get_modes, why is that
necessary?

> +
> +static void starfive_hdmi_connector_destroy(struct drm_connector *connector)
> +{
> +	drm_connector_unregister(connector);
> +	drm_connector_cleanup(connector);
> +}

Use drmm_connector_init.

> +static irqreturn_t starfive_hdmi_irq(int irq, void *dev_id)
> +{
> +	struct starfive_hdmi *hdmi = dev_id;
> +
> +	drm_helper_hpd_irq_event(hdmi->connector.dev);

drm_connector_helper_hpd_irq_event()

> +static int starfive_hdmi_get_clk_rst(struct device *dev, struct starfive_hdmi *hdmi)
> +{
> +	hdmi->sys_clk = devm_clk_get(dev, "sysclk");
> +	if (IS_ERR(hdmi->sys_clk)) {
> +		DRM_DEV_ERROR(dev, "Unable to get HDMI sysclk clk\n");
> +		return PTR_ERR(hdmi->sys_clk);
> +	}
> +	hdmi->mclk = devm_clk_get(dev, "mclk");
> +	if (IS_ERR(hdmi->mclk)) {
> +		DRM_DEV_ERROR(dev, "Unable to get HDMI mclk clk\n");
> +		return PTR_ERR(hdmi->mclk);
> +	}
> +	hdmi->bclk = devm_clk_get(dev, "bclk");
> +	if (IS_ERR(hdmi->bclk)) {
> +		DRM_DEV_ERROR(dev, "Unable to get HDMI bclk clk\n");
> +		return PTR_ERR(hdmi->bclk);
> +	}
> +	hdmi->tx_rst = reset_control_get_shared(dev, "hdmi_tx");
> +	if (IS_ERR(hdmi->tx_rst)) {
> +		DRM_DEV_ERROR(dev, "Unable to get HDMI tx rst\n");
> +		return PTR_ERR(hdmi->tx_rst);
> +	}

That one isn't device-managed, you'll need to put back the reference in
unbind.

> +	return 0;
> +}
> +
> +static int starfive_hdmi_bind(struct device *dev, struct device *master,
> +			      void *data)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct drm_device *drm = data;
> +	struct starfive_hdmi *hdmi;
> +	struct resource *iores;
> +	int irq;
> +	int ret;
> +
> +	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
> +	if (!hdmi)
> +		return -ENOMEM;

Using device-managed actions to allocate memory that will eventually
hold the connectors and encoders is unsafe.

Please use drmm_kzalloc here, and test that it all works fine by
enabling KASAN and removing the module.

> +
> +	hdmi->dev = dev;
> +	hdmi->drm_dev = drm;
> +
> +	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	hdmi->regs = devm_ioremap_resource(dev, iores);
> +	if (IS_ERR(hdmi->regs))
> +		return PTR_ERR(hdmi->regs);

The main issue I was mentioning above is that whenever the device is
unbound from its driver, all the device-managed actions are executed.

However, the KMS device will still be there until the last (userspace)
user closes its FD, so if anything happens between the time the module
is removed and the FD is closed, you get plenty of use-after-free errors.

For MMIO accesses, this is even more true since you need to use a
device-managed action for the registers mapping (this is true for any
resource tied to the device itself, so clocks, reset, etc. fit that
description too).

To protect against it, you need to protect any device access by a call
to drm_dev_enter/drm_dev_exit.

> +
> +	ret = starfive_hdmi_get_clk_rst(dev, hdmi);
> +	ret = starfive_hdmi_enable_clk_deassert_rst(dev, hdmi);

Why does the device need to be powered here?

> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0) {
> +		ret = irq;
> +		goto err_disable_clk;
> +	}
> +
> +	hdmi->ddc = starfive_hdmi_i2c_adapter(hdmi);
> +	if (IS_ERR(hdmi->ddc)) {
> +		ret = PTR_ERR(hdmi->ddc);
> +		hdmi->ddc = NULL;
> +		goto err_disable_clk;
> +	}
> +
> +	hdmi->tmds_rate = clk_get_rate(hdmi->sys_clk);

It's not clear to me what tmds_rate is here, wouldn't that change from
one mode to the next?

> +	starfive_hdmi_i2c_init(hdmi);
> +
> +	ret = starfive_hdmi_register(drm, hdmi);
> +	if (ret)
> +		goto err_put_adapter;
> +
> +	dev_set_drvdata(dev, hdmi);
> +
> +	/* Unmute hotplug interrupt */
> +	hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1));
> +
> +	ret = devm_request_threaded_irq(dev, irq, starfive_hdmi_hardirq,
> +					starfive_hdmi_irq, IRQF_SHARED,
> +					dev_name(dev), hdmi);
> +	if (ret < 0)
> +		goto err_cleanup_hdmi;
> +
> +	pm_runtime_use_autosuspend(&pdev->dev);
> +	pm_runtime_set_autosuspend_delay(&pdev->dev, 500);

Autosuspend? Shouldn't we enable the device as long as there is an
active video output (and you have that covered already)?

> +	pm_runtime_enable(&pdev->dev);
> +
> +	starfive_hdmi_disable_clk_assert_rst(dev, hdmi);

It would be clearer if you would move
starfive_hdmi_enable_clk_deassert_rst()/disable_clk_assert_rst() into
runtime_resume/runtime_suspend, and then in you bind just call
pm_runtime_enable(), pm_runtime_get_sync(), do the registration, and
pm_runtime_put.

> +#define UPDATE(x, h, l)\
> +({\
> +	typeof(x) x_ = (x);\
> +	typeof(h) h_ = (h);\
> +	typeof(l) l_ = (l);\
> +	(((x_) << (l_)) & GENMASK((h_), (l_)));\
> +})

That's FIELD_PREP, right?
Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem
  2023-06-02 18:21   ` Conor Dooley
@ 2023-06-06 18:41     ` Shengyu Qu
  2023-06-06 22:22       ` Heiko Stübner
  0 siblings, 1 reply; 46+ messages in thread
From: Shengyu Qu @ 2023-06-06 18:41 UTC (permalink / raw)
  To: Conor Dooley, Keith Zhao
  Cc: wiagn233, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig, David Airlie, Daniel Vetter,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Emil Renner Berthing, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Heiko Stuebner, Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu,
	Shengyang Chen, Changhuang Liang


[-- Attachment #1.1.1: Type: text/plain, Size: 7105 bytes --]

Hi Conor,

> Hey Keith,
>
> On Fri, Jun 02, 2023 at 03:40:35PM +0800, Keith Zhao wrote:
>> Add bindings for JH7110 display subsystem which
>> has a display controller verisilicon dc8200
>> and an HDMI interface.
>>
>> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
>> ---
>>   .../display/verisilicon/starfive-hdmi.yaml    |  93 +++++++++++++++
>>   .../display/verisilicon/verisilicon-dc.yaml   | 110 ++++++++++++++++++
>>   .../display/verisilicon/verisilicon-drm.yaml  |  42 +++++++
>>   .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
>>   MAINTAINERS                                   |   7 ++
>>   5 files changed, 254 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
>>   create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
>>   create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml b/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
>> new file mode 100644
>> index 000000000000..c30b7954a355
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
>> @@ -0,0 +1,93 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/display/verisilicon/starfive-hdmi.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: StarFive HDMI transmiter
>> +
>> +description:
>> +  The StarFive SoC uses the HDMI signal transmiter based on innosilicon IP
> Is innosilicon the same thing as verisilicon? Also
> s/transmiter/transmitter/, both here and in the title.

I think that is not the same, I remember Rockchip has used a HDMI 
transmitter from

Innosilicon, and there is a existing driver for that in mainline.

So Keith, if that's true, I think it is better to seperate the HDMI 
stuff and reuse existing

driver.

Best regards,

Shengyu

>
>> +  to generate HDMI signal from its input and transmit the signal to the screen.
>> +
>> +maintainers:
>> +  - Keith Zhao <keith.zhao@starfivetech.com>
>> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
>> +
>> +properties:
>> +  compatible:
>> +    const: starfive,hdmi
> Is this going to work on every SoC that StarFive has ever & will ever
> make? Please use soc-based compatibles ;)
>
>> +
>> +  reg:
>> +    minItems: 1
>> +
>> +  interrupts:
>> +    items:
>> +      - description: The HDMI hot plug detection interrupt.
>> +
>> +  clocks:
>> +    items:
>> +      - description: System clock of HDMI module.
>> +      - description: Mclk clock of HDMI audio.
>> +      - description: Bclk clock of HDMI audio.
>> +      - description: Pixel clock generated by HDMI module.
>> +
>> +  clock-names:
>> +    items:
>> +      - const: sysclk
>> +      - const: mclk
>> +      - const: bclk
>> +      - const: pclk
>> +
>> +  resets:
>> +    items:
>> +      - description: Reset for HDMI module.
>> +
>> +  reset-names:
>> +    items:
>> +      - const: hdmi_tx
> You only have one item here, you don't need the "items: - const:",
> "const:" alone will do.
>
>
>> diff --git a/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
>> new file mode 100644
>> index 000000000000..1322502c4cde
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
>> @@ -0,0 +1,110 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-dc.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: StarFive display controller
>> +
>> +description:
>> +  The StarFive SoC uses the display controller based on Verisilicon IP
>> +  to transfer the image data from a video memory
>> +  buffer to an external LCD interface.
> Is it based on Verisilicon IP, or is it exactly that verisilicon IP? I
> ask because...
>
>> +maintainers:
>> +  - Keith Zhao <keith.zhao@starfivetech.com>
>> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
>> +
>> +properties:
>> +  compatible:
>> +    const: verisilicon,dc8200
> ...the compatible is the verisilicon IP. I would be a lot happier if
> the compatibles were set yp for something like:
> "starfive,jh7110-foo", "verisilicon,dc8200"
>
>> diff --git a/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
>> new file mode 100644
>> index 000000000000..aed8d4af2c55
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
>> @@ -0,0 +1,42 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-drm.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Verisilicon DRM master device
>> +
>> +maintainers:
>> +  - Keith Zhao <keith.zhao@starfivetech.com>
>> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
>> +
>> +description: |
>> +  The Verisilicon DRM master device is a virtual device needed to list all
>> +  display controller or other display interface nodes that comprise the
>> +  graphics subsystem.
>> +
>> +properties:
>> +  compatible:
>> +    const: verisilicon,display-subsystem
> Same here.
>
>> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
>> index 82d39ab0231b..52c04fd098be 100644
>> --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
>> +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
>> @@ -1436,6 +1436,8 @@ patternProperties:
>>       description: Variscite Ltd.
>>     "^vdl,.*":
>>       description: Van der Laan b.v.
>> +  "^verisilicon,.*":
>> +    description: Verisilicon Technologies, Inc.
> This should be in it's own patch.
>
> Cheers,
> Conor.
>
>>     "^vertexcom,.*":
>>       description: Vertexcom Technologies, Inc.
>>     "^via,.*":
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 2a0496448b7f..293aa13d484c 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -7049,6 +7049,13 @@ F:	Documentation/devicetree/bindings/display/brcm,bcm2835-*.yaml
>>   F:	drivers/gpu/drm/vc4/
>>   F:	include/uapi/drm/vc4_drm.h
>>   
>> +DRM DRIVERS FOR VERISILICON
>> +M:	Keith Zhao <keith.zhao@starfivetech.com>
>> +L:	dri-devel@lists.freedesktop.org
>> +S:	Maintained
>> +T:	git git://anongit.freedesktop.org/drm/drm-misc
>> +F:	Documentation/devicetree/bindings/display/verisilicon/
>> +
>>   DRM DRIVERS FOR VIVANTE GPU IP
>>   M:	Lucas Stach <l.stach@pengutronix.de>
>>   R:	Russell King <linux+etnaviv@armlinux.org.uk>
>> -- 
>> 2.34.1
>>

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 6977 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem
  2023-06-06 18:41     ` Shengyu Qu
@ 2023-06-06 22:22       ` Heiko Stübner
  2023-06-06 22:37         ` Conor Dooley
  0 siblings, 1 reply; 46+ messages in thread
From: Heiko Stübner @ 2023-06-06 22:22 UTC (permalink / raw)
  To: Conor Dooley, Keith Zhao, Shengyu Qu
  Cc: wiagn233, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig, David Airlie, Daniel Vetter,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Emil Renner Berthing, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Am Dienstag, 6. Juni 2023, 20:41:17 CEST schrieb Shengyu Qu:
> Hi Conor,
> 
> > Hey Keith,
> >
> > On Fri, Jun 02, 2023 at 03:40:35PM +0800, Keith Zhao wrote:
> >> Add bindings for JH7110 display subsystem which
> >> has a display controller verisilicon dc8200
> >> and an HDMI interface.
> >>
> >> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> >> ---
> >>   .../display/verisilicon/starfive-hdmi.yaml    |  93 +++++++++++++++
> >>   .../display/verisilicon/verisilicon-dc.yaml   | 110 ++++++++++++++++++
> >>   .../display/verisilicon/verisilicon-drm.yaml  |  42 +++++++
> >>   .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
> >>   MAINTAINERS                                   |   7 ++
> >>   5 files changed, 254 insertions(+)
> >>   create mode 100644 Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
> >>   create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
> >>   create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
> >>
> >> diff --git a/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml b/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
> >> new file mode 100644
> >> index 000000000000..c30b7954a355
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
> >> @@ -0,0 +1,93 @@
> >> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >> +%YAML 1.2
> >> +---
> >> +$id: http://devicetree.org/schemas/display/verisilicon/starfive-hdmi.yaml#
> >> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >> +
> >> +title: StarFive HDMI transmiter
> >> +
> >> +description:
> >> +  The StarFive SoC uses the HDMI signal transmiter based on innosilicon IP
> > Is innosilicon the same thing as verisilicon? Also
> > s/transmiter/transmitter/, both here and in the title.
> 
> I think that is not the same, I remember Rockchip has used a HDMI 
> transmitter from
> 
> Innosilicon, and there is a existing driver for that in mainline.

Yep, I think Innosilicon is the company you turn to when you want to save
a bit of money ;-) . In the bigger SoCs Rockchip most of the time uses
Designware hdmi blocks and looking at the history only the rk3036 ever
used an Innosilicon block.

Looking at the history, 2016 really was a long time ago :-D.


> So Keith, if that's true, I think it is better to seperate the HDMI 
> stuff and reuse existing driver.

I'm not so sure about that - at least from a cursory glance :-) .

The registers do look slightly different and I don't know how much
the IP changed between the rk3036-version and the jh7110 version.

At the very least, I know my rk3036 board isn't booting right now, so
I can't really provide help for generalizing the rockchip-driver.


At the very least both the binding and driver could drop the "starfive-hdmi"
and actually use the Innosilicon in the naming somewhere, so that it's
clear for future developers :-)


Heiko


> >> +  to generate HDMI signal from its input and transmit the signal to the screen.
> >> +
> >> +maintainers:
> >> +  - Keith Zhao <keith.zhao@starfivetech.com>
> >> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
> >> +
> >> +properties:
> >> +  compatible:
> >> +    const: starfive,hdmi
> > Is this going to work on every SoC that StarFive has ever & will ever
> > make? Please use soc-based compatibles ;)
> >
> >> +
> >> +  reg:
> >> +    minItems: 1
> >> +
> >> +  interrupts:
> >> +    items:
> >> +      - description: The HDMI hot plug detection interrupt.
> >> +
> >> +  clocks:
> >> +    items:
> >> +      - description: System clock of HDMI module.
> >> +      - description: Mclk clock of HDMI audio.
> >> +      - description: Bclk clock of HDMI audio.
> >> +      - description: Pixel clock generated by HDMI module.
> >> +
> >> +  clock-names:
> >> +    items:
> >> +      - const: sysclk
> >> +      - const: mclk
> >> +      - const: bclk
> >> +      - const: pclk
> >> +
> >> +  resets:
> >> +    items:
> >> +      - description: Reset for HDMI module.
> >> +
> >> +  reset-names:
> >> +    items:
> >> +      - const: hdmi_tx
> > You only have one item here, you don't need the "items: - const:",
> > "const:" alone will do.
> >
> >
> >> diff --git a/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
> >> new file mode 100644
> >> index 000000000000..1322502c4cde
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
> >> @@ -0,0 +1,110 @@
> >> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >> +%YAML 1.2
> >> +---
> >> +$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-dc.yaml#
> >> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >> +
> >> +title: StarFive display controller
> >> +
> >> +description:
> >> +  The StarFive SoC uses the display controller based on Verisilicon IP
> >> +  to transfer the image data from a video memory
> >> +  buffer to an external LCD interface.
> > Is it based on Verisilicon IP, or is it exactly that verisilicon IP? I
> > ask because...
> >
> >> +maintainers:
> >> +  - Keith Zhao <keith.zhao@starfivetech.com>
> >> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
> >> +
> >> +properties:
> >> +  compatible:
> >> +    const: verisilicon,dc8200
> > ...the compatible is the verisilicon IP. I would be a lot happier if
> > the compatibles were set yp for something like:
> > "starfive,jh7110-foo", "verisilicon,dc8200"
> >
> >> diff --git a/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
> >> new file mode 100644
> >> index 000000000000..aed8d4af2c55
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
> >> @@ -0,0 +1,42 @@
> >> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >> +%YAML 1.2
> >> +---
> >> +$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-drm.yaml#
> >> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >> +
> >> +title: Verisilicon DRM master device
> >> +
> >> +maintainers:
> >> +  - Keith Zhao <keith.zhao@starfivetech.com>
> >> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
> >> +
> >> +description: |
> >> +  The Verisilicon DRM master device is a virtual device needed to list all
> >> +  display controller or other display interface nodes that comprise the
> >> +  graphics subsystem.
> >> +
> >> +properties:
> >> +  compatible:
> >> +    const: verisilicon,display-subsystem
> > Same here.
> >
> >> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> >> index 82d39ab0231b..52c04fd098be 100644
> >> --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
> >> +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> >> @@ -1436,6 +1436,8 @@ patternProperties:
> >>       description: Variscite Ltd.
> >>     "^vdl,.*":
> >>       description: Van der Laan b.v.
> >> +  "^verisilicon,.*":
> >> +    description: Verisilicon Technologies, Inc.
> > This should be in it's own patch.
> >
> > Cheers,
> > Conor.
> >
> >>     "^vertexcom,.*":
> >>       description: Vertexcom Technologies, Inc.
> >>     "^via,.*":
> >> diff --git a/MAINTAINERS b/MAINTAINERS
> >> index 2a0496448b7f..293aa13d484c 100644
> >> --- a/MAINTAINERS
> >> +++ b/MAINTAINERS
> >> @@ -7049,6 +7049,13 @@ F:	Documentation/devicetree/bindings/display/brcm,bcm2835-*.yaml
> >>   F:	drivers/gpu/drm/vc4/
> >>   F:	include/uapi/drm/vc4_drm.h
> >>   
> >> +DRM DRIVERS FOR VERISILICON
> >> +M:	Keith Zhao <keith.zhao@starfivetech.com>
> >> +L:	dri-devel@lists.freedesktop.org
> >> +S:	Maintained
> >> +T:	git git://anongit.freedesktop.org/drm/drm-misc
> >> +F:	Documentation/devicetree/bindings/display/verisilicon/
> >> +
> >>   DRM DRIVERS FOR VIVANTE GPU IP
> >>   M:	Lucas Stach <l.stach@pengutronix.de>
> >>   R:	Russell King <linux+etnaviv@armlinux.org.uk>
> >> -- 
> >> 2.34.1
> >>
> 





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

* Re: [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem
  2023-06-06 22:22       ` Heiko Stübner
@ 2023-06-06 22:37         ` Conor Dooley
  2023-06-07  6:41           ` Maxime Ripard
  2023-06-07  8:40           ` Heiko Stübner
  0 siblings, 2 replies; 46+ messages in thread
From: Conor Dooley @ 2023-06-06 22:37 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Keith Zhao, Shengyu Qu, dri-devel, devicetree, linux-kernel,
	linux-riscv, linux-media, linaro-mm-sig, David Airlie,
	Daniel Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Emil Renner Berthing, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu, Shengyang Chen,
	Changhuang Liang

[-- Attachment #1: Type: text/plain, Size: 2136 bytes --]

On Wed, Jun 07, 2023 at 12:22:33AM +0200, Heiko Stübner wrote:
> Am Dienstag, 6. Juni 2023, 20:41:17 CEST schrieb Shengyu Qu:
> > > On Fri, Jun 02, 2023 at 03:40:35PM +0800, Keith Zhao wrote:
> > >> Add bindings for JH7110 display subsystem which
> > >> has a display controller verisilicon dc8200
> > >> and an HDMI interface.

> > >> +description:
> > >> +  The StarFive SoC uses the HDMI signal transmiter based on innosilicon IP
> > > Is innosilicon the same thing as verisilicon? Also
> > > s/transmiter/transmitter/, both here and in the title.
> > 
> > I think that is not the same, I remember Rockchip has used a HDMI 
> > transmitter from
> > 
> > Innosilicon, and there is a existing driver for that in mainline.
> 
> Yep, I think Innosilicon is the company you turn to when you want to save
> a bit of money ;-) . In the bigger SoCs Rockchip most of the time uses
> Designware hdmi blocks and looking at the history only the rk3036 ever
> used an Innosilicon block.
> 
> Looking at the history, 2016 really was a long time ago :-D.
> 
> > So Keith, if that's true, I think it is better to seperate the HDMI 
> > stuff and reuse existing driver.
> 
> I'm not so sure about that - at least from a cursory glance :-) .
> 
> The registers do look slightly different and I don't know how much
> the IP changed between the rk3036-version and the jh7110 version.
> 
> At the very least, I know my rk3036 board isn't booting right now, so
> I can't really provide help for generalizing the rockchip-driver.
> 
> At the very least both the binding and driver could drop the "starfive-hdmi"
> and actually use the Innosilicon in the naming somewhere, so that it's
> clear for future developers :-)

Seeing "based on" always makes me a little bit nervous to be honest when
it comes to using a compatible from the IP. Is it the IP? What version
is it? etc. Perhaps "starfive,jh7110-hdmi" & falling back to some sort
of "innosilicon,hdmi" would be more future/IP-silliness proof.
Driver can always be generic & bind against "innosilicon,hdmi" until
that becomes impossible.

Cheers,
Conor.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem
  2023-06-06 22:37         ` Conor Dooley
@ 2023-06-07  6:41           ` Maxime Ripard
  2023-06-07  8:02             ` Keith Zhao
  2023-06-07  8:40           ` Heiko Stübner
  1 sibling, 1 reply; 46+ messages in thread
From: Maxime Ripard @ 2023-06-07  6:41 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Heiko Stübner, Keith Zhao, Shengyu Qu, dri-devel,
	devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig, David Airlie, Daniel Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Emil Renner Berthing,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Maarten Lankhorst,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu,
	Shengyang Chen, Changhuang Liang

[-- Attachment #1: Type: text/plain, Size: 2473 bytes --]

On Tue, Jun 06, 2023 at 11:37:53PM +0100, Conor Dooley wrote:
> On Wed, Jun 07, 2023 at 12:22:33AM +0200, Heiko Stübner wrote:
> > Am Dienstag, 6. Juni 2023, 20:41:17 CEST schrieb Shengyu Qu:
> > > > On Fri, Jun 02, 2023 at 03:40:35PM +0800, Keith Zhao wrote:
> > > >> Add bindings for JH7110 display subsystem which
> > > >> has a display controller verisilicon dc8200
> > > >> and an HDMI interface.
> 
> > > >> +description:
> > > >> +  The StarFive SoC uses the HDMI signal transmiter based on innosilicon IP
> > > > Is innosilicon the same thing as verisilicon? Also
> > > > s/transmiter/transmitter/, both here and in the title.
> > > 
> > > I think that is not the same, I remember Rockchip has used a HDMI 
> > > transmitter from
> > > 
> > > Innosilicon, and there is a existing driver for that in mainline.
> > 
> > Yep, I think Innosilicon is the company you turn to when you want to save
> > a bit of money ;-) . In the bigger SoCs Rockchip most of the time uses
> > Designware hdmi blocks and looking at the history only the rk3036 ever
> > used an Innosilicon block.
> > 
> > Looking at the history, 2016 really was a long time ago :-D.
> > 
> > > So Keith, if that's true, I think it is better to seperate the HDMI 
> > > stuff and reuse existing driver.
> > 
> > I'm not so sure about that - at least from a cursory glance :-) .
> > 
> > The registers do look slightly different and I don't know how much
> > the IP changed between the rk3036-version and the jh7110 version.
> > 
> > At the very least, I know my rk3036 board isn't booting right now, so
> > I can't really provide help for generalizing the rockchip-driver.
> > 
> > At the very least both the binding and driver could drop the "starfive-hdmi"
> > and actually use the Innosilicon in the naming somewhere, so that it's
> > clear for future developers :-)
> 
> Seeing "based on" always makes me a little bit nervous to be honest when
> it comes to using a compatible from the IP. Is it the IP? What version
> is it? etc. Perhaps "starfive,jh7110-hdmi" & falling back to some sort
> of "innosilicon,hdmi" would be more future/IP-silliness proof.
> Driver can always be generic & bind against "innosilicon,hdmi" until
> that becomes impossible.

Given that Neil was saying that there's at least two
generations/revisions/models of an HDMI controller from Innosilicon, I'm
not sure that compatible is enough to reach that goal anyway.

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem
  2023-06-02  7:40 ` [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem Keith Zhao
  2023-06-02 18:21   ` Conor Dooley
@ 2023-06-07  7:35   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 46+ messages in thread
From: Krzysztof Kozlowski @ 2023-06-07  7:35 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Jack Zhu, Shengyang Chen, Changhuang Liang

On 02/06/2023 09:40, Keith Zhao wrote:
> Add bindings for JH7110 display subsystem which
> has a display controller verisilicon dc8200
> and an HDMI interface.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>  .../display/verisilicon/starfive-hdmi.yaml    |  93 +++++++++++++++
>  .../display/verisilicon/verisilicon-dc.yaml   | 110 ++++++++++++++++++
>  .../display/verisilicon/verisilicon-drm.yaml  |  42 +++++++
>  .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
>  MAINTAINERS                                   |   7 ++
>  5 files changed, 254 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml b/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
> new file mode 100644
> index 000000000000..c30b7954a355
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml

Filename matching compatible.

> @@ -0,0 +1,93 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/verisilicon/starfive-hdmi.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: StarFive HDMI transmiter
> +
> +description:
> +  The StarFive SoC uses the HDMI signal transmiter based on innosilicon IP
> +  to generate HDMI signal from its input and transmit the signal to the screen.
> +
> +maintainers:
> +  - Keith Zhao <keith.zhao@starfivetech.com>
> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
> +
> +properties:
> +  compatible:
> +    const: starfive,hdmi

Conor already commented on this.

> +
> +  reg:
> +    minItems: 1
> +
> +  interrupts:
> +    items:
> +      - description: The HDMI hot plug detection interrupt.
> +
> +  clocks:
> +    items:
> +      - description: System clock of HDMI module.
> +      - description: Mclk clock of HDMI audio.
> +      - description: Bclk clock of HDMI audio.
> +      - description: Pixel clock generated by HDMI module.
> +
> +  clock-names:
> +    items:
> +      - const: sysclk
> +      - const: mclk
> +      - const: bclk
> +      - const: pclk
> +
> +  resets:
> +    items:
> +      - description: Reset for HDMI module.
> +
> +  reset-names:
> +    items:
> +      - const: hdmi_tx
> +
> +  '#sound-dai-cells':
> +    const: 0
> +
> +  port:
> +    $ref: /schemas/graph.yaml#/properties/port
> +    description:
> +      Port node with one endpoint connected to a display connector node.

One port, so how do you get data? From where does it come?

> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - clock-names
> +  - resets
> +  - reset-names
> +  - '#sound-dai-cells'
> +  - port
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    hdmi: hdmi@29590000 {
> +      compatible = "starfive,hdmi";
> +      reg = <0x29590000 0x4000>;
> +      interrupts = <99>;
> +      clocks = <&voutcrg 17>,
> +               <&voutcrg 15>,
> +               <&voutcrg 16>,
> +               <&hdmitx0_pixelclk>;
> +      clock-names = "sysclk", "mclk","bclk","pclk";
> +      resets = <&voutcrg 9>;
> +      reset-names = "hdmi_tx";
> +      #sound-dai-cells = <0>;
> +      hdmi_in: port {
> +          #address-cells = <1>;
> +          #size-cells = <0>;
> +          hdmi_input: endpoint@0 {
> +            reg = <0>;
> +            remote-endpoint = <&dc_out_dpi0>;

Mixed up indentation.

> +          };
> +      };
> +    };
> diff --git a/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
> new file mode 100644
> index 000000000000..1322502c4cde
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml

Same problem.

> @@ -0,0 +1,110 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-dc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: StarFive display controller
> +
> +description:
> +  The StarFive SoC uses the display controller based on Verisilicon IP
> +  to transfer the image data from a video memory
> +  buffer to an external LCD interface.
> +
> +maintainers:
> +  - Keith Zhao <keith.zhao@starfivetech.com>
> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
> +
> +properties:
> +  compatible:
> +    const: verisilicon,dc8200
> +
> +  reg:
> +    maxItems: 3
> +
> +  interrupts:
> +    items:
> +      - description: The interrupt will be generated when DC finish one frame
> +
> +  clocks:
> +    items:
> +      - description: Clock for display system noc bus.
> +      - description: Pixel clock for display channel 0.
> +      - description: Pixel clock for display channel 1.
> +      - description: Clock for axi interface of display controller.
> +      - description: Core clock for display controller.
> +      - description: Clock for ahb interface of display controller.
> +      - description: External HDMI pixel clock.
> +      - description: Parent clock for pixel clock
> +
> +  clock-names:
> +    items:
> +      - const: clk_vout_noc_disp

Why do you need "clk_" prefixes? Drop.


> +      - const: clk_vout_pix0
> +      - const: clk_vout_pix1
> +      - const: clk_vout_axi
> +      - const: clk_vout_core
> +      - const: clk_vout_vout_ahb
> +      - const: hdmitx0_pixel
> +      - const: clk_vout_dc8200
> +
> +  resets:
> +    items:
> +      - description: Reset for axi interface of display controller.
> +      - description: Reset for ahb interface of display controller.
> +      - description: Core reset of display controller.
> +
> +  reset-names:
> +    items:
> +      - const: rst_vout_axi

Drop rst_

> +      - const: rst_vout_ahb
> +      - const: rst_vout_core
> +
> +  port:
> +    $ref: /schemas/graph.yaml#/properties/port
> +    description:
> +      Port node with one endpoint connected to a hdmi node.

Oh really? But your HDMI does not allow it! Submit DTS user of all this
so we can see it.

> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - clock-names
> +  - resets
> +  - reset-names
> +  - port
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    dc8200: dc8200@29400000 {

Node names should be generic. See also explanation and list of examples
in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation

> +      compatible = "verisilicon,dc8200";
> +      reg = <0x29400000 0x100>,
> +            <0x29400800 0x2000>,
> +            <0x295B0000 0x90>;

Lowercase hex

> +      interrupts = <95>;
> +      clocks = <&syscrg 60>,
> +               <&voutcrg 7>,
> +               <&voutcrg 8>,
> +               <&voutcrg 4>,
> +               <&voutcrg 5>,
> +               <&voutcrg 6>,
> +               <&hdmitx0_pixelclk>,
> +               <&voutcrg 1>;
> +      clock-names = "clk_vout_noc_disp", "clk_vout_pix0", "clk_vout_pix1", "clk_vout_axi",
> +                    "clk_vout_core", "clk_vout_vout_ahb", "hdmitx0_pixel","clk_vout_dc8200";
> +      resets = <&voutcrg 0>,
> +               <&voutcrg 1>,
> +               <&voutcrg 2>;
> +      reset-names = "rst_vout_axi","rst_vout_ahb","rst_vout_core";
> +      dc_out: port {
> +          #address-cells = <1>;
> +          #size-cells = <0>;
> +          dc_out_dpi0: endpoint@0 {
> +              reg = <0>;
> +              remote-endpoint = <&hdmi_input>;
> +          };
> +      };
> +    };
> diff --git a/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
> new file mode 100644
> index 000000000000..aed8d4af2c55
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml

Same comments

> @@ -0,0 +1,42 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-drm.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Verisilicon DRM master device

What is DRM? If Linux thingy, then it does not suit bindings.

Give it proper description of hardware.

> +
> +maintainers:
> +  - Keith Zhao <keith.zhao@starfivetech.com>
> +  - ShengYang Chen <shengyang.chen@starfivetech.com>
> +
> +description: |

Do not need '|' unless you need to preserve formatting.

> +  The Verisilicon DRM master device is a virtual device needed to list all

We do not describe virtual devices in bindings.

NAK.

> +  display controller or other display interface nodes that comprise the
> +  graphics subsystem.
> +
> +properties:
> +  compatible:
> +    const: verisilicon,display-subsystem
> +
> +  ports:
> +    $ref: /schemas/types.yaml#/definitions/phandle-array

Ports is an object, not array. Drop entire property. It's just wrong.


Best regards,
Krzysztof


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

* Re: [PATCH 2/9] riscv: dts: starfive: jh7110: add dc&hdmi controller node
  2023-06-02  7:40 ` [PATCH 2/9] riscv: dts: starfive: jh7110: add dc&hdmi controller node Keith Zhao
@ 2023-06-07  7:38   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 46+ messages in thread
From: Krzysztof Kozlowski @ 2023-06-07  7:38 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Jack Zhu, Shengyang Chen, Changhuang Liang

On 02/06/2023 09:40, Keith Zhao wrote:
> Add the dc controller and hdmi node for the Starfive JH7110 SoC.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>  .../jh7110-starfive-visionfive-2.dtsi         | 87 +++++++++++++++++++
>  arch/riscv/boot/dts/starfive/jh7110.dtsi      | 46 ++++++++++
>  2 files changed, 133 insertions(+)
> 
> diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
> index 1155b97b593d..8dc6c8a15c59 100644
> --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
> +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
> @@ -31,6 +31,21 @@ memory@40000000 {
>  		reg = <0x0 0x40000000 0x1 0x0>;
>  	};
>  
> +	reserved-memory {
> +		#address-cells = <2>;
> +		#size-cells = <2>;
> +		ranges;
> +
> +		linux,cma {
> +			compatible = "shared-dma-pool";
> +			reusable;
> +			size = <0x0 0x20000000>;
> +			alignment = <0x0 0x1000>;
> +			alloc-ranges = <0x0 0x80000000 0x0 0x20000000>;
> +			linux,cma-default;
> +		};
> +	};
> +
>  	gpio-restart {
>  		compatible = "gpio-restart";
>  		gpios = <&sysgpio 35 GPIO_ACTIVE_HIGH>;
> @@ -214,6 +229,41 @@ GPOEN_DISABLE,
>  			slew-rate = <0>;
>  		};
>  	};
> +
> +	hdmi_pins: hdmi-0 {
> +		hdmi-scl-pins {
> +			pinmux = <GPIOMUX(0, GPOUT_SYS_HDMI_DDC_SCL,
> +					     GPOEN_SYS_HDMI_DDC_SCL,
> +					     GPI_SYS_HDMI_DDC_SCL)>;
> +			input-enable;
> +			bias-pull-up;
> +		};
> +
> +		hdmi-sda-pins {
> +			pinmux = <GPIOMUX(1, GPOUT_SYS_HDMI_DDC_SDA,
> +					     GPOEN_SYS_HDMI_DDC_SDA,
> +					     GPI_SYS_HDMI_DDC_SDA)>;
> +			input-enable;
> +			bias-pull-up;
> +		};
> +
> +		hdmi-cec-pins {
> +			pinmux = <GPIOMUX(14, GPOUT_SYS_HDMI_CEC_SDA,
> +					     GPOEN_SYS_HDMI_CEC_SDA,
> +					     GPI_SYS_HDMI_CEC_SDA)>;
> +			input-enable;
> +			bias-pull-up;
> +		};
> +
> +		hdmi-hpd-pins {
> +			pinmux = <GPIOMUX(15, GPOUT_HIGH,
> +					     GPOEN_ENABLE,
> +					     GPI_SYS_HDMI_HPD)>;
> +			input-enable;
> +			bias-disable; /* external pull-up */
> +		};
> +	};
> +
>  };
>  
>  &uart0 {
> @@ -221,3 +271,40 @@ &uart0 {
>  	pinctrl-0 = <&uart0_pins>;
>  	status = "okay";
>  };
> +
> +&voutcrg {
> +	status = "okay";
> +};
> +
> +&display {
> +	status = "okay";
> +};
> +
> +&hdmi {
> +	status = "okay";
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&hdmi_pins>;
> +
> +	hdmi_in: port {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		hdmi_input: endpoint@0 {
> +			reg = <0>;
> +			remote-endpoint = <&dc_out_dpi0>;

This does not make any sense. You wrote in bindings that this is display
output, but you call it HDMI input. If this is input, where is your output?

> +		};
> +	};
> +};
> +
> +&dc8200 {
> +	status = "okay";
> +
> +	dc_out: port {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		dc_out_dpi0: endpoint@0 {
> +			reg = <0>;
> +			remote-endpoint = <&hdmi_input>;
> +		};
> +

Stray blank line.

> +	};
> +};
> diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
> index 9acb5fb1716d..66be6e65a066 100644
> --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
> +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
> @@ -249,6 +249,11 @@ tdm_ext: tdm-ext-clock {
>  		#clock-cells = <0>;
>  	};
>  
> +	display: display-subsystem {
> +		compatible = "verisilicon,display-subsystem";

Drop fake nodes which do not represent hardware. Instead, DTS and
bindings should describe real hardware.


> +		ports = <&dc_out>;
> +	};
> +
>  	soc {
>  		compatible = "simple-bus";
>  		interrupt-parent = <&plic>;
> @@ -570,5 +575,46 @@ voutcrg: clock-controller@295c0000 {
>  			#reset-cells = <1>;
>  			power-domains = <&pwrc JH7110_PD_VOUT>;
>  		};
> +
> +		dc8200: dc8200@29400000 {

Node names should be generic. See also explanation and list of examples
in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation

> +			compatible = "verisilicon,dc8200";
> +			reg = <0x0 0x29400000 0x0 0x100>,
> +			      <0x0 0x29400800 0x0 0x2000>,
> +			      <0x0 0x295B0000 0x0 0x90>;
> +			interrupts = <95>;
> +			clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_DISP_AXI>,
> +				<&voutcrg JH7110_VOUTCLK_DC8200_PIX0>,
> +				<&voutcrg JH7110_VOUTCLK_DC8200_PIX1>,
> +				<&voutcrg JH7110_VOUTCLK_DC8200_AXI>,
> +				<&voutcrg JH7110_VOUTCLK_DC8200_CORE>,
> +				<&voutcrg JH7110_VOUTCLK_DC8200_AHB>,
> +				<&hdmitx0_pixelclk>,
> +				<&voutcrg JH7110_VOUTCLK_DC8200_PIX>;
> +			clock-names = "clk_vout_noc_disp",
> +				"clk_vout_pix0","clk_vout_pix1",

Fix alignment

> +				"clk_vout_axi","clk_vout_core",
> +				"clk_vout_vout_ahb","hdmitx0_pixel",
> +				"clk_vout_dc8200";
> +			resets = <&voutcrg JH7110_VOUTRST_DC8200_AXI>,
> +				 <&voutcrg JH7110_VOUTRST_DC8200_AHB>,
> +				 <&voutcrg JH7110_VOUTRST_DC8200_CORE>;
> +			reset-names = "rst_vout_axi","rst_vout_ahb",
> +						"rst_vout_core";

Fix alignment.



Best regards,
Krzysztof


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

* Re: [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem
  2023-06-07  6:41           ` Maxime Ripard
@ 2023-06-07  8:02             ` Keith Zhao
  0 siblings, 0 replies; 46+ messages in thread
From: Keith Zhao @ 2023-06-07  8:02 UTC (permalink / raw)




On 2023/6/7 14:41, Maxime Ripard wrote:
> On Tue, Jun 06, 2023 at 11:37:53PM +0100, Conor Dooley wrote:
>> On Wed, Jun 07, 2023 at 12:22:33AM +0200, Heiko Stübner wrote:
>> > Am Dienstag, 6. Juni 2023, 20:41:17 CEST schrieb Shengyu Qu:
>> > > > On Fri, Jun 02, 2023 at 03:40:35PM +0800, Keith Zhao wrote:
>> > > >> Add bindings for JH7110 display subsystem which
>> > > >> has a display controller verisilicon dc8200
>> > > >> and an HDMI interface.
>> 
>> > > >> +description:
>> > > >> +  The StarFive SoC uses the HDMI signal transmiter based on innosilicon IP
>> > > > Is innosilicon the same thing as verisilicon? Also
>> > > > s/transmiter/transmitter/, both here and in the title.
yes,innosilicon is the HDMI IP  and verisilicon is the DC-controller IP

>> > > 
>> > > I think that is not the same, I remember Rockchip has used a HDMI 
>> > > transmitter from
>> > > 
>> > > Innosilicon, and there is a existing driver for that in mainline.
>> > 
>> > Yep, I think Innosilicon is the company you turn to when you want to save
>> > a bit of money ;-) . In the bigger SoCs Rockchip most of the time uses
>> > Designware hdmi blocks and looking at the history only the rk3036 ever
>> > used an Innosilicon block.
>> > 
I have done a HDMIcomparison of the rk3036 and the jh7110, and they are both based on ip Innosilicon.

the hardware of them .
Some parts of the hardware of the two are common, such as the logic of hdmi I2C to obtain edid, and the register definition is consistent.

Many registers are defined differently from the linux main line inno driver, including registers that contain specific bits
and some registers in linux main line inno driver no longer used in my new inoo hdmi hardware.

>> > Looking at the history, 2016 really was a long time ago :-D.
>> > 
>> > > So Keith, if that's true, I think it is better to seperate the HDMI 
>> > > stuff and reuse existing driver.
>> > 
>> > I'm not so sure about that - at least from a cursory glance :-) .
>> > 
>> > The registers do look slightly different and I don't know how much
>> > the IP changed between the rk3036-version and the jh7110 version.
>> > 
>> > At the very least, I know my rk3036 board isn't booting right now, so
>> > I can't really provide help for generalizing the rockchip-driver.
>> > 
>> > At the very least both the binding and driver could drop the "starfive-hdmi"
>> > and actually use the Innosilicon in the naming somewhere, so that it's
>> > clear for future developers :-)
>> 
>> Seeing "based on" always makes me a little bit nervous to be honest when
>> it comes to using a compatible from the IP. Is it the IP? What version
>> is it? etc. Perhaps "starfive,jh7110-hdmi" & falling back to some sort
>> of "innosilicon,hdmi" would be more future/IP-silliness proof.
>> Driver can always be generic & bind against "innosilicon,hdmi" until
>> that becomes impossible.
> 
> Given that Neil was saying that there's at least two
> generations/revisions/models of an HDMI controller from Innosilicon, I'm
> not sure that compatible is enough to reach that goal anyway.
> 
> Maxime



I will change the  the binding  to meet innosilicon,hdmi .
for the drivers part , I will study the possibility of RK-HDMI reuse.

Thank you for your comments
















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

* Re: [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem
  2023-06-06 22:37         ` Conor Dooley
  2023-06-07  6:41           ` Maxime Ripard
@ 2023-06-07  8:40           ` Heiko Stübner
  1 sibling, 0 replies; 46+ messages in thread
From: Heiko Stübner @ 2023-06-07  8:40 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Keith Zhao, Shengyu Qu, dri-devel, devicetree, linux-kernel,
	linux-riscv, linux-media, linaro-mm-sig, David Airlie,
	Daniel Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Emil Renner Berthing, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Am Mittwoch, 7. Juni 2023, 00:37:53 CEST schrieb Conor Dooley:
> On Wed, Jun 07, 2023 at 12:22:33AM +0200, Heiko Stübner wrote:
> > Am Dienstag, 6. Juni 2023, 20:41:17 CEST schrieb Shengyu Qu:
> > > > On Fri, Jun 02, 2023 at 03:40:35PM +0800, Keith Zhao wrote:
> > > >> Add bindings for JH7110 display subsystem which
> > > >> has a display controller verisilicon dc8200
> > > >> and an HDMI interface.
> 
> > > >> +description:
> > > >> +  The StarFive SoC uses the HDMI signal transmiter based on innosilicon IP
> > > > Is innosilicon the same thing as verisilicon? Also
> > > > s/transmiter/transmitter/, both here and in the title.
> > > 
> > > I think that is not the same, I remember Rockchip has used a HDMI 
> > > transmitter from
> > > 
> > > Innosilicon, and there is a existing driver for that in mainline.
> > 
> > Yep, I think Innosilicon is the company you turn to when you want to save
> > a bit of money ;-) . In the bigger SoCs Rockchip most of the time uses
> > Designware hdmi blocks and looking at the history only the rk3036 ever
> > used an Innosilicon block.
> > 
> > Looking at the history, 2016 really was a long time ago :-D.
> > 
> > > So Keith, if that's true, I think it is better to seperate the HDMI 
> > > stuff and reuse existing driver.
> > 
> > I'm not so sure about that - at least from a cursory glance :-) .
> > 
> > The registers do look slightly different and I don't know how much
> > the IP changed between the rk3036-version and the jh7110 version.
> > 
> > At the very least, I know my rk3036 board isn't booting right now, so
> > I can't really provide help for generalizing the rockchip-driver.
> > 
> > At the very least both the binding and driver could drop the "starfive-hdmi"
> > and actually use the Innosilicon in the naming somewhere, so that it's
> > clear for future developers :-)
> 
> Seeing "based on" always makes me a little bit nervous to be honest when
> it comes to using a compatible from the IP. Is it the IP? What version
> is it? etc. Perhaps "starfive,jh7110-hdmi" & falling back to some sort
> of "innosilicon,hdmi" would be more future/IP-silliness proof.
> Driver can always be generic & bind against "innosilicon,hdmi" until
> that becomes impossible.


what Connor said makes a lot of sense. Just name the compatible
after the actual implementation - aka "starfive,jh7110-hdmi" .

This is similar to what the rk3036 does with its
"rockchip,rk3036-inno-hdmi". That way you're nicely independent
and future proof.


Heiko



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

* Re: [PATCH 3/9] drm/verisilicon: Add basic drm driver
  2023-06-02  7:40 ` [PATCH 3/9] drm/verisilicon: Add basic drm driver Keith Zhao
@ 2023-06-07  8:53   ` Lucas Stach
  2023-07-25  3:12     ` Keith Zhao
  2023-06-19 12:59   ` Thomas Zimmermann
  2023-07-03 18:42   ` Shengyu Qu
  2 siblings, 1 reply; 46+ messages in thread
From: Lucas Stach @ 2023-06-07  8:53 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: Krzysztof Kozlowski, Sumit Semwal, Emil Renner Berthing,
	Shengyang Chen, Conor Dooley, Albert Ou, Thomas Zimmermann,
	Jagan Teki, Rob Herring, Chris Morgan, Paul Walmsley,
	Bjorn Andersson, Changhuang Liang, Jack Zhu, Palmer Dabbelt,
	Shawn Guo, christian.koenig

Hi Keith,

Am Freitag, dem 02.06.2023 um 15:40 +0800 schrieb Keith Zhao:
> Add a basic platform driver of the DRM driver for JH7110 SoC.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>  MAINTAINERS                          |   2 +
>  drivers/gpu/drm/Kconfig              |   2 +
>  drivers/gpu/drm/Makefile             |   1 +
>  drivers/gpu/drm/verisilicon/Kconfig  |  13 ++
>  drivers/gpu/drm/verisilicon/Makefile |   6 +
>  drivers/gpu/drm/verisilicon/vs_drv.c | 284 +++++++++++++++++++++++++++
>  drivers/gpu/drm/verisilicon/vs_drv.h |  48 +++++
>  include/uapi/drm/drm_fourcc.h        |  83 ++++++++
>  include/uapi/drm/vs_drm.h            |  50 +++++
>  9 files changed, 489 insertions(+)
>  create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
>  create mode 100644 drivers/gpu/drm/verisilicon/Makefile
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
>  create mode 100644 include/uapi/drm/vs_drm.h
> 
> 
> [...]
> +#endif /* __VS_DRV_H__ */
> diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
> index de703c6be969..af4fb50f9207 100644
> --- a/include/uapi/drm/drm_fourcc.h
> +++ b/include/uapi/drm/drm_fourcc.h
> @@ -419,6 +419,7 @@ extern "C" {
>  #define DRM_FORMAT_MOD_VENDOR_ARM     0x08
>  #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09
>  #define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a
> +#define DRM_FORMAT_MOD_VENDOR_VS      0x0b
>  
>  /* add more to the end as needed */
>  
> @@ -1519,6 +1520,88 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
>  #define AMD_FMT_MOD_CLEAR(field) \
>  	(~((__u64)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT))
>  
> +#define DRM_FORMAT_MOD_VS_TYPE_NORMAL        0x00
> +#define DRM_FORMAT_MOD_VS_TYPE_COMPRESSED    0x01
> +#define DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT  0x02
> +#define DRM_FORMAT_MOD_VS_TYPE_MASK     ((__u64)0x3 << 54)
> +
> +#define fourcc_mod_vs_code(type, val) \
> +	fourcc_mod_code(VS, ((((__u64)type) << 54) | (val)))
> +
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_MODE_MASK    0x3F
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_XMAJOR   0x00
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_YMAJOR   0x01
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4     0x02
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4      0x03
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_4X8      0x04
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X4   0x06
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X4     0x07
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4     0x08
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X1  0x09
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X1  0x0A
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X4   0x0B
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X2  0x0C
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X2  0x0D
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X4  0x0E
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X1   0x0F
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X8     0x10
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X16     0x11
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_512X1  0x12
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X4   0x13
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X2   0x14
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X2   0x15
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X1   0x16
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X1   0x17
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X4    0x18
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_256X4    0x19
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_512X4    0x1A
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X16    0x1B
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X16    0x1C
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X16    0x1D
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X8    0x1E
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4_S    0x1F
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_S   0x20
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_S   0x21
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_LSB 0x22
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_LSB 0x23
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X8     0x24
> +
> +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_32      (0x01 << 6)
> +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_64      (0x01 << 7)
> +
> +#define fourcc_mod_vs_dec_code(tile, align) \
> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_COMPRESSED, \
> +				((tile) | (align)))
> +
> +#define DRM_FORMAT_MOD_VS_NORM_MODE_MASK        0x1F
> +#define DRM_FORMAT_MOD_VS_LINEAR                0x00
> +#define DRM_FORMAT_MOD_VS_TILED4x4              0x01
> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR    0x02
> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR    0x03
> +#define DRM_FORMAT_MOD_VS_TILE_8X8              0x04
> +#define DRM_FORMAT_MOD_VS_TILE_MODE1            0x05
> +#define DRM_FORMAT_MOD_VS_TILE_MODE2            0x06
> +#define DRM_FORMAT_MOD_VS_TILE_8X4              0x07
> +#define DRM_FORMAT_MOD_VS_TILE_MODE4            0x08
> +#define DRM_FORMAT_MOD_VS_TILE_MODE5            0x09
> +#define DRM_FORMAT_MOD_VS_TILE_MODE6            0x0A
> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4    0x0B
> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8    0x0C
> +#define DRM_FORMAT_MOD_VS_TILE_Y                0x0D
> +#define DRM_FORMAT_MOD_VS_TILE_128X1            0x0F
> +#define DRM_FORMAT_MOD_VS_TILE_256X1            0x10
> +#define DRM_FORMAT_MOD_VS_TILE_32X1             0x11
> +#define DRM_FORMAT_MOD_VS_TILE_64X1             0x12
> +#define DRM_FORMAT_MOD_VS_TILE_MODE4X4          0x15
> +
> +#define fourcc_mod_vs_norm_code(tile) \
> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_NORMAL, \
> +				(tile))
> +
> +#define fourcc_mod_vs_custom_code(tile) \
> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT, \
> +				(tile))
> +

You are opening a new namespace for what is effectively the VIVANTE
tiling. While your list seems much more exhaustive than the (reverse
engineered) list provided under the VIVANTE namespace, this is still
unacceptable as it adds new aliases for existing modifiers.

Also any modifier additions should be in a separate patch and not
buried in another change.

Regards,
Lucas

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

* Re: [PATCH 3/9] drm/verisilicon: Add basic drm driver
  2023-06-02  7:40 ` [PATCH 3/9] drm/verisilicon: Add basic drm driver Keith Zhao
  2023-06-07  8:53   ` Lucas Stach
@ 2023-06-19 12:59   ` Thomas Zimmermann
  2023-07-07 18:09     ` Nicolas Dufresne
  2023-07-03 18:42   ` Shengyu Qu
  2 siblings, 1 reply; 46+ messages in thread
From: Thomas Zimmermann @ 2023-06-19 12:59 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: Krzysztof Kozlowski, Sumit Semwal, Emil Renner Berthing,
	Shengyang Chen, Conor Dooley, Albert Ou, Jagan Teki, Rob Herring,
	Chris Morgan, Paul Walmsley, Bjorn Andersson, Changhuang Liang,
	Jack Zhu, Palmer Dabbelt, Shawn Guo, christian.koenig


[-- Attachment #1.1: Type: text/plain, Size: 20044 bytes --]

Hi,

I appreciate that you split the driver into small patches. Please find 
some comments below.

Am 02.06.23 um 09:40 schrieb Keith Zhao:
> Add a basic platform driver of the DRM driver for JH7110 SoC.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>   MAINTAINERS                          |   2 +
>   drivers/gpu/drm/Kconfig              |   2 +
>   drivers/gpu/drm/Makefile             |   1 +
>   drivers/gpu/drm/verisilicon/Kconfig  |  13 ++
>   drivers/gpu/drm/verisilicon/Makefile |   6 +
>   drivers/gpu/drm/verisilicon/vs_drv.c | 284 +++++++++++++++++++++++++++
>   drivers/gpu/drm/verisilicon/vs_drv.h |  48 +++++
>   include/uapi/drm/drm_fourcc.h        |  83 ++++++++
>   include/uapi/drm/vs_drm.h            |  50 +++++
>   9 files changed, 489 insertions(+)
>   create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
>   create mode 100644 drivers/gpu/drm/verisilicon/Makefile
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
>   create mode 100644 include/uapi/drm/vs_drm.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 293aa13d484c..da5b6766a7bb 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7055,6 +7055,8 @@ L:	dri-devel@lists.freedesktop.org
>   S:	Maintained
>   T:	git git://anongit.freedesktop.org/drm/drm-misc
>   F:	Documentation/devicetree/bindings/display/verisilicon/
> +F:	drivers/gpu/drm/verisilicon/
> +F:	include/uapi/drm/vs_drm.h
>   
>   DRM DRIVERS FOR VIVANTE GPU IP
>   M:	Lucas Stach <l.stach@pengutronix.de>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index ba3fb04bb691..f7e461fa4656 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -371,6 +371,8 @@ source "drivers/gpu/drm/solomon/Kconfig"
>   
>   source "drivers/gpu/drm/sprd/Kconfig"
>   
> +source "drivers/gpu/drm/verisilicon/Kconfig"
> +
>   config DRM_HYPERV
>   	tristate "DRM Support for Hyper-V synthetic video device"
>   	depends on DRM && PCI && MMU && HYPERV
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index a33257d2bc7f..e50622ee4e46 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -194,3 +194,4 @@ obj-y			+= gud/
>   obj-$(CONFIG_DRM_HYPERV) += hyperv/
>   obj-y			+= solomon/
>   obj-$(CONFIG_DRM_SPRD) += sprd/
> +obj-$(CONFIG_DRM_VERISILICON) += verisilicon/
> diff --git a/drivers/gpu/drm/verisilicon/Kconfig b/drivers/gpu/drm/verisilicon/Kconfig
> new file mode 100644
> index 000000000000..89d12185f73b
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/Kconfig
> @@ -0,0 +1,13 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +config DRM_VERISILICON
> +	tristate "DRM Support for VeriSilicon"

Can you rename the driver and files? 'VeriSilicon' seems 
unpronounceable. Simply 'StarFive' and starfive/ would be fine.

> +	depends on DRM
> +	select DRM_KMS_HELPER
> +	select CMA
> +	select DMA_CMA
> +	help
> +	  Choose this option if you have a VeriSilicon soc chipset.
> +	  This driver provides VeriSilicon kernel mode
> +	  setting and buffer management. It does not
> +	  provide 2D or 3D acceleration.
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> new file mode 100644
> index 000000000000..64ce1b26546c
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +vs_drm-objs := vs_drv.o
> +
> +obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
> +
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
> new file mode 100644
> index 000000000000..24d333598477
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> @@ -0,0 +1,284 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/delay.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/iommu.h>
> +#include <linux/of_graph.h>
> +#include <linux/of_reserved_mem.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/reset.h>
> +#include <linux/version.h>
> +
> +#include <drm/drm_aperture.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_debugfs.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_fbdev_generic.h>
> +#include <drm/drm_file.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_ioctl.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_prime.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/drm_vblank.h>
> +
> +#include "vs_drv.h"
> +
> +#define DRV_NAME	"starfive"
> +#define DRV_DESC	"Starfive DRM driver"
> +#define DRV_DATE	"202305161"
> +#define DRV_MAJOR	1
> +#define DRV_MINOR	0
> +
> +static struct platform_driver vs_drm_platform_driver;
> +
> +static const struct file_operations fops = {
> +	.owner			= THIS_MODULE,
> +	.open			= drm_open,
> +	.release		= drm_release,
> +	.unlocked_ioctl	= drm_ioctl,
> +	.compat_ioctl	= drm_compat_ioctl,
> +	.poll			= drm_poll,
> +	.read			= drm_read,
> +};
> +
> +static struct drm_driver vs_drm_driver = {
> +	.driver_features	= DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
> +	.lastclose		= drm_fb_helper_lastclose,
> +	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> +	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> +	.fops			= &fops,
> +	.name			= DRV_NAME,
> +	.desc			= DRV_DESC,
> +	.date			= DRV_DATE,
> +	.major			= DRV_MAJOR,
> +	.minor			= DRV_MINOR,
> +};
> +
> +void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
> +				   unsigned int alignment)
> +{
> +	struct vs_drm_private *priv = drm_dev->dev_private;
> +
> +	if (alignment > priv->pitch_alignment)
> +		priv->pitch_alignment = alignment;
> +}
> +
> +static int vs_drm_bind(struct device *dev)
> +{
> +	struct drm_device *drm_dev;
> +	struct vs_drm_private *priv;
> +	int ret;
> +	static u64 dma_mask = DMA_BIT_MASK(40);
> +
> +	/* Remove existing drivers that may own the framebuffer memory. */
> +	ret = drm_aperture_remove_framebuffers(false, &vs_drm_driver);
> +	if (ret) {
> +		DRM_DEV_ERROR(dev,

drm_err(), drm_info(), drm_warn(), etc.  Here and everwhere else. The 
DRM_DEV_*() print macros are obsolete.

> +			      "Failed to remove existing framebuffers - %d.\n",
> +			      ret);
> +		return ret;
> +	}
> +
> +	drm_dev = drm_dev_alloc(&vs_drm_driver, dev);
> +	if (IS_ERR(drm_dev))
> +		return PTR_ERR(drm_dev);
> +
> +	dev_set_drvdata(dev, drm_dev);
> +
> +	priv = devm_kzalloc(drm_dev->dev, sizeof(struct vs_drm_private),
> +			    GFP_KERNEL);
> +	if (!priv) {
> +		ret = -ENOMEM;
> +		goto err_put_dev;
> +	}
> +
> +	priv->pitch_alignment = 64;
> +	priv->dma_dev = drm_dev->dev;
> +	priv->dma_dev->coherent_dma_mask = dma_mask;
> +	drm_dev->dev_private = priv;

dev_private is obsolete and about to go away at some point.

Please embed drm_device in vs_drm_private and allocate the memory with 
devm_drm_dev_alloc().

> +
> +	drm_mode_config_init(drm_dev);

drmm_mode_config_init() please.

> +
> +	/* Now try and bind all our sub-components */
> +	ret = component_bind_all(dev, drm_dev);
> +	if (ret)
> +		goto err_mode;
> +
> +	ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
> +	if (ret)
> +		goto err_bind;
> +
> +	drm_mode_config_reset(drm_dev);
> +
> +	drm_kms_helper_poll_init(drm_dev);
> +
> +	ret = drm_dev_register(drm_dev, 0);
> +	if (ret)
> +		goto err_helper;
> +
> +	drm_fbdev_generic_setup(drm_dev, 32);
> +
> +	return 0;
> +
> +err_helper:
> +	drm_kms_helper_poll_fini(drm_dev);
> +err_bind:
> +	component_unbind_all(drm_dev->dev, drm_dev);
> +err_mode:
> +	drm_mode_config_cleanup(drm_dev);
> +	if (priv->domain)
> +		iommu_domain_free(priv->domain);
> +err_put_dev:
> +	drm_dev->dev_private = NULL;
> +	dev_set_drvdata(dev, NULL);
> +	drm_dev_put(drm_dev);
> +	return ret;
> +}
> +
> +static void vs_drm_unbind(struct device *dev)
> +{
> +	struct drm_device *drm_dev = dev_get_drvdata(dev);
> +	struct vs_drm_private *priv = drm_dev->dev_private;
> +
> +	drm_dev_unregister(drm_dev);
> +
> +	drm_kms_helper_poll_fini(drm_dev);
> +
> +	component_unbind_all(drm_dev->dev, drm_dev);
> +
> +	drm_mode_config_cleanup(drm_dev);
> +
> +	if (priv->domain) {
> +		iommu_domain_free(priv->domain);
> +		priv->domain = NULL;
> +	}
> +
> +	drm_dev->dev_private = NULL;
> +	dev_set_drvdata(dev, NULL);
> +	drm_dev_put(drm_dev);

You rather want to convert the individual steps of this cleanup to 
managed functions (drmm_ and devm_) to automate the cleanup when as part 
of drm_dev_put().

> +}
> +
> +static const struct component_master_ops vs_drm_ops = {
> +	.bind = vs_drm_bind,
> +	.unbind = vs_drm_unbind,
> +};
> +
> +static struct platform_driver *drm_sub_drivers[] = {
> +};
> +
> +#define NUM_DRM_DRIVERS \
> +	(sizeof(drm_sub_drivers) / sizeof(struct platform_driver *))

Does this really work? sizeof(drm_sub_drivers) isn't know at compile 
time. It is always assumed to be 0 AFAICT. Or do you fill this array in 
later patches?


> +
> +static int compare_dev(struct device *dev, void *data)
> +{
> +	return dev == (struct device *)data;
> +}
> +
> +static struct component_match *vs_drm_match_add(struct device *dev)
> +{
> +	struct component_match *match = NULL;
> +	int i;
> +
> +	for (i = 0; i < NUM_DRM_DRIVERS; ++i) {
> +		struct platform_driver *drv = drm_sub_drivers[i];
> +		struct device *p = NULL, *d;
> +
> +		while ((d = platform_find_device_by_driver(p, &drv->driver))) {
> +			put_device(p);
> +
> +			component_match_add(dev, &match, compare_dev, d);
> +			p = d;
> +		}
> +		put_device(p);
> +	}
> +
> +	return match ?: ERR_PTR(-ENODEV);
> +}
> +
> +static int vs_drm_platform_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct component_match *match;
> +
> +	match = vs_drm_match_add(dev);
> +	if (IS_ERR(match))
> +		return PTR_ERR(match);
> +
> +	return component_master_add_with_match(dev, &vs_drm_ops, match);
> +}
> +
> +static int vs_drm_platform_remove(struct platform_device *pdev)
> +{
> +	component_master_del(&pdev->dev, &vs_drm_ops);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int vs_drm_suspend(struct device *dev)
> +{
> +	struct drm_device *drm = dev_get_drvdata(dev);
> +
> +	return drm_mode_config_helper_suspend(drm);
> +}
> +
> +static int vs_drm_resume(struct device *dev)
> +{
> +	struct drm_device *drm = dev_get_drvdata(dev);
> +
> +	return drm_mode_config_helper_resume(drm);
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(vs_drm_pm_ops, vs_drm_suspend, vs_drm_resume);
> +
> +static const struct of_device_id vs_drm_dt_ids[] = {
> +	{ .compatible = "verisilicon,display-subsystem", },
> +};
> +
> +MODULE_DEVICE_TABLE(of, vs_drm_dt_ids);
> +
> +static struct platform_driver vs_drm_platform_driver = {
> +	.probe = vs_drm_platform_probe,
> +	.remove = vs_drm_platform_remove,
> +
> +	.driver = {
> +		.name = DRV_NAME,
> +		.of_match_table = vs_drm_dt_ids,
> +		.pm = &vs_drm_pm_ops,
> +	},
> +};
> +
> +static int __init vs_drm_init(void)
> +{
> +	int ret;
> +
> +	ret = platform_register_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
> +	if (ret)
> +		return ret;
> +
> +	ret = platform_driver_register(&vs_drm_platform_driver);
> +	if (ret)
> +		platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
> +
> +	return ret;
> +}
> +
> +static void __exit vs_drm_fini(void)
> +{
> +	platform_driver_unregister(&vs_drm_platform_driver);
> +	platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
> +}
> +
> +module_init(vs_drm_init);
> +module_exit(vs_drm_fini);
> +
> +MODULE_DESCRIPTION("VeriSilicon DRM Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
> new file mode 100644
> index 000000000000..0382b44e3bf0
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.h
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_DRV_H__
> +#define __VS_DRV_H__
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/version.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_gem.h>
> +
> +/*
> + *
> + * @dma_dev: device for DMA API.
> + *	- use the first attached device if support iommu
> +	else use drm device (only contiguous buffer support)
> + * @domain: iommu domain for DRM.
> + *	- all DC IOMMU share same domain to reduce mapping
> + * @pitch_alignment: buffer pitch alignment required by sub-devices.
> + *
> + */
> +struct vs_drm_private {
> +	struct device *dma_dev;
> +	struct iommu_domain *domain;
> +	unsigned int pitch_alignment;
> +};

As mentioned, this struct needs to embed struct drm_device.

> +
> +void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
> +				   unsigned int alignment);
> +
> +static inline struct device *to_dma_dev(struct drm_device *dev)
> +{
> +	struct vs_drm_private *priv = dev->dev_private;
> +
> +	return priv->dma_dev;

And this needs to be an upcast via container_of().

> +}
> +
> +static inline bool is_iommu_enabled(struct drm_device *dev)
> +{
> +	struct vs_drm_private *priv = dev->dev_private;
> +
> +	return priv->domain ? true : false;
> +}
> +
> +#endif /* __VS_DRV_H__ */
> diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
> index de703c6be969..af4fb50f9207 100644
> --- a/include/uapi/drm/drm_fourcc.h
> +++ b/include/uapi/drm/drm_fourcc.h

The UAPI changes shouldn't be needed in this patch?

> @@ -419,6 +419,7 @@ extern "C" {
>   #define DRM_FORMAT_MOD_VENDOR_ARM     0x08
>   #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09
>   #define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a
> +#define DRM_FORMAT_MOD_VENDOR_VS      0x0b
>   
>   /* add more to the end as needed */
>   
> @@ -1519,6 +1520,88 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
>   #define AMD_FMT_MOD_CLEAR(field) \
>   	(~((__u64)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT))
>   
> +#define DRM_FORMAT_MOD_VS_TYPE_NORMAL        0x00
> +#define DRM_FORMAT_MOD_VS_TYPE_COMPRESSED    0x01
> +#define DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT  0x02
> +#define DRM_FORMAT_MOD_VS_TYPE_MASK     ((__u64)0x3 << 54)
> +
> +#define fourcc_mod_vs_code(type, val) \
> +	fourcc_mod_code(VS, ((((__u64)type) << 54) | (val)))
> +
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_MODE_MASK    0x3F
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_XMAJOR   0x00
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_YMAJOR   0x01
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4     0x02
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4      0x03
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_4X8      0x04
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X4   0x06
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X4     0x07
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4     0x08
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X1  0x09
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X1  0x0A
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X4   0x0B
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X2  0x0C
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X2  0x0D
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X4  0x0E
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X1   0x0F
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X8     0x10
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X16     0x11
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_512X1  0x12
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X4   0x13
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X2   0x14
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X2   0x15
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X1   0x16
> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X1   0x17
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X4    0x18
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_256X4    0x19
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_512X4    0x1A
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X16    0x1B
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X16    0x1C
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X16    0x1D
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X8    0x1E
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4_S    0x1F
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_S   0x20
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_S   0x21
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_LSB 0x22
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_LSB 0x23
> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X8     0x24
> +
> +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_32      (0x01 << 6)
> +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_64      (0x01 << 7)
> +
> +#define fourcc_mod_vs_dec_code(tile, align) \
> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_COMPRESSED, \
> +				((tile) | (align)))
> +
> +#define DRM_FORMAT_MOD_VS_NORM_MODE_MASK        0x1F
> +#define DRM_FORMAT_MOD_VS_LINEAR                0x00
> +#define DRM_FORMAT_MOD_VS_TILED4x4              0x01
> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR    0x02
> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR    0x03
> +#define DRM_FORMAT_MOD_VS_TILE_8X8              0x04
> +#define DRM_FORMAT_MOD_VS_TILE_MODE1            0x05
> +#define DRM_FORMAT_MOD_VS_TILE_MODE2            0x06
> +#define DRM_FORMAT_MOD_VS_TILE_8X4              0x07
> +#define DRM_FORMAT_MOD_VS_TILE_MODE4            0x08
> +#define DRM_FORMAT_MOD_VS_TILE_MODE5            0x09
> +#define DRM_FORMAT_MOD_VS_TILE_MODE6            0x0A
> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4    0x0B
> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8    0x0C
> +#define DRM_FORMAT_MOD_VS_TILE_Y                0x0D
> +#define DRM_FORMAT_MOD_VS_TILE_128X1            0x0F
> +#define DRM_FORMAT_MOD_VS_TILE_256X1            0x10
> +#define DRM_FORMAT_MOD_VS_TILE_32X1             0x11
> +#define DRM_FORMAT_MOD_VS_TILE_64X1             0x12
> +#define DRM_FORMAT_MOD_VS_TILE_MODE4X4          0x15
> +
> +#define fourcc_mod_vs_norm_code(tile) \
> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_NORMAL, \
> +				(tile))
> +
> +#define fourcc_mod_vs_custom_code(tile) \
> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT, \
> +				(tile))
> +
>   #if defined(__cplusplus)
>   }
>   #endif
> diff --git a/include/uapi/drm/vs_drm.h b/include/uapi/drm/vs_drm.h
> new file mode 100644
> index 000000000000..96b7fc95d658
> --- /dev/null
> +++ b/include/uapi/drm/vs_drm.h

Another UAPI addition that appears to be unused. Please only add things 
that you're using.

Best regards
Thomas

> @@ -0,0 +1,50 @@
> +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
> +/*
> + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_DRM_H__
> +#define __VS_DRM_H__
> +
> +#include "drm.h"
> +
> +enum drm_vs_degamma_mode {
> +	VS_DEGAMMA_DISABLE = 0,
> +	VS_DEGAMMA_BT709 = 1,
> +	VS_DEGAMMA_BT2020 = 2,
> +};
> +
> +enum drm_vs_sync_dc_mode {
> +	VS_SINGLE_DC = 0,
> +	VS_MULTI_DC_PRIMARY = 1,
> +	VS_MULTI_DC_SECONDARY = 2,
> +};
> +
> +enum drm_vs_mmu_prefetch_mode {
> +	VS_MMU_PREFETCH_DISABLE = 0,
> +	VS_MMU_PREFETCH_ENABLE = 1,
> +};
> +
> +struct drm_vs_watermark {
> +	__u32 watermark;
> +	__u8 qos_low;
> +	__u8 qos_high;
> +};
> +
> +struct drm_vs_color_mgmt {
> +	__u32 colorkey;
> +	__u32 colorkey_high;
> +	__u32 clear_value;
> +	bool  clear_enable;
> +	bool  transparency;
> +};
> +
> +struct drm_vs_roi {
> +	bool enable;
> +	__u16 roi_x;
> +	__u16 roi_y;
> +	__u16 roi_w;
> +	__u16 roi_h;
> +};
> +
> +#endif /* __VS_DRM_H__ */

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH 4/9] drm/verisilicon: Add gem driver for JH7110 SoC
  2023-06-02  7:40 ` [PATCH 4/9] drm/verisilicon: Add gem driver for JH7110 SoC Keith Zhao
@ 2023-06-19 13:18   ` Thomas Zimmermann
  2023-07-20 10:00     ` Keith Zhao
  2023-06-19 14:22   ` Thomas Zimmermann
  1 sibling, 1 reply; 46+ messages in thread
From: Thomas Zimmermann @ 2023-06-19 13:18 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Heiko Stuebner, Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu,
	Shengyang Chen, Changhuang Liang


[-- Attachment #1.1: Type: text/plain, Size: 15338 bytes --]



Am 02.06.23 um 09:40 schrieb Keith Zhao:
> This patch implements gem related APIs for JH7100 SoC.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>   drivers/gpu/drm/verisilicon/Makefile |   3 +-
>   drivers/gpu/drm/verisilicon/vs_drv.c |   6 +
>   drivers/gpu/drm/verisilicon/vs_gem.c | 372 +++++++++++++++++++++++++++
>   drivers/gpu/drm/verisilicon/vs_gem.h |  72 ++++++
>   4 files changed, 452 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_gem.c
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_gem.h
> 
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> index 64ce1b26546c..30360e370e47 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -1,6 +1,7 @@
>   # SPDX-License-Identifier: GPL-2.0
>   
> -vs_drm-objs := vs_drv.o
> +vs_drm-objs := vs_drv.o \
> +		vs_gem.o
>   
>   obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
>   
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
> index 24d333598477..e0a2fc43b55f 100644
> --- a/drivers/gpu/drm/verisilicon/vs_drv.c
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> @@ -30,6 +30,7 @@
>   #include <drm/drm_vblank.h>
>   
>   #include "vs_drv.h"
> +#include "vs_gem.h"
>   
>   #define DRV_NAME	"starfive"
>   #define DRV_DESC	"Starfive DRM driver"
> @@ -47,6 +48,7 @@ static const struct file_operations fops = {
>   	.compat_ioctl	= drm_compat_ioctl,
>   	.poll			= drm_poll,
>   	.read			= drm_read,
> +	.mmap			= vs_gem_mmap,
>   };
>   
>   static struct drm_driver vs_drm_driver = {
> @@ -54,6 +56,10 @@ static struct drm_driver vs_drm_driver = {
>   	.lastclose		= drm_fb_helper_lastclose,
>   	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
>   	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> +	.gem_prime_import	= vs_gem_prime_import,
> +	.gem_prime_import_sg_table = vs_gem_prime_import_sg_table,
> +	.gem_prime_mmap		= vs_gem_prime_mmap,
> +	.dumb_create		= vs_gem_dumb_create,
>   	.fops			= &fops,
>   	.name			= DRV_NAME,
>   	.desc			= DRV_DESC,
> diff --git a/drivers/gpu/drm/verisilicon/vs_gem.c b/drivers/gpu/drm/verisilicon/vs_gem.c
> new file mode 100644
> index 000000000000..3f963471c1ab
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_gem.c
> @@ -0,0 +1,372 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#include <linux/dma-buf.h>
> +#include <linux/of_reserved_mem.h>
> +#include <drm/drm_gem_dma_helper.h>
> +
> +#include "vs_drv.h"
> +#include "vs_gem.h"
> +
> +static const struct drm_gem_object_funcs vs_gem_default_funcs;
> +
> +static int vs_gem_alloc_buf(struct vs_gem_object *vs_obj)
> +{
> +	struct drm_device *dev = vs_obj->base.dev;
> +	unsigned int nr_pages;
> +	struct sg_table sgt;
> +	int ret = -ENOMEM;
> +
> +	if (vs_obj->dma_addr) {
> +		DRM_DEV_DEBUG_KMS(dev->dev, "already allocated.\n");
> +		return 0;
> +	}
> +
> +	vs_obj->dma_attrs = DMA_ATTR_WRITE_COMBINE | DMA_ATTR_FORCE_CONTIGUOUS
> +			   | DMA_ATTR_NO_KERNEL_MAPPING;
> +
> +	nr_pages = vs_obj->size >> PAGE_SHIFT;
> +
> +	vs_obj->pages = kvmalloc_array(nr_pages, sizeof(struct page *),
> +				       GFP_KERNEL | __GFP_ZERO);
> +	if (!vs_obj->pages) {
> +		DRM_DEV_ERROR(dev->dev, "failed to allocate pages.\n");
> +		return -ENOMEM;
> +	}
> +
> +	vs_obj->cookie = dma_alloc_attrs(to_dma_dev(dev), vs_obj->size,
> +					 &vs_obj->dma_addr, GFP_KERNEL,
> +					 vs_obj->dma_attrs);
> +
> +	if (!vs_obj->cookie) {
> +		DRM_DEV_ERROR(dev->dev, "failed to allocate buffer.\n");
> +		goto err_free;
> +	}
> +
> +	vs_obj->iova = vs_obj->dma_addr;
> +
> +	ret = dma_get_sgtable_attrs(to_dma_dev(dev), &sgt,
> +				    vs_obj->cookie, vs_obj->dma_addr,
> +				    vs_obj->size, vs_obj->dma_attrs);
> +	if (ret < 0) {
> +		DRM_DEV_ERROR(dev->dev, "failed to get sgtable.\n");
> +		goto err_mem_free;
> +	}
> +
> +	if (drm_prime_sg_to_page_array(&sgt, vs_obj->pages, nr_pages)) {
> +		DRM_DEV_ERROR(dev->dev, "invalid sgtable.\n");
> +		ret = -EINVAL;
> +		goto err_sgt_free;
> +	}
> +
> +	sg_free_table(&sgt);
> +
> +	return 0;
> +
> +err_sgt_free:
> +	sg_free_table(&sgt);
> +err_mem_free:
> +		dma_free_attrs(to_dma_dev(dev), vs_obj->size, vs_obj->cookie,
> +			       vs_obj->dma_addr, vs_obj->dma_attrs);
> +err_free:
> +	kvfree(vs_obj->pages);
> +
> +	return ret;
> +}
> +
> +static void vs_gem_free_buf(struct vs_gem_object *vs_obj)
> +{
> +	struct drm_device *dev = vs_obj->base.dev;
> +
> +	if (!vs_obj->dma_addr) {
> +		DRM_DEV_DEBUG_KMS(dev->dev, "dma_addr is invalid.\n");
> +		return;
> +	}
> +
> +	dma_free_attrs(to_dma_dev(dev), vs_obj->size, vs_obj->cookie,
> +		       (dma_addr_t)vs_obj->dma_addr,
> +		       vs_obj->dma_attrs);
> +
> +	kvfree(vs_obj->pages);
> +}
> +
> +static void vs_gem_free_object(struct drm_gem_object *obj)
> +{
> +	struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
> +
> +	if (obj->import_attach)
> +		drm_prime_gem_destroy(obj, vs_obj->sgt);
> +	else
> +		vs_gem_free_buf(vs_obj);
> +
> +	drm_gem_object_release(obj);
> +
> +	kfree(vs_obj);
> +}
> +
> +static struct vs_gem_object *vs_gem_alloc_object(struct drm_device *dev,
> +						 size_t size)
> +{
> +	struct vs_gem_object *vs_obj;
> +	struct drm_gem_object *obj;
> +	int ret;
> +
> +	vs_obj = kzalloc(sizeof(*vs_obj), GFP_KERNEL);
> +	if (!vs_obj)
> +		return ERR_PTR(-ENOMEM);
> +
> +	vs_obj->size = size;
> +	obj = &vs_obj->base;
> +
> +	ret = drm_gem_object_init(dev, obj, size);
> +	if (ret)
> +		goto err_free;
> +
> +	vs_obj->base.funcs = &vs_gem_default_funcs;
> +
> +	ret = drm_gem_create_mmap_offset(obj);
> +	if (ret) {
> +		drm_gem_object_release(obj);
> +		goto err_free;
> +	}
> +
> +	return vs_obj;
> +
> +err_free:
> +	kfree(vs_obj);
> +	return ERR_PTR(ret);
> +}
> +
> +struct vs_gem_object *vs_gem_create_object(struct drm_device *dev,
> +					   size_t size)
> +{
> +	struct vs_gem_object *vs_obj;
> +	int ret;
> +
> +	size = PAGE_ALIGN(size);
> +
> +	vs_obj = vs_gem_alloc_object(dev, size);
> +	if (IS_ERR(vs_obj))
> +		return vs_obj;
> +
> +	ret = vs_gem_alloc_buf(vs_obj);
> +	if (ret) {
> +		drm_gem_object_release(&vs_obj->base);
> +		kfree(vs_obj);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return vs_obj;
> +}
> +
> +static struct vs_gem_object *vs_gem_create_with_handle(struct drm_device *dev,
> +						       struct drm_file *file,
> +						       size_t size,
> +						       unsigned int *handle)
> +{
> +	struct vs_gem_object *vs_obj;
> +	struct drm_gem_object *obj;
> +	int ret;
> +
> +	vs_obj = vs_gem_create_object(dev, size);
> +	if (IS_ERR(vs_obj))
> +		return vs_obj;
> +
> +	obj = &vs_obj->base;
> +
> +	ret = drm_gem_handle_create(file, obj, handle);
> +
> +	drm_gem_object_put(obj);
> +
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return vs_obj;
> +}
> +
> +static int vs_gem_mmap_obj(struct drm_gem_object *obj,
> +			   struct vm_area_struct *vma)
> +{
> +	struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
> +	struct drm_device *drm_dev = vs_obj->base.dev;
> +	unsigned long vm_size;
> +	int ret = 0;
> +
> +	vm_size = vma->vm_end - vma->vm_start;
> +	if (vm_size > vs_obj->size)
> +		return -EINVAL;
> +
> +	vma->vm_pgoff = 0;
> +
> +	/*
> +	 * We allocated a struct page table for starfive_obj, so clear
> +	 * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
> +	 */
> +	vm_flags_mod(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP, VM_PFNMAP);
> +
> +	vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
> +	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
> +
> +	ret = dma_mmap_attrs(to_dma_dev(drm_dev), vma, vs_obj->cookie,
> +			     vs_obj->dma_addr, vs_obj->size,
> +			     vs_obj->dma_attrs);
> +
> +	if (ret)
> +		drm_gem_vm_close(vma);
> +
> +	return ret;
> +}
> +
> +struct sg_table *vs_gem_prime_get_sg_table(struct drm_gem_object *obj)
> +{
> +	struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
> +
> +	return drm_prime_pages_to_sg(obj->dev, vs_obj->pages,
> +					 vs_obj->size >> PAGE_SHIFT);
> +}
> +
> +int vs_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
> +{
> +	struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
> +
> +	void *vaddr = vs_obj->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING ?
> +		       page_address(vs_obj->cookie) : vs_obj->cookie;
> +
> +	iosys_map_set_vaddr(map, vaddr);
> +
> +	return 0;
> +}
> +
> +void vs_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
> +{
> +	/* Nothing to do */
> +}
> +
> +static const struct vm_operations_struct vs_vm_ops = {
> +	.open  = drm_gem_vm_open,
> +	.close = drm_gem_vm_close,
> +};
> +
> +static const struct drm_gem_object_funcs vs_gem_default_funcs = {
> +	.free = vs_gem_free_object,
> +	.get_sg_table = vs_gem_prime_get_sg_table,
> +	.vmap = vs_gem_prime_vmap,
> +	.vunmap = vs_gem_prime_vunmap,
> +	.vm_ops = &vs_vm_ops,
> +};
> +
> +int vs_gem_dumb_create(struct drm_file *file,
> +		       struct drm_device *dev,
> +		       struct drm_mode_create_dumb *args)
> +{
> +	struct vs_drm_private *priv = dev->dev_private;
> +	struct vs_gem_object *vs_obj;
> +	unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
> +
> +	if (args->bpp % 10)
> +		args->pitch = ALIGN(pitch, priv->pitch_alignment);
> +	else
> +		/* for costum 10bit format with no bit gaps */
> +		args->pitch = pitch;
> +	args->size = PAGE_ALIGN(args->pitch * args->height);
> +	vs_obj = vs_gem_create_with_handle(dev, file, args->size,
> +					   &args->handle);
> +	return PTR_ERR_OR_ZERO(vs_obj);
> +}
> +
> +struct drm_gem_object *vs_gem_prime_import(struct drm_device *dev,
> +					   struct dma_buf *dma_buf)
> +{
> +	return drm_gem_prime_import_dev(dev, dma_buf, to_dma_dev(dev));
> +}
> +
> +struct drm_gem_object *
> +vs_gem_prime_import_sg_table(struct drm_device *dev,
> +			     struct dma_buf_attachment *attach,
> +			     struct sg_table *sgt)
> +{
> +	struct vs_gem_object *vs_obj;
> +	int npages;
> +	int ret;
> +	struct scatterlist *s;
> +	u32 i;
> +	dma_addr_t expected;
> +	size_t size = attach->dmabuf->size;
> +
> +	size = PAGE_ALIGN(size);
> +
> +	vs_obj = vs_gem_alloc_object(dev, size);
> +	if (IS_ERR(vs_obj))
> +		return ERR_CAST(vs_obj);
> +
> +	expected = sg_dma_address(sgt->sgl);
> +	for_each_sg(sgt->sgl, s, sgt->nents, i) {
> +		if (sg_dma_address(s) != expected) {
> +			DRM_ERROR("sg_table is not contiguous");
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +		if (sg_dma_len(s) & (PAGE_SIZE - 1)) {
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +		if (i == 0)
> +			vs_obj->iova = sg_dma_address(s);
> +		expected = sg_dma_address(s) + sg_dma_len(s);
> +	}
> +
> +	vs_obj->dma_addr = sg_dma_address(sgt->sgl);
> +
> +	npages = vs_obj->size >> PAGE_SHIFT;
> +	vs_obj->pages = kvmalloc_array(npages, sizeof(struct page *),
> +				       GFP_KERNEL);
> +	if (!vs_obj->pages) {
> +		ret = -ENOMEM;
> +		goto err;
> +	}
> +
> +	ret = drm_prime_sg_to_page_array(sgt, vs_obj->pages, npages);
> +	if (ret)
> +		goto err_free_page;
> +
> +	vs_obj->sgt = sgt;
> +
> +	return &vs_obj->base;
> +
> +err_free_page:
> +	kvfree(vs_obj->pages);
> +err:
> +	vs_gem_free_object(&vs_obj->base);
> +
> +	return ERR_PTR(ret);
> +}
> +
> +int vs_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
> +{
> +	int ret = 0;
> +
> +	ret = drm_gem_mmap_obj(obj, obj->size, vma);
> +	if (ret < 0)
> +		return ret;
> +
> +	return vs_gem_mmap_obj(obj, vma);
> +}
> +
> +int vs_gem_mmap(struct file *filp, struct vm_area_struct *vma)

This function needs to go away.

> +{
> +	struct drm_gem_object *obj;
> +	int ret;
> +
> +	ret = drm_gem_mmap(filp, vma);

Set drm_gem_mmap() as your fops.mmap callback.

> +	if (ret)
> +		return ret;
> +
> +	obj = vma->vm_private_data;
> +
> +	if (obj->import_attach)
> +		return dma_buf_mmap(obj->dma_buf, vma, 0);
> +
> +	return vs_gem_mmap_obj(obj, vma);

Both, dma_buf and regular objects, should be handled in struct 
drm_gem_object_funcs.mmap. drm_gem_mmap() will call it for you. 
vs_gem_mmap_obj() can then be removed.

you can find example code in drm_gem_shmem_helper.c and 
drm_gem_dma_helper.c on how to write GEM object's mmap function.


> +}
> diff --git a/drivers/gpu/drm/verisilicon/vs_gem.h b/drivers/gpu/drm/verisilicon/vs_gem.h
> new file mode 100644
> index 000000000000..3a6d7452cb06
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_gem.h
> @@ -0,0 +1,72 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_GEM_H__
> +#define __VS_GEM_H__
> +
> +#include <linux/dma-buf.h>
> +
> +#include <drm/drm_gem.h>
> +#include <drm/drm_prime.h>
> +
> +#include "vs_drv.h"
> +/*
> + *
> + * @base: drm gem object.
> + * @size: size requested from user
> + * @cookie: cookie returned by dma_alloc_attrs
> + *	- not kernel virtual address with DMA_ATTR_NO_KERNEL_MAPPING
> + * @dma_addr: bus address(accessed by dma) to allocated memory region.
> + *	- this address could be physical address without IOMMU and
> + *	device address with IOMMU.
> + * @dma_attrs: attribute for DMA API
> + * @get_pages: flag for manually applying for non-contiguous memory.
> + * @pages: Array of backing pages.
> + * @sgt: Imported sg_table.
> + *
> + */
> +struct vs_gem_object {
> +	struct drm_gem_object	base;
> +	size_t			size;
> +	void			*cookie;
> +	dma_addr_t		dma_addr;
> +	u32				iova;
> +	unsigned long	dma_attrs;
> +	bool			get_pages;
> +	struct page		**pages;
> +	struct sg_table *sgt;
> +};
> +
> +static inline
> +struct vs_gem_object *to_vs_gem_object(struct drm_gem_object *obj)
> +{
> +	return container_of(obj, struct vs_gem_object, base);
> +}
> +
> +struct vs_gem_object *vs_gem_create_object(struct drm_device *dev,
> +					   size_t size);
> +
> +int vs_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map);
> +void vs_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map);



> +
> +int vs_gem_prime_mmap(struct drm_gem_object *obj,
> +		      struct vm_area_struct *vma);
> +
> +int vs_gem_dumb_create(struct drm_file *file_priv,
> +		       struct drm_device *drm,
> +		       struct drm_mode_create_dumb *args);
> +
> +int vs_gem_mmap(struct file *filp, struct vm_area_struct *vma);
> +
> +struct sg_table *vs_gem_prime_get_sg_table(struct drm_gem_object *obj);
> +
> +struct drm_gem_object *vs_gem_prime_import(struct drm_device *dev,
> +					   struct dma_buf *dma_buf);
> +struct drm_gem_object *
> +vs_gem_prime_import_sg_table(struct drm_device *dev,
> +			     struct dma_buf_attachment *attach,
> +			     struct sg_table *sgt);
> +
> +#endif /* __VS_GEM_H__ */

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH 4/9] drm/verisilicon: Add gem driver for JH7110 SoC
  2023-06-02  7:40 ` [PATCH 4/9] drm/verisilicon: Add gem driver for JH7110 SoC Keith Zhao
  2023-06-19 13:18   ` Thomas Zimmermann
@ 2023-06-19 14:22   ` Thomas Zimmermann
  2023-06-21 10:44     ` Thomas Zimmermann
  1 sibling, 1 reply; 46+ messages in thread
From: Thomas Zimmermann @ 2023-06-19 14:22 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: Krzysztof Kozlowski, Sumit Semwal, Emil Renner Berthing,
	Shengyang Chen, Conor Dooley, Albert Ou, Jagan Teki, Rob Herring,
	Chris Morgan, Paul Walmsley, Bjorn Andersson, Changhuang Liang,
	Jack Zhu, Palmer Dabbelt, Shawn Guo, christian.koenig


[-- Attachment #1.1: Type: text/plain, Size: 3252 bytes --]

Hi

Am 02.06.23 um 09:40 schrieb Keith Zhao:
> This patch implements gem related APIs for JH7100 SoC.

please also see my other reply to this patch. My mail client had a bug 
before I could finish it. Below are some more comments.

> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
[...]
> +#ifndef __VS_GEM_H__
> +#define __VS_GEM_H__
> +
> +#include <linux/dma-buf.h>
> +
> +#include <drm/drm_gem.h>
> +#include <drm/drm_prime.h>
> +
> +#include "vs_drv.h"
> +/*
> + *
> + * @base: drm gem object.
> + * @size: size requested from user
> + * @cookie: cookie returned by dma_alloc_attrs
> + *	- not kernel virtual address with DMA_ATTR_NO_KERNEL_MAPPING
> + * @dma_addr: bus address(accessed by dma) to allocated memory region.
> + *	- this address could be physical address without IOMMU and
> + *	device address with IOMMU.
> + * @dma_attrs: attribute for DMA API
> + * @get_pages: flag for manually applying for non-contiguous memory.
> + * @pages: Array of backing pages.
> + * @sgt: Imported sg_table.
> + *
> + */
> +struct vs_gem_object {
> +	struct drm_gem_object	base;
> +	size_t			size;
> +	void			*cookie;
> +	dma_addr_t		dma_addr;
> +	u32				iova;
> +	unsigned long	dma_attrs;
> +	bool			get_pages;
> +	struct page		**pages;
> +	struct sg_table *sgt;
> +};
> +
> +static inline
> +struct vs_gem_object *to_vs_gem_object(struct drm_gem_object *obj)
> +{
> +	return container_of(obj, struct vs_gem_object, base);
> +}
> +
> +struct vs_gem_object *vs_gem_create_object(struct drm_device *dev,
> +					   size_t size);
> +
> +int vs_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map);
> +void vs_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map);

I'd consider this bad style. Your functions are in the vs_ namespace, so 
they should take a vs_gem_object as first argument. Rather implement 
vs_gem_prime_vmap(struct vs_gem_object *vs_obj, struct iosys_map *map)
and _vunmap() and _mmap().

For the callbacks in struct drm_gemobject_funcs, you can write small 
wrappers around the helpers to do the type casting. See 
drm_gem_shmem_object_mmap() and drm_gem_shmem_mmap() for an example.

https://elixir.bootlin.com/linux/latest/source/include/drm/drm_gem_shmem_helper.h#L233



> +
> +int vs_gem_prime_mmap(struct drm_gem_object *obj,
> +		      struct vm_area_struct *vma);
> +
> +int vs_gem_dumb_create(struct drm_file *file_priv,
> +		       struct drm_device *drm,
> +		       struct drm_mode_create_dumb *args);
> +
> +int vs_gem_mmap(struct file *filp, struct vm_area_struct *vma);
> +
> +struct sg_table *vs_gem_prime_get_sg_table(struct drm_gem_object *obj);
> +
> +struct drm_gem_object *vs_gem_prime_import(struct drm_device *dev,
> +					   struct dma_buf *dma_buf);
> +struct drm_gem_object *
> +vs_gem_prime_import_sg_table(struct drm_device *dev,
> +			     struct dma_buf_attachment *attach,
> +			     struct sg_table *sgt);
> +
> +#endif /* __VS_GEM_H__ */

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH 4/9] drm/verisilicon: Add gem driver for JH7110 SoC
  2023-06-19 14:22   ` Thomas Zimmermann
@ 2023-06-21 10:44     ` Thomas Zimmermann
  0 siblings, 0 replies; 46+ messages in thread
From: Thomas Zimmermann @ 2023-06-21 10:44 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: Conor Dooley, Albert Ou, Emil Renner Berthing, christian.koenig,
	Bjorn Andersson, Chris Morgan, Changhuang Liang, Jagan Teki,
	Jack Zhu, Rob Herring, Palmer Dabbelt, Krzysztof Kozlowski,
	Paul Walmsley, Shengyang Chen, Shawn Guo, Sumit Semwal


[-- Attachment #1.1: Type: text/plain, Size: 4281 bytes --]

Hi

Am 19.06.23 um 16:22 schrieb Thomas Zimmermann:
> Hi
> 
> Am 02.06.23 um 09:40 schrieb Keith Zhao:
>> This patch implements gem related APIs for JH7100 SoC.
> 
> please also see my other reply to this patch. My mail client had a bug 
> before I could finish it. Below are some more comments.
> 
>>
>> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
>> ---
> [...]
>> +#ifndef __VS_GEM_H__
>> +#define __VS_GEM_H__
>> +
>> +#include <linux/dma-buf.h>
>> +
>> +#include <drm/drm_gem.h>
>> +#include <drm/drm_prime.h>
>> +
>> +#include "vs_drv.h"
>> +/*
>> + *
>> + * @base: drm gem object.
>> + * @size: size requested from user
>> + * @cookie: cookie returned by dma_alloc_attrs
>> + *    - not kernel virtual address with DMA_ATTR_NO_KERNEL_MAPPING
>> + * @dma_addr: bus address(accessed by dma) to allocated memory region.
>> + *    - this address could be physical address without IOMMU and
>> + *    device address with IOMMU.
>> + * @dma_attrs: attribute for DMA API
>> + * @get_pages: flag for manually applying for non-contiguous memory.
>> + * @pages: Array of backing pages.
>> + * @sgt: Imported sg_table.
>> + *
>> + */
>> +struct vs_gem_object {
>> +    struct drm_gem_object    base;
>> +    size_t            size;
>> +    void            *cookie;
>> +    dma_addr_t        dma_addr;
>> +    u32                iova;
>> +    unsigned long    dma_attrs;
>> +    bool            get_pages;
>> +    struct page        **pages;
>> +    struct sg_table *sgt;
>> +};
>> +
>> +static inline
>> +struct vs_gem_object *to_vs_gem_object(struct drm_gem_object *obj)
>> +{
>> +    return container_of(obj, struct vs_gem_object, base);
>> +}
>> +
>> +struct vs_gem_object *vs_gem_create_object(struct drm_device *dev,
>> +                       size_t size);
>> +
>> +int vs_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map 
>> *map);
>> +void vs_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map 
>> *map);
> 
> I'd consider this bad style. Your functions are in the vs_ namespace, so 
> they should take a vs_gem_object as first argument. Rather implement 
> vs_gem_prime_vmap(struct vs_gem_object *vs_obj, struct iosys_map *map)
> and _vunmap() and _mmap().
> 
> For the callbacks in struct drm_gemobject_funcs, you can write small 
> wrappers around the helpers to do the type casting. See 
> drm_gem_shmem_object_mmap() and drm_gem_shmem_mmap() for an example.
> 
> https://elixir.bootlin.com/linux/latest/source/include/drm/drm_gem_shmem_helper.h#L233

I was thinking about my advise with the wrappers, but it doesn't seem so 
good after all. Maybe just ignore it. I think you should still rename 
the function to something like vs_gem_object_vmap(), etc.  So they name 
reflects that they operate on a struct drm_gem_object.

But many of the helpers in this file are only ever used in vs_gem.c. 
You should declare them static in the C file and remove them from this 
header.

Best regards
Thomas

> 
> 
> 
>> +
>> +int vs_gem_prime_mmap(struct drm_gem_object *obj,
>> +              struct vm_area_struct *vma);
>> +
>> +int vs_gem_dumb_create(struct drm_file *file_priv,
>> +               struct drm_device *drm,
>> +               struct drm_mode_create_dumb *args);
>> +
>> +int vs_gem_mmap(struct file *filp, struct vm_area_struct *vma);
>> +
>> +struct sg_table *vs_gem_prime_get_sg_table(struct drm_gem_object *obj);
>> +
>> +struct drm_gem_object *vs_gem_prime_import(struct drm_device *dev,
>> +                       struct dma_buf *dma_buf);
>> +struct drm_gem_object *
>> +vs_gem_prime_import_sg_table(struct drm_device *dev,
>> +                 struct dma_buf_attachment *attach,
>> +                 struct sg_table *sgt);
>> +
>> +#endif /* __VS_GEM_H__ */
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH 5/9] drm/verisilicon: Add mode config funcs
  2023-06-02  7:40 ` [PATCH 5/9] drm/verisilicon: Add mode config funcs Keith Zhao
@ 2023-06-21 11:04   ` Thomas Zimmermann
  2023-07-21  9:06     ` Keith Zhao
  0 siblings, 1 reply; 46+ messages in thread
From: Thomas Zimmermann @ 2023-06-21 11:04 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Heiko Stuebner, Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu,
	Shengyang Chen, Changhuang Liang


[-- Attachment #1.1: Type: text/plain, Size: 8471 bytes --]

Hi Keith

Am 02.06.23 um 09:40 schrieb Keith Zhao:
> Add mode setting functions for JH7110 SoC.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>   drivers/gpu/drm/verisilicon/Makefile |   1 +
>   drivers/gpu/drm/verisilicon/vs_drv.c |   3 +

>   drivers/gpu/drm/verisilicon/vs_fb.c  | 181 +++++++++++++++++++++++++++
>   drivers/gpu/drm/verisilicon/vs_fb.h  |  15 +++

I'd call these files vs_modeset.{c,h} to be consistent with the rest of 
the drivers.

>   4 files changed, 200 insertions(+)
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_fb.c
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_fb.h
> 
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> index 30360e370e47..38254dc5d98d 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -1,6 +1,7 @@
>   # SPDX-License-Identifier: GPL-2.0
>   
>   vs_drm-objs := vs_drv.o \
> +		vs_fb.o \
>   		vs_gem.o
>   
>   obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
> index e0a2fc43b55f..d84aacd751bc 100644
> --- a/drivers/gpu/drm/verisilicon/vs_drv.c
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> @@ -30,6 +30,7 @@
>   #include <drm/drm_vblank.h>
>   
>   #include "vs_drv.h"
> +#include "vs_fb.h"
>   #include "vs_gem.h"
>   
>   #define DRV_NAME	"starfive"
> @@ -118,6 +119,8 @@ static int vs_drm_bind(struct device *dev)
>   	if (ret)
>   		goto err_mode;
>   
> +	vs_mode_config_init(drm_dev);
> +
>   	ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
>   	if (ret)
>   		goto err_bind;
> diff --git a/drivers/gpu/drm/verisilicon/vs_fb.c b/drivers/gpu/drm/verisilicon/vs_fb.c
> new file mode 100644
> index 000000000000..3e85f7365084
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_fb.c
> @@ -0,0 +1,181 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/version.h>
> +
> +#include <drm/drm_damage_helper.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_framebuffer.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_gem_framebuffer_helper.h>
> +
> +#include "vs_fb.h"
> +#include "vs_gem.h"
> +
> +#define fourcc_mod_vs_get_type(val) \
> +	(((val) & DRM_FORMAT_MOD_VS_TYPE_MASK) >> 54)
> +
> +static struct drm_framebuffer_funcs vs_fb_funcs = {
> +	.create_handle	= drm_gem_fb_create_handle,
> +	.destroy	= drm_gem_fb_destroy,
> +	.dirty		= drm_atomic_helper_dirtyfb,
> +};
> +
> +static struct drm_framebuffer *
> +vs_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd,
> +	    struct vs_gem_object **obj, unsigned int num_planes)
> +{
> +	struct drm_framebuffer *fb;
> +	int ret, i;
> +
> +	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
> +	if (!fb)
> +		return ERR_PTR(-ENOMEM);
> +
> +	drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
> +
> +	for (i = 0; i < num_planes; i++)
> +		fb->obj[i] = &obj[i]->base;
> +
> +	ret = drm_framebuffer_init(dev, fb, &vs_fb_funcs);
> +	if (ret) {
> +		dev_err(dev->dev, "Failed to initialize framebuffer: %d\n",
> +			ret);
> +		kfree(fb);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return fb;
> +}
> +
> +static struct drm_framebuffer *vs_fb_create(struct drm_device *dev,
> +					    struct drm_file *file_priv,
> +					    const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	struct drm_framebuffer *fb;
> +	const struct drm_format_info *info;
> +	struct vs_gem_object *objs[MAX_NUM_PLANES];
> +	struct drm_gem_object *obj;
> +	unsigned int height, size;
> +	unsigned char i, num_planes;
> +	int ret = 0;
> +
> +	info = drm_get_format_info(dev, mode_cmd);
> +	if (!info)
> +		return ERR_PTR(-EINVAL);
> +
> +	num_planes = info->num_planes;
> +	if (num_planes > MAX_NUM_PLANES)
> +		return ERR_PTR(-EINVAL);
> +
> +	for (i = 0; i < num_planes; i++) {
> +		obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
> +		if (!obj) {
> +			dev_err(dev->dev, "Failed to lookup GEM object.\n");
> +			ret = -ENXIO;
> +			goto err;
> +		}
> +
> +		height = drm_format_info_plane_height(info,
> +						      mode_cmd->height, i);
> +
> +		size = height * mode_cmd->pitches[i] + mode_cmd->offsets[i];
> +
> +		if (obj->size < size) {
> +			drm_gem_object_put(obj);
> +
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +
> +		objs[i] = to_vs_gem_object(obj);
> +	}
> +
> +	fb = vs_fb_alloc(dev, mode_cmd, objs, i);
> +	if (IS_ERR(fb)) {
> +		ret = PTR_ERR(fb);
> +		goto err;
> +	}
> +
> +	return fb;
> +
> +err:
> +	for (; i > 0; i--)
> +		drm_gem_object_put(&objs[i - 1]->base);
> +
> +	return ERR_PTR(ret);
> +}
> +
> +struct vs_gem_object *vs_fb_get_gem_obj(struct drm_framebuffer *fb,
> +					unsigned char plane)
> +{
> +	if (plane > MAX_NUM_PLANES)
> +		return NULL;
> +
> +	return to_vs_gem_object(fb->obj[plane]);
> +}
> +
> +static const struct drm_format_info vs_formats[] = {
> +	{.format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .char_per_block = { 20, 40, 0 },
> +	 .block_w = { 4, 4, 0 }, .block_h = { 4, 4, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true},
> +	{.format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .char_per_block = { 20, 20, 20 },
> +	 .block_w = { 4, 4, 4 }, .block_h = { 4, 4, 4 }, .hsub = 1, .vsub = 1, .is_yuv = true},
> +};
> +
> +static const struct drm_format_info *
> +vs_lookup_format_info(const struct drm_format_info formats[],
> +		      int num_formats, u32 format)
> +{
> +	int i;
> +
> +	for (i = 0; i < num_formats; i++) {
> +		if (formats[i].format == format)
> +			return &formats[i];
> +	}
> +
> +	return NULL;
> +}
> +
> +static const struct drm_format_info *
> +vs_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
> +{
> +	if (fourcc_mod_vs_get_type(cmd->modifier[0]) ==
> +		DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT)
> +		return vs_lookup_format_info(vs_formats, ARRAY_SIZE(vs_formats),
> +									 cmd->pixel_format);
> +	else
> +		return NULL;
> +}
> +
> +static const struct drm_mode_config_funcs vs_mode_config_funcs = {
> +	.fb_create			 = vs_fb_create,

Maybe I'm missing something here, but it looks like you can call
drm_gem_fb_create_with_funcs() to create the framebuffer.

> +	.get_format_info	 = vs_get_format_info,
> +	.output_poll_changed = drm_fb_helper_output_poll_changed,
> +	.atomic_check		 = drm_atomic_helper_check,
> +	.atomic_commit		 = drm_atomic_helper_commit,
> +};
> +
> +static struct drm_mode_config_helper_funcs vs_mode_config_helpers = {
> +	.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
> +};
> +
> +void vs_mode_config_init(struct drm_device *dev)
> +{

If possible, move the call to drm_mode_config_init() into this function.

> +	dev->mode_config.fb_modifiers_not_supported = false;
> +
> +	if (dev->mode_config.max_width == 0 ||
> +	    dev->mode_config.max_height == 0) {
> +		dev->mode_config.min_width  = 0;
> +		dev->mode_config.min_height = 0;
> +		dev->mode_config.max_width  = 4096;
> +		dev->mode_config.max_height = 4096;
> +	}
> +	dev->mode_config.funcs = &vs_mode_config_funcs;
> +	dev->mode_config.helper_private = &vs_mode_config_helpers;
> +}
> diff --git a/drivers/gpu/drm/verisilicon/vs_fb.h b/drivers/gpu/drm/verisilicon/vs_fb.h
> new file mode 100644
> index 000000000000..78dda8e42894
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_fb.h
> @@ -0,0 +1,15 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_FB_H__
> +#define __VS_FB_H__
> +
> +#define MAX_NUM_PLANES		3 /* colour format plane */

There's DRM_FORMAT_MAX_PLANES already. Please don't introduce a constant 
with the same purpose.

Best regards
Thomas

> +
> +struct vs_gem_object *vs_fb_get_gem_obj(struct drm_framebuffer *fb,
> +					unsigned char plane);
> +
> +void vs_mode_config_init(struct drm_device *dev);
> +#endif /* __VS_FB_H__ */

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH 0/9] Add DRM driver for StarFive SoC JH7110
  2023-06-02  7:40 [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Keith Zhao
                   ` (8 preceding siblings ...)
  2023-06-02  7:40 ` [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver Keith Zhao
@ 2023-06-22 18:19 ` Palmer Dabbelt
  9 siblings, 0 replies; 46+ messages in thread
From: Palmer Dabbelt @ 2023-06-22 18:19 UTC (permalink / raw)
  To: keith.zhao
  Cc: dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig, airlied, daniel, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, kernel, Paul Walmsley, aou, maarten.lankhorst, mripard,
	tzimmermann, p.zabel, sumit.semwal, christian.koenig, andersson,
	heiko, shawnguo, jagan, macromorgan, keith.zhao, jack.zhu,
	shengyang.chen, changhuang.liang

On Fri, 02 Jun 2023 00:40:34 PDT (-0700), keith.zhao@starfivetech.com wrote:
> Hi,
>
> This series is a DRM driver for StarFive SoC JH7110, which includes a
> display controller driver for Verisilicon DC8200 and an HMDI driver.
>
> We use GEM framework for buffer management and allocate memory by
> using DMA APIs.
>
> The JH7110 display subsystem includes a display controller Verisilicon
> DC8200 and an HDMI transmitter. The HDMI TX IP is designed for transmitting
> video and audio data from DC8200 to a display device. The HDMI TX IP
> consists of  the digital controller and the physical layer.
>
> This series does not support HDMI audio driver.
>
> Keith Zhao (9):
>   dt-bindings: display: Add yamls for JH7110 display subsystem
>   riscv: dts: starfive: jh7110: add dc&hdmi controller node
>   drm/verisilicon: Add basic drm driver
>   drm/verisilicon: Add gem driver for JH7110 SoC
>   drm/verisilicon: Add mode config funcs
>   drm/verisilicon: Add drm crtc funcs
>   drm/verisilicon: Add drm plane funcs
>   drm/verisilicon: Add verisilicon dc controller driver
>   drm/verisilicon: Add starfive hdmi driver
>
>  .../display/verisilicon/starfive-hdmi.yaml    |   93 +
>  .../display/verisilicon/verisilicon-dc.yaml   |  110 +
>  .../display/verisilicon/verisilicon-drm.yaml  |   42 +
>  .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
>  MAINTAINERS                                   |    9 +
>  .../jh7110-starfive-visionfive-2.dtsi         |   87 +
>  arch/riscv/boot/dts/starfive/jh7110.dtsi      |   46 +
>  drivers/gpu/drm/Kconfig                       |    2 +
>  drivers/gpu/drm/Makefile                      |    1 +
>  drivers/gpu/drm/verisilicon/Kconfig           |   24 +
>  drivers/gpu/drm/verisilicon/Makefile          |   13 +
>  drivers/gpu/drm/verisilicon/starfive_hdmi.c   |  928 ++++++++
>  drivers/gpu/drm/verisilicon/starfive_hdmi.h   |  296 +++
>  drivers/gpu/drm/verisilicon/vs_crtc.c         |  388 ++++
>  drivers/gpu/drm/verisilicon/vs_crtc.h         |   74 +
>  drivers/gpu/drm/verisilicon/vs_dc.c           | 1040 +++++++++
>  drivers/gpu/drm/verisilicon/vs_dc.h           |   62 +
>  drivers/gpu/drm/verisilicon/vs_dc_hw.c        | 2008 +++++++++++++++++
>  drivers/gpu/drm/verisilicon/vs_dc_hw.h        |  496 ++++
>  drivers/gpu/drm/verisilicon/vs_drv.c          |  301 +++
>  drivers/gpu/drm/verisilicon/vs_drv.h          |   52 +
>  drivers/gpu/drm/verisilicon/vs_fb.c           |  181 ++
>  drivers/gpu/drm/verisilicon/vs_fb.h           |   15 +
>  drivers/gpu/drm/verisilicon/vs_gem.c          |  372 +++
>  drivers/gpu/drm/verisilicon/vs_gem.h          |   72 +
>  drivers/gpu/drm/verisilicon/vs_plane.c        |  440 ++++
>  drivers/gpu/drm/verisilicon/vs_plane.h        |   74 +
>  drivers/gpu/drm/verisilicon/vs_type.h         |   72 +
>  include/uapi/drm/drm_fourcc.h                 |   83 +
>  include/uapi/drm/vs_drm.h                     |   50 +
>  30 files changed, 7433 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
>  create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
>  create mode 100644 drivers/gpu/drm/verisilicon/Makefile
>  create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.c
>  create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.h
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.c
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.h
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_fb.c
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_fb.h
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_gem.c
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_gem.h
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
>  create mode 100644 include/uapi/drm/vs_drm.h

This popped up in the RISC-V patchwork, so

Acked-by: Palmer Dabbelt <palmer@rivosinc.com> # RISC-V

in case anyone was looking for one -- I definately don't know anything 
about DRM, though, so not sure that means much...

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

* RE: [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver
  2023-06-02  7:40 ` [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver Keith Zhao
  2023-06-05  8:08   ` Philipp Zabel
  2023-06-05  9:56   ` Maxime Ripard
@ 2023-06-23  2:38   ` Hoegeun Kwon
  2023-06-26  5:34     ` Keith Zhao
  2 siblings, 1 reply; 46+ messages in thread
From: Hoegeun Kwon @ 2023-06-23  2:38 UTC (permalink / raw)
  To: 'Keith Zhao',
	dri-devel, devicetree, linux-kernel, linux-riscv, linux-media,
	linaro-mm-sig
  Cc: 'Krzysztof Kozlowski', 'Sumit Semwal',
	'Emil Renner Berthing', 'Shengyang Chen',
	'Conor Dooley', 'Albert Ou',
	'Thomas Zimmermann', 'Jagan Teki',
	'Rob Herring', 'Chris Morgan',
	'Paul Walmsley', 'Bjorn Andersson',
	'Changhuang Liang', 'Jack Zhu',
	'Palmer Dabbelt', 'Shawn Guo',
	christian.koenig, hoegeun.kwon

Hi Keith,

There is a problem with stopping when changing modes.

Below test log

root:~> modetest -Mstarfive -c
Connectors:
id      encoder status          name            size (mm)       modes
encoders
116     115     connected       HDMI-A-1        320x180         51      115
  modes:
        index name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot
  #0 1280x800 59.91 1280 1328 1360 1440 800 803 809 823 71000 flags: phsync,
pvsync; type: preferred, driver
  #1 1920x1080 60.00 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags:
phsync, pvsync; type: driver
[...]

root:~> modetest -Mstarfive -s 116:#0 -v
setting mode 1280x800-59.91Hz on connectors 116, crtc 31
freq: 60.65Hz
freq: 59.91Hz
freq: 59.91Hz

root:~> modetest -Mstarfive -s 116:#1 -v
setting mode 1920x1080-60.00Hz on connectors 116, crtc 31
[   94.535626] rcu: INFO: rcu_sched detected stalls on CPUs/tasks:
[   94.560985] rcu:     1-...0: (20 ticks this GP)
idle=c9bc/1/0x4000000000000000 softirq=3869/3871 fqs=1120
[   94.589532] rcu:     (detected by 3, t=5264 jiffies, g=4645, q=63
ncpus=4)
[   94.615335] Task dump for CPU 1:
[   94.637723] task:modetest        state:R  running task     stack:0
pid:407   ppid:397    flags:0x00000008
[   94.667299] Call Trace:
[   94.689297] [<ffffffff80d1e8fc>] __schedule+0x2a8/0xa52
[   94.714221] [<ffffffff80d1f100>] schedule+0x5a/0xdc
[   94.738626] [<ffffffff80d25a14>] schedule_timeout+0x220/0x2a6
[   94.763762] [<ffffffff80d2037a>] wait_for_completion+0xfe/0x126
[   94.789073] [<ffffffff8002ffe4>] kthread_flush_worker+0x82/0xa0


> -----Original Message-----
> From: dri-devel <dri-devel-bounces@lists.freedesktop.org> On Behalf Of
> Keith Zhao
> Sent: Friday, June 2, 2023 4:41 PM
> To: dri-devel@lists.freedesktop.org; devicetree@vger.kernel.org; linux-
> kernel@vger.kernel.org; linux-riscv@lists.infradead.org; linux-
> media@vger.kernel.org; linaro-mm-sig@lists.linaro.org
> Cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>; Sumit Semwal
> <sumit.semwal@linaro.org>; Emil Renner Berthing <kernel@esmil.dk>;
> Shengyang Chen <shengyang.chen@starfivetech.com>; Conor Dooley
> <conor+dt@kernel.org>; Albert Ou <aou@eecs.berkeley.edu>; Thomas
> Zimmermann <tzimmermann@suse.de>; Jagan Teki <jagan@edgeble.ai>; Rob
> Herring <robh+dt@kernel.org>; Chris Morgan <macromorgan@hotmail.com>; Paul
> Walmsley <paul.walmsley@sifive.com>; Keith Zhao
> <keith.zhao@starfivetech.com>; Bjorn Andersson <andersson@kernel.org>;
> Changhuang Liang <changhuang.liang@starfivetech.com>; Jack Zhu
> <jack.zhu@starfivetech.com>; Palmer Dabbelt <palmer@dabbelt.com>; Shawn
> Guo <shawnguo@kernel.org>; christian.koenig@amd.com
> Subject: [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver
> 
> Add HDMI dirver for StarFive SoC JH7110.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>  drivers/gpu/drm/verisilicon/Kconfig         |  11 +
>  drivers/gpu/drm/verisilicon/Makefile        |   1 +
>  drivers/gpu/drm/verisilicon/starfive_hdmi.c | 928 ++++++++++++++++++++
> drivers/gpu/drm/verisilicon/starfive_hdmi.h | 296 +++++++
>  drivers/gpu/drm/verisilicon/vs_drv.c        |   6 +
>  drivers/gpu/drm/verisilicon/vs_drv.h        |   4 +
>  6 files changed, 1246 insertions(+)
>  create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.c
>  create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.h

[...]

> diff --git a/drivers/gpu/drm/verisilicon/starfive_hdmi.c
> b/drivers/gpu/drm/verisilicon/starfive_hdmi.c
> new file mode 100644
> index 000000000000..128ecca03309
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/starfive_hdmi.c
> @@ -0,0 +1,928 @@

[...]

> +static int starfive_hdmi_setup(struct starfive_hdmi *hdmi,
> +			       struct drm_display_mode *mode) {

[...]

> +	return 0;
> +}
> +
> +static void starfive_hdmi_encoder_mode_set(struct drm_encoder *encoder,
> +					   struct drm_display_mode *mode,
> +					   struct drm_display_mode
*adj_mode) {
> +	struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
> +
> +	starfive_hdmi_setup(hdmi, adj_mode);

When starfive_hdmi_setup runs here,
when changing the mode, a problem occurs because try to write a value to reg
in a state that is not resumed after suspend.

> +
> +	memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi-
> >previous_mode)); }
> +
> +static void starfive_hdmi_encoder_enable(struct drm_encoder *encoder) {
> +	struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
> +
> +	pm_runtime_get_sync(hdmi->dev);

So if move the call point of starfive_hdmi_setup here, it works normally.

> +}

Best regards,
Hoegeun



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

* Re: [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver
  2023-06-23  2:38   ` Hoegeun Kwon
@ 2023-06-26  5:34     ` Keith Zhao
  0 siblings, 0 replies; 46+ messages in thread
From: Keith Zhao @ 2023-06-26  5:34 UTC (permalink / raw)


yes I tested 
modetest -M starfive -D 0 -s 116@31:1280x720-59.94 -v
modetest -M starfive -D 0 -s 116@31:1920x1080 -v

and the second command will repeat the problem
as you advise at the beginning
I call the "starfive_hdmi_setup"  function in the "starfive_hdmi_encoder_enable"
instead of "starfive_hdmi_encoder_mode_set"
resolve the problem
i will add this modify in my next patch

Thank you Hoegeun

On 2023/6/23 10:38, Hoegeun Kwon wrote:
> Hi Keith,
> 
> There is a problem with stopping when changing modes.
> 
> Below test log
> 
> root:~> modetest -Mstarfive -c
> Connectors:
> id      encoder status          name            size (mm)       modes
> encoders
> 116     115     connected       HDMI-A-1        320x180         51      115
>   modes:
>         index name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot
>   #0 1280x800 59.91 1280 1328 1360 1440 800 803 809 823 71000 flags: phsync,
> pvsync; type: preferred, driver
>   #1 1920x1080 60.00 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags:
> phsync, pvsync; type: driver
> [...]
> 
> root:~> modetest -Mstarfive -s 116:#0 -v
> setting mode 1280x800-59.91Hz on connectors 116, crtc 31
> freq: 60.65Hz
> freq: 59.91Hz
> freq: 59.91Hz
> 
> root:~> modetest -Mstarfive -s 116:#1 -v
> setting mode 1920x1080-60.00Hz on connectors 116, crtc 31
> [   94.535626] rcu: INFO: rcu_sched detected stalls on CPUs/tasks:
> [   94.560985] rcu:     1-...0: (20 ticks this GP)
> idle=c9bc/1/0x4000000000000000 softirq=3869/3871 fqs=1120
> [   94.589532] rcu:     (detected by 3, t=5264 jiffies, g=4645, q=63
> ncpus=4)
> [   94.615335] Task dump for CPU 1:
> [   94.637723] task:modetest        state:R  running task     stack:0
> pid:407   ppid:397    flags:0x00000008
> [   94.667299] Call Trace:
> [   94.689297] [<ffffffff80d1e8fc>] __schedule+0x2a8/0xa52
> [   94.714221] [<ffffffff80d1f100>] schedule+0x5a/0xdc
> [   94.738626] [<ffffffff80d25a14>] schedule_timeout+0x220/0x2a6
> [   94.763762] [<ffffffff80d2037a>] wait_for_completion+0xfe/0x126
> [   94.789073] [<ffffffff8002ffe4>] kthread_flush_worker+0x82/0xa0
> 
> 
>> -----Original Message-----
>> From: dri-devel <dri-devel-bounces@lists.freedesktop.org> On Behalf Of
>> Keith Zhao
>> Sent: Friday, June 2, 2023 4:41 PM
>> To: dri-devel@lists.freedesktop.org; devicetree@vger.kernel.org; linux-
>> kernel@vger.kernel.org; linux-riscv@lists.infradead.org; linux-
>> media@vger.kernel.org; linaro-mm-sig@lists.linaro.org
>> Cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>; Sumit Semwal
>> <sumit.semwal@linaro.org>; Emil Renner Berthing <kernel@esmil.dk>;
>> Shengyang Chen <shengyang.chen@starfivetech.com>; Conor Dooley
>> <conor+dt@kernel.org>; Albert Ou <aou@eecs.berkeley.edu>; Thomas
>> Zimmermann <tzimmermann@suse.de>; Jagan Teki <jagan@edgeble.ai>; Rob
>> Herring <robh+dt@kernel.org>; Chris Morgan <macromorgan@hotmail.com>; Paul
>> Walmsley <paul.walmsley@sifive.com>; Keith Zhao
>> <keith.zhao@starfivetech.com>; Bjorn Andersson <andersson@kernel.org>;
>> Changhuang Liang <changhuang.liang@starfivetech.com>; Jack Zhu
>> <jack.zhu@starfivetech.com>; Palmer Dabbelt <palmer@dabbelt.com>; Shawn
>> Guo <shawnguo@kernel.org>; christian.koenig@amd.com
>> Subject: [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver
>> 
>> Add HDMI dirver for StarFive SoC JH7110.
>> 
>> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
>> ---
>>  drivers/gpu/drm/verisilicon/Kconfig         |  11 +
>>  drivers/gpu/drm/verisilicon/Makefile        |   1 +
>>  drivers/gpu/drm/verisilicon/starfive_hdmi.c | 928 ++++++++++++++++++++
>> drivers/gpu/drm/verisilicon/starfive_hdmi.h | 296 +++++++
>>  drivers/gpu/drm/verisilicon/vs_drv.c        |   6 +
>>  drivers/gpu/drm/verisilicon/vs_drv.h        |   4 +
>>  6 files changed, 1246 insertions(+)
>>  create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.c
>>  create mode 100644 drivers/gpu/drm/verisilicon/starfive_hdmi.h
> 
> [...]
> 
>> diff --git a/drivers/gpu/drm/verisilicon/starfive_hdmi.c
>> b/drivers/gpu/drm/verisilicon/starfive_hdmi.c
>> new file mode 100644
>> index 000000000000..128ecca03309
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/starfive_hdmi.c
>> @@ -0,0 +1,928 @@
> 
> [...]
> 
>> +static int starfive_hdmi_setup(struct starfive_hdmi *hdmi,
>> +			       struct drm_display_mode *mode) {
> 
> [...]
> 
>> +	return 0;
>> +}
>> +
>> +static void starfive_hdmi_encoder_mode_set(struct drm_encoder *encoder,
>> +					   struct drm_display_mode *mode,
>> +					   struct drm_display_mode
> *adj_mode) {
>> +	struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
>> +
>> +	starfive_hdmi_setup(hdmi, adj_mode);
> 
> When starfive_hdmi_setup runs here,
> when changing the mode, a problem occurs because try to write a value to reg
> in a state that is not resumed after suspend.
> 
>> +
>> +	memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi-
>> >previous_mode)); }
>> +
>> +static void starfive_hdmi_encoder_enable(struct drm_encoder *encoder) {
>> +	struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
>> +
>> +	pm_runtime_get_sync(hdmi->dev);
> 
> So if move the call point of starfive_hdmi_setup here, it works normally.
> 
>> +}
> 
> Best regards,
> Hoegeun
> 
> 

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

* Re: [PATCH 6/9] drm/verisilicon: Add drm crtc funcs
  2023-06-02  7:40 ` [PATCH 6/9] drm/verisilicon: Add drm crtc funcs Keith Zhao
@ 2023-06-30 11:55   ` Thomas Zimmermann
  2023-07-21 11:57     ` Keith Zhao
  0 siblings, 1 reply; 46+ messages in thread
From: Thomas Zimmermann @ 2023-06-30 11:55 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Heiko Stuebner, Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu,
	Shengyang Chen, Changhuang Liang


[-- Attachment #1.1: Type: text/plain, Size: 18641 bytes --]

Hi

Am 02.06.23 um 09:40 schrieb Keith Zhao:
> Add crtc driver which implements crtc related operation functions.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>   drivers/gpu/drm/verisilicon/Makefile  |   1 +
>   drivers/gpu/drm/verisilicon/vs_crtc.c | 388 ++++++++++++++++++++++++++
>   drivers/gpu/drm/verisilicon/vs_crtc.h |  74 +++++
>   drivers/gpu/drm/verisilicon/vs_type.h |  72 +++++
>   4 files changed, 535 insertions(+)
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
> 
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> index 38254dc5d98d..bae5fbab9bbb 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -1,6 +1,7 @@
>   # SPDX-License-Identifier: GPL-2.0
>   
>   vs_drm-objs := vs_drv.o \
> +		vs_crtc.o \
>   		vs_fb.o \
>   		vs_gem.o
>   
> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c
> new file mode 100644
> index 000000000000..a9e742d7bd1a
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.c
> @@ -0,0 +1,388 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + *
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/debugfs.h>
> +#include <linux/media-bus-format.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_gem_atomic_helper.h>
> +#include <drm/drm_vblank.h>
> +#include <drm/vs_drm.h>
> +
> +#include "vs_crtc.h"
> +
> +void vs_crtc_destroy(struct drm_crtc *crtc)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +
> +	drm_crtc_cleanup(crtc);
> +	kfree(vs_crtc);
> +}
> +
> +static void vs_crtc_reset(struct drm_crtc *crtc)
> +{
> +	struct vs_crtc_state *state;
> +
> +	if (crtc->state) {
> +		__drm_atomic_helper_crtc_destroy_state(crtc->state);
> +
> +		state = to_vs_crtc_state(crtc->state);
> +		kfree(state);
> +		crtc->state = NULL;
> +	}
> +
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return;
> +
> +	__drm_atomic_helper_crtc_reset(crtc, &state->base);
> +
> +	state->sync_mode = VS_SINGLE_DC;
> +	state->output_fmt = MEDIA_BUS_FMT_RBG888_1X24;
> +	state->encoder_type = DRM_MODE_ENCODER_NONE;
> +}
> +
> +static struct drm_crtc_state *
> +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
> +{
> +	struct vs_crtc_state *ori_state;
> +	struct vs_crtc_state *state;
> +
> +	if (WARN_ON(!crtc->state))
> +		return NULL;

I'd leave this check out. IIRC, crtc->state not supposed to be NULL 
here. Rather let it crash.

> +
> +	ori_state = to_vs_crtc_state(crtc->state);
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return NULL;
> +
> +	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
> +
> +	state->sync_mode = ori_state->sync_mode;
> +	state->output_fmt = ori_state->output_fmt;
> +	state->encoder_type = ori_state->encoder_type;
> +	state->bg_color = ori_state->bg_color;
> +	state->bpp = ori_state->bpp;
> +	state->sync_enable = ori_state->sync_enable;
> +	state->dither_enable = ori_state->dither_enable;
> +	state->underflow = ori_state->underflow;
> +
> +	return &state->base;
> +}
> +
> +static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
> +					 struct drm_crtc_state *state)
> +{
> +	__drm_atomic_helper_crtc_destroy_state(state);
> +	kfree(to_vs_crtc_state(state));
> +}
> +
> +static int vs_crtc_atomic_set_property(struct drm_crtc *crtc,
> +				       struct drm_crtc_state *state,
> +				       struct drm_property *property,
> +				       uint64_t val)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(state);
> +
> +	if (property == vs_crtc->sync_mode)
> +		vs_crtc_state->sync_mode = val;
> +	else if (property == vs_crtc->mmu_prefetch)
> +		vs_crtc_state->mmu_prefetch = val;
> +	else if (property == vs_crtc->bg_color)
> +		vs_crtc_state->bg_color = val;
> +	else if (property == vs_crtc->panel_sync)
> +		vs_crtc_state->sync_enable = val;
> +	else if (property == vs_crtc->dither)
> +		vs_crtc_state->dither_enable = val;
> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int vs_crtc_atomic_get_property(struct drm_crtc *crtc,
> +				       const struct drm_crtc_state *state,
> +				       struct drm_property *property,
> +				       uint64_t *val)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +	const struct vs_crtc_state *vs_crtc_state =
> +		container_of(state, const struct vs_crtc_state, base);
> +
> +	if (property == vs_crtc->sync_mode)
> +		*val = vs_crtc_state->sync_mode;
> +	else if (property == vs_crtc->mmu_prefetch)
> +		*val = vs_crtc_state->mmu_prefetch;
> +	else if (property == vs_crtc->bg_color)
> +		*val = vs_crtc_state->bg_color;
> +	else if (property == vs_crtc->panel_sync)
> +		*val = vs_crtc_state->sync_enable;
> +	else if (property == vs_crtc->dither)
> +		*val = vs_crtc_state->dither_enable;
> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int vs_crtc_late_register(struct drm_crtc *crtc)
> +{
> +	return 0;
> +}
> +
> +static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +
> +	vs_crtc->funcs->enable_vblank(vs_crtc->dev, true);
> +
> +	return 0;
> +}
> +
> +static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +
> +	vs_crtc->funcs->enable_vblank(vs_crtc->dev, false);
> +}
> +
> +static const struct drm_crtc_funcs vs_crtc_funcs = {
> +	.set_config		= drm_atomic_helper_set_config,
> +	.destroy		= vs_crtc_destroy,
> +	.page_flip		= drm_atomic_helper_page_flip,
> +	.reset			= vs_crtc_reset,
> +	.atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
> +	.atomic_destroy_state	= vs_crtc_atomic_destroy_state,
> +	.atomic_set_property	= vs_crtc_atomic_set_property,
> +	.atomic_get_property	= vs_crtc_atomic_get_property,
> +	.late_register		= vs_crtc_late_register,
> +	.enable_vblank		= vs_crtc_enable_vblank,
> +	.disable_vblank		= vs_crtc_disable_vblank,
> +};
> +
> +static u8 cal_pixel_bits(u32 bus_format)
> +{
> +	u8 bpp;
> +
> +	switch (bus_format) {
> +	case MEDIA_BUS_FMT_RGB565_1X16:
> +	case MEDIA_BUS_FMT_UYVY8_1X16:
> +		bpp = 16;
> +		break;
> +	case MEDIA_BUS_FMT_RGB666_1X18:
> +	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
> +		bpp = 18;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY10_1X20:
> +		bpp = 20;
> +		break;
> +	case MEDIA_BUS_FMT_BGR888_1X24:
> +	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> +	case MEDIA_BUS_FMT_YUV8_1X24:
> +		bpp = 24;
> +		break;
> +	case MEDIA_BUS_FMT_RGB101010_1X30:
> +	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> +	case MEDIA_BUS_FMT_YUV10_1X30:
> +		bpp = 30;
> +		break;
> +	default:
> +		bpp = 24;
> +		break;
> +	}
> +
> +	return bpp;
> +}
> +
> +static bool vs_crtc_mode_fixup(struct drm_crtc *crtc,
> +			       const struct drm_display_mode *mode,
> +			       struct drm_display_mode *adjusted_mode)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +
> +	return vs_crtc->funcs->mode_fixup(vs_crtc->dev, mode, adjusted_mode);
> +}
> +
> +static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
> +				  struct drm_atomic_state *state)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
> +
> +	vs_crtc_state->bpp = cal_pixel_bits(vs_crtc_state->output_fmt);
> +
> +	vs_crtc->funcs->enable(vs_crtc->dev, crtc);
> +	drm_crtc_vblank_on(crtc);
> +}
> +
> +static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
> +				   struct drm_atomic_state *state)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +
> +	drm_crtc_vblank_off(crtc);
> +
> +	vs_crtc->funcs->disable(vs_crtc->dev, crtc);
> +
> +	if (crtc->state->event && !crtc->state->active) {
> +		spin_lock_irq(&crtc->dev->event_lock);
> +		drm_crtc_send_vblank_event(crtc, crtc->state->event);
> +		spin_unlock_irq(&crtc->dev->event_lock);
> +
> +		crtc->state->event = NULL;
> +	}
> +}
> +
> +static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
> +				 struct drm_atomic_state *state)
> +{
> +	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
> +									  crtc);
> +
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +	struct device *dev = vs_crtc->dev;
> +	struct drm_property_blob *blob = crtc->state->gamma_lut;
> +	struct drm_color_lut *lut;
> +
> +	if (crtc_state->color_mgmt_changed) {
> +		if (blob && blob->length) {
> +			lut = blob->data;
> +			vs_crtc->funcs->set_gamma(dev, crtc, lut,
> +						  blob->length / sizeof(*lut));
> +			vs_crtc->funcs->enable_gamma(dev, crtc, true);
> +		} else {
> +			vs_crtc->funcs->enable_gamma(dev, crtc, false);
> +		}
> +	}
> +}
> +
> +static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
> +				 struct drm_atomic_state *state)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +	struct drm_pending_vblank_event *event = crtc->state->event;
> +
> +	vs_crtc->funcs->commit(vs_crtc->dev);
> +
> +	if (event) {
> +		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
> +
> +		spin_lock_irq(&crtc->dev->event_lock);
> +		drm_crtc_arm_vblank_event(crtc, event);
> +		spin_unlock_irq(&crtc->dev->event_lock);
> +		crtc->state->event = NULL;
> +	}
> +}
> +
> +static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
> +	.mode_fixup = vs_crtc_mode_fixup,
> +	.atomic_enable	= vs_crtc_atomic_enable,
> +	.atomic_disable = vs_crtc_atomic_disable,
> +	.atomic_begin	= vs_crtc_atomic_begin,
> +	.atomic_flush	= vs_crtc_atomic_flush,
> +};
> +
> +static const struct drm_prop_enum_list vs_sync_mode_enum_list[] = {
> +	{ VS_SINGLE_DC,			"single dc mode" },
> +	{ VS_MULTI_DC_PRIMARY,		"primary dc for multi dc mode" },
> +	{ VS_MULTI_DC_SECONDARY,	"secondary dc for multi dc mode" },
> +};
> +
> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> +			       struct vs_dc_info *info)
> +{
> +	struct vs_crtc *crtc;
> +	int ret;
> +
> +	if (!info)
> +		return NULL;
> +
> +	crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
> +	if (!crtc)
> +		return NULL;
> +
> +	ret = drm_crtc_init_with_planes(drm_dev, &crtc->base,
> +					NULL, NULL, &vs_crtc_funcs,
> +					info->name ? info->name : NULL);
> +	if (ret)
> +		goto err_free_crtc;
> +
> +	drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
> +
> +	/* Set up the crtc properties */
> +	if (info->pipe_sync) {
> +		crtc->sync_mode = drm_property_create_enum(drm_dev, 0,
> +							   "SYNC_MODE",
> +							    vs_sync_mode_enum_list,
> +							    ARRAY_SIZE(vs_sync_mode_enum_list));
> +
> +		if (!crtc->sync_mode)
> +			goto err_cleanup_crts;
> +
> +		drm_object_attach_property(&crtc->base.base,
> +					   crtc->sync_mode,
> +					   VS_SINGLE_DC);
> +	}
> +
> +	if (info->gamma_size) {
> +		ret = drm_mode_crtc_set_gamma_size(&crtc->base,
> +						   info->gamma_size);
> +		if (ret)
> +			goto err_cleanup_crts;
> +
> +		drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
> +					   info->gamma_size);
> +	}
> +
> +	if (info->background) {
> +		crtc->bg_color = drm_property_create_range(drm_dev, 0,
> +							   "BG_COLOR", 0, 0xffffffff);
> +
> +		if (!crtc->bg_color)
> +			goto err_cleanup_crts;
> +
> +		drm_object_attach_property(&crtc->base.base, crtc->bg_color, 0);
> +	}
> +
> +	if (info->panel_sync) {
> +		crtc->panel_sync = drm_property_create_bool(drm_dev, 0, "SYNC_ENABLED");
> +
> +		if (!crtc->panel_sync)
> +			goto err_cleanup_crts;
> +
> +		drm_object_attach_property(&crtc->base.base, crtc->panel_sync, 0);
> +	}
> +
> +	crtc->dither = drm_property_create_bool(drm_dev, 0, "DITHER_ENABLED");
> +	if (!crtc->dither)
> +		goto err_cleanup_crts;
> +
> +	drm_object_attach_property(&crtc->base.base, crtc->dither, 0);
> +
> +	crtc->max_bpc = info->max_bpc;
> +	crtc->color_formats = info->color_formats;
> +	return crtc;
> +
> +err_cleanup_crts:
> +	drm_crtc_cleanup(&crtc->base);
> +
> +err_free_crtc:
> +	kfree(crtc);
> +	return NULL;
> +}
> +
> +void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow)
> +{
> +	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
> +
> +	drm_crtc_handle_vblank(crtc);
> +
> +	vs_crtc_state->underflow = underflow;
> +}
> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h b/drivers/gpu/drm/verisilicon/vs_crtc.h
> new file mode 100644
> index 000000000000..33b3b14249ce
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_CRTC_H__
> +#define __VS_CRTC_H__
> +
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +
> +#include "vs_type.h"
> +
> +struct vs_crtc_funcs {
> +	void (*enable)(struct device *dev, struct drm_crtc *crtc);
> +	void (*disable)(struct device *dev, struct drm_crtc *crtc);
> +	bool (*mode_fixup)(struct device *dev,
> +			   const struct drm_display_mode *mode,
> +			   struct drm_display_mode *adjusted_mode);
> +	void (*set_gamma)(struct device *dev, struct drm_crtc *crtc,
> +			  struct drm_color_lut *lut, unsigned int size);
> +	void (*enable_gamma)(struct device *dev, struct drm_crtc *crtc,
> +			     bool enable);
> +	void (*enable_vblank)(struct device *dev, bool enable);
> +	void (*commit)(struct device *dev);
> +};

Why is this here? You are reproducing our interface with an internal 
interface. I know where this leads to: you have multiple chipset 
revisions and each has its own implemenation of these internal interfaces.

That will absolutely come back to haunt you in the long rung: the more 
chip revisions you support, the more obscure these internal interfaces 
and implentations become. And you won't be able to change these 
callbacks, as that affects all revisions. We've seen this with a few 
drivers. It will become unmaintainable.

A better approach is to treat DRM's atomic callback funcs and atomic 
helper funcs as your interface for each chip revision. So for each 
model, you implement a separate modesetting pipeline. When you add a new 
chip revision, you copy the previous chip's code into a new file and 
adopt it. If you find comon code among individual revisions, you can put 
it into a shared helper.  With this design, each chip revision stands on 
its own.

I suggest to study the mgag200 driver. It detects the chip revision very 
early and builds a chip-specific modesetting pipline. Although each chip 
is handled separately, a lot of shared code is in helpers. So the size 
of the driver remains small.

> +
> +struct vs_crtc_state {
> +	struct drm_crtc_state base;
> +
> +	u32 sync_mode;
> +	u32 output_fmt;
> +	u32 bg_color;
> +	u8 encoder_type;
> +	u8 mmu_prefetch;
> +	u8 bpp;
> +	bool sync_enable;
> +	bool dither_enable;
> +	bool underflow;
> +};
> +
> +struct vs_crtc {
> +	struct drm_crtc base;
> +	struct device *dev;

That's stored in base.dev already.

> +	struct drm_pending_vblank_event *event;

That's in drm_crtc_state.event already.

> +	unsigned int max_bpc;
> +	unsigned int color_formats; /* supported color format */

These come from a vs_dc_info. Why not just store a pointer to the info 
instead?

> +
> +	struct drm_property *sync_mode;
> +	struct drm_property *mmu_prefetch;
> +	struct drm_property *bg_color;
> +	struct drm_property *panel_sync;
> +	struct drm_property *dither;
> +
> +	const struct vs_crtc_funcs *funcs;

Please, see my rant why that's not a good idea.

> +};
> +
> +void vs_crtc_destroy(struct drm_crtc *crtc);
> +
> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> +			       struct vs_dc_info *info);
> +void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow);
> +
> +static inline struct vs_crtc *to_vs_crtc(struct drm_crtc *crtc)
> +{
> +	return container_of(crtc, struct vs_crtc, base);
> +}
> +
> +static inline struct vs_crtc_state *
> +to_vs_crtc_state(struct drm_crtc_state *state)
> +{
> +	return container_of(state, struct vs_crtc_state, base);
> +}
> +#endif /* __VS_CRTC_H__ */
> diff --git a/drivers/gpu/drm/verisilicon/vs_type.h b/drivers/gpu/drm/verisilicon/vs_type.h
> new file mode 100644
> index 000000000000..6f8db65a703d
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_type.h
> @@ -0,0 +1,72 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_TYPE_H__
> +#define __VS_TYPE_H__
> +
> +#include <linux/version.h>

Why?

Best regards
Thomas

> +
> +#include <drm/drm_plane.h>
> +#include <drm/drm_plane_helper.h>
> +
> +struct vs_plane_info {
> +	const char *name;
> +	u8 id;
> +	enum drm_plane_type type;
> +	unsigned int num_formats;
> +	const u32 *formats;
> +	u8 num_modifiers;
> +	const u64 *modifiers;
> +	unsigned int min_width;
> +	unsigned int min_height;
> +	unsigned int max_width;
> +	unsigned int max_height;
> +	unsigned int rotation;
> +	unsigned int blend_mode;
> +	unsigned int color_encoding;
> +
> +	/* 0 means no de-gamma LUT */
> +	unsigned int degamma_size;
> +
> +	int min_scale; /* 16.16 fixed point */
> +	int max_scale; /* 16.16 fixed point */
> +
> +	/* default zorder value,
> +	 * and 255 means unsupported zorder capability
> +	 */
> +	u8	 zpos;
> +
> +	bool watermark;
> +	bool color_mgmt;
> +	bool roi;
> +};
> +
> +struct vs_dc_info {
> +	const char *name;
> +
> +	u8 panel_num;
> +
> +	/* planes */
> +	u8 plane_num;
> +	const struct vs_plane_info *planes;
> +
> +	u8 layer_num;
> +	unsigned int max_bpc;
> +	unsigned int color_formats;
> +
> +	/* 0 means no gamma LUT */
> +	u16 gamma_size;
> +	u8 gamma_bits;
> +
> +	u16 pitch_alignment;
> +
> +	bool pipe_sync;
> +	bool mmu_prefetch;
> +	bool background;
> +	bool panel_sync;
> +	bool cap_dec;
> +};
> +
> +#endif /* __VS_TYPE_H__ */

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH 7/9] drm/verisilicon: Add drm plane funcs
  2023-06-02  7:40 ` [PATCH 7/9] drm/verisilicon: Add drm plane funcs Keith Zhao
@ 2023-06-30 12:14   ` Thomas Zimmermann
  2023-07-10 16:46   ` Shengyu Qu
  1 sibling, 0 replies; 46+ messages in thread
From: Thomas Zimmermann @ 2023-06-30 12:14 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Heiko Stuebner, Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu,
	Shengyang Chen, Changhuang Liang


[-- Attachment #1.1: Type: text/plain, Size: 18104 bytes --]



Am 02.06.23 um 09:40 schrieb Keith Zhao:
> Implement plane functions for the DRM driver.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>   drivers/gpu/drm/verisilicon/Makefile   |   3 +-
>   drivers/gpu/drm/verisilicon/vs_plane.c | 440 +++++++++++++++++++++++++
>   drivers/gpu/drm/verisilicon/vs_plane.h |  74 +++++
>   3 files changed, 516 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
> 
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> index bae5fbab9bbb..d96ad9399fc7 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -3,7 +3,8 @@
>   vs_drm-objs := vs_drv.o \
>   		vs_crtc.o \
>   		vs_fb.o \
> -		vs_gem.o
> +		vs_gem.o \
> +		vs_plane.o
>   
>   obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
>   
> diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c
> new file mode 100644
> index 000000000000..7b0dcef232ae
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_plane.c
> @@ -0,0 +1,440 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_blend.h>
> +#include <drm/drm_gem_dma_helper.h>
> +#include <drm/drm_fb_dma_helper.h>
> +#include <drm/drm_framebuffer.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include <drm/vs_drm.h>
> +
> +#include "vs_crtc.h"
> +#include "vs_fb.h"
> +#include "vs_gem.h"
> +#include "vs_plane.h"
> +#include "vs_type.h"
> +
> +void vs_plane_destory(struct drm_plane *plane)

'_destroy'

> +{
> +	struct vs_plane *vs_plane = to_vs_plane(plane);
> +
> +	drm_plane_cleanup(plane);
> +	kfree(vs_plane);
> +}

I think we have helpers to do the cleanup.

As I mentioned in another review, you should switch to managed code 
instead of using your own memory management. If your modesetting 
pipeline is static, you can use drmm_mode_config_init() and it will 
release all pipeline structs for you. The related memory can allowed as 
part of the device instance.  If the pipeline is dynamic, you can use 
drmm_ helpers to allocate conenctors, crtcs, planes, etc.  IIRC, the vc4 
driver does something like that.

> +
> +static void vs_plane_reset(struct drm_plane *plane)
> +{
> +	struct vs_plane_state *state;
> +	struct vs_plane *vs_plane = to_vs_plane(plane);
> +
> +	if (plane->state) {
> +		__drm_atomic_helper_plane_destroy_state(plane->state);
> +
> +		state = to_vs_plane_state(plane->state);
> +		kfree(state);
> +		plane->state = NULL;
> +	}
> +
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return;
> +
> +	__drm_atomic_helper_plane_reset(plane, &state->base);
> +
> +	state->degamma = VS_DEGAMMA_DISABLE;
> +	state->degamma_changed = false;
> +	state->base.zpos = vs_plane->id;
> +
> +	memset(&state->status, 0, sizeof(state->status));

Should already be 0 from kzalloc().

> +}
> +
> +static void _vs_plane_duplicate_blob(struct vs_plane_state *state,
> +				     struct vs_plane_state *ori_state)
> +{
> +	state->watermark = ori_state->watermark;
> +	state->color_mgmt = ori_state->color_mgmt;
> +	state->roi = ori_state->roi;
> +
> +	if (state->watermark)
> +		drm_property_blob_get(state->watermark);
> +	if (state->color_mgmt)
> +		drm_property_blob_get(state->color_mgmt);
> +	if (state->roi)
> +		drm_property_blob_get(state->roi);
> +}
> +
> +static int
> +_vs_plane_set_property_blob_from_id(struct drm_device *dev,
> +				    struct drm_property_blob **blob,
> +				    u64 blob_id,
> +				    size_t expected_size)
> +{
> +	struct drm_property_blob *new_blob = NULL;
> +
> +	if (blob_id) {
> +		new_blob = drm_property_lookup_blob(dev, blob_id);
> +		if (!new_blob)
> +			return -EINVAL;
> +
> +		if (new_blob->length != expected_size) {
> +			drm_property_blob_put(new_blob);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	drm_property_replace_blob(blob, new_blob);
> +	drm_property_blob_put(new_blob);
> +
> +	return 0;
> +}
> +
> +static struct drm_plane_state *
> +vs_plane_atomic_duplicate_state(struct drm_plane *plane)
> +{
> +	struct vs_plane_state *ori_state;
> +	struct vs_plane_state *state;
> +
> +	if (WARN_ON(!plane->state))
> +		return NULL;
> +
> +	ori_state = to_vs_plane_state(plane->state);
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return NULL;
> +
> +	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
> +
> +	state->degamma = ori_state->degamma;
> +	state->degamma_changed = ori_state->degamma_changed;
> +
> +	_vs_plane_duplicate_blob(state, ori_state);
> +	memcpy(&state->status, &ori_state->status, sizeof(ori_state->status));
> +
> +	return &state->base;
> +}
> +
> +static void vs_plane_atomic_destroy_state(struct drm_plane *plane,
> +					  struct drm_plane_state *state)
> +{
> +	struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
> +
> +	__drm_atomic_helper_plane_destroy_state(state);
> +
> +	drm_property_blob_put(vs_plane_state->watermark);
> +	drm_property_blob_put(vs_plane_state->color_mgmt);
> +	drm_property_blob_put(vs_plane_state->roi);
> +	kfree(vs_plane_state);
> +}
> +
> +static int vs_plane_atomic_set_property(struct drm_plane *plane,
> +					struct drm_plane_state *state,
> +					struct drm_property *property,
> +					uint64_t val)
> +{
> +	struct drm_device *dev = plane->dev;
> +	struct vs_plane *vs_plane = to_vs_plane(plane);
> +	struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
> +	int ret = 0;
> +
> +	if (property == vs_plane->degamma_mode) {
> +		if (vs_plane_state->degamma != val) {
> +			vs_plane_state->degamma = val;
> +			vs_plane_state->degamma_changed = true;
> +		} else {
> +			vs_plane_state->degamma_changed = false;
> +		}
> +	} else if (property == vs_plane->watermark_prop) {
> +		ret = _vs_plane_set_property_blob_from_id(dev,
> +							  &vs_plane_state->watermark,
> +							  val,
> +							  sizeof(struct drm_vs_watermark));
> +		return ret;
> +	} else if (property == vs_plane->color_mgmt_prop) {
> +		ret = _vs_plane_set_property_blob_from_id(dev,
> +							  &vs_plane_state->color_mgmt,
> +							  val,
> +							  sizeof(struct drm_vs_color_mgmt));
> +		return ret;
> +	} else if (property == vs_plane->roi_prop) {
> +		ret = _vs_plane_set_property_blob_from_id(dev,
> +							  &vs_plane_state->roi,
> +							  val,
> +							  sizeof(struct drm_vs_roi));
> +		return ret;
> +	} else {
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vs_plane_atomic_get_property(struct drm_plane *plane,
> +					const struct drm_plane_state *state,
> +					struct drm_property *property,
> +					uint64_t *val)
> +{
> +	struct vs_plane *vs_plane = to_vs_plane(plane);
> +	const struct vs_plane_state *vs_plane_state =
> +		container_of(state, const struct vs_plane_state, base);
> +
> +	if (property == vs_plane->degamma_mode)
> +		*val = vs_plane_state->degamma;
> +	else if (property == vs_plane->watermark_prop)
> +		*val = (vs_plane_state->watermark) ?
> +					vs_plane_state->watermark->base.id : 0;
> +	else if (property == vs_plane->color_mgmt_prop)
> +		*val = (vs_plane_state->color_mgmt) ?
> +					vs_plane_state->color_mgmt->base.id : 0;
> +	else if (property == vs_plane->roi_prop)
> +		*val = (vs_plane_state->roi) ?
> +					vs_plane_state->roi->base.id : 0;
> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static bool vs_format_mod_supported(struct drm_plane *plane,
> +				    u32 format,
> +				    u64 modifier)
> +{
> +	int i;
> +
> +       /* We always have to allow these modifiers:

Indention seems off.

> +	* 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
> +	* 2. Not passing any modifiers is the same as explicitly passing INVALID.
> +	*/
> +	if (modifier == DRM_FORMAT_MOD_LINEAR)
> +		return true;
> +
> +	/* Check that the modifier is on the list of the plane's supported modifiers. */
> +	for (i = 0; i < plane->modifier_count; i++) {
> +		if (modifier == plane->modifiers[i])
> +			break;
> +	}
> +
> +	if (i == plane->modifier_count)
> +		return false;
> +
> +	return true;
> +}
> +
> +const struct drm_plane_funcs vs_plane_funcs = {
> +	.update_plane		= drm_atomic_helper_update_plane,
> +	.disable_plane		= drm_atomic_helper_disable_plane,
> +	.destroy		= vs_plane_destory,
> +	.reset			= vs_plane_reset,
> +	.atomic_duplicate_state = vs_plane_atomic_duplicate_state,
> +	.atomic_destroy_state	= vs_plane_atomic_destroy_state,
> +	.atomic_set_property	= vs_plane_atomic_set_property,
> +	.atomic_get_property	= vs_plane_atomic_get_property,
> +	.format_mod_supported	= vs_format_mod_supported,
> +};
> +
> +static unsigned char vs_get_plane_number(struct drm_framebuffer *fb)
> +{
> +	const struct drm_format_info *info;
> +
> +	if (!fb)
> +		return 0;
> +
> +	info = drm_format_info(fb->format->format);
> +	if (!info || info->num_planes > MAX_NUM_PLANES)
> +		return 0;
> +
> +	return info->num_planes;
> +}
> +
> +static int vs_plane_atomic_check(struct drm_plane *plane,
> +				 struct drm_atomic_state *state)
> +{
> +	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> +										 plane);
> +	struct vs_plane *vs_plane = to_vs_plane(plane);
> +	struct drm_framebuffer *fb = new_plane_state->fb;
> +	struct drm_crtc *crtc = new_plane_state->crtc;
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +
> +	if (!crtc || !fb)
> +		return 0;
> +
> +	//return vs_plane->funcs->check(vs_crtc->dev, vs_plane, new_plane_state);
> +	return vs_plane->funcs->check(vs_crtc->dev, plane, state);
> +}
> +
> +static void vs_plane_atomic_update(struct drm_plane *plane,
> +				   struct drm_atomic_state *state)
> +{
> +	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
> +									   plane);
> +	unsigned char i, num_planes;
> +	struct drm_framebuffer *fb;
> +	struct vs_plane *vs_plane = to_vs_plane(plane);
> +	//struct drm_plane_state *state = plane->state;
> +	struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
> +	struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
> +	//struct drm_format_name_buf *name = &plane_state->status.format_name;
> +
> +	if (!new_state->fb || !new_state->crtc)
> +		return;
> +
> +	fb = new_state->fb;
> +
> +	num_planes = vs_get_plane_number(fb);
> +
> +	for (i = 0; i < num_planes; i++) {
> +		struct vs_gem_object *vs_obj;
> +
> +		vs_obj = vs_fb_get_gem_obj(fb, i);
> +		vs_plane->dma_addr[i] = vs_obj->iova + fb->offsets[i];
> +	}
> +
> +	plane_state->status.src = drm_plane_state_src(new_state);
> +	plane_state->status.dest = drm_plane_state_dest(new_state);
> +
> +	vs_plane->funcs->update(vs_crtc->dev, vs_plane, plane, state);
> +}
> +
> +static void vs_plane_atomic_disable(struct drm_plane *plane,
> +				    struct drm_atomic_state *state)
> +{
> +	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
> +										   plane);
> +	struct vs_plane *vs_plane = to_vs_plane(plane);
> +	struct vs_crtc *vs_crtc = to_vs_crtc(old_state->crtc);
> +
> +	vs_plane->funcs->disable(vs_crtc->dev, vs_plane, old_state);
> +}
> +
> +const struct drm_plane_helper_funcs vs_plane_helper_funcs = {
> +	.atomic_check	= vs_plane_atomic_check,
> +	.atomic_update	= vs_plane_atomic_update,
> +	.atomic_disable = vs_plane_atomic_disable,
> +};
> +
> +static const struct drm_prop_enum_list vs_degamma_mode_enum_list[] = {
> +	{ VS_DEGAMMA_DISABLE,	"disabled" },
> +	{ VS_DEGAMMA_BT709, "preset degamma for BT709" },
> +	{ VS_DEGAMMA_BT2020,	"preset degamma for BT2020" },
> +};
> +
> +struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
> +				 struct vs_plane_info *info,
> +				 unsigned int layer_num,
> +				 unsigned int possible_crtcs)
> +{
> +	struct vs_plane *plane;
> +	int ret;
> +
> +	if (!info)
> +		return NULL;
> +
> +	plane = kzalloc(sizeof(*plane), GFP_KERNEL);
> +	if (!plane)
> +		return NULL;
> +
> +	ret = drm_universal_plane_init(drm_dev, &plane->base, possible_crtcs,
> +				       &vs_plane_funcs, info->formats,
> +				       info->num_formats, info->modifiers, info->type,
> +				       info->name ? info->name : NULL);
> +	if (ret)
> +		goto err_free_plane;
> +
> +	drm_plane_helper_add(&plane->base, &vs_plane_helper_funcs);
> +
> +	/* Set up the plane properties */
> +	if (info->degamma_size) {
> +		plane->degamma_mode =
> +		drm_property_create_enum(drm_dev, 0,
> +					 "DEGAMMA_MODE",
> +					 vs_degamma_mode_enum_list,
> +					 ARRAY_SIZE(vs_degamma_mode_enum_list));
> +
> +		if (!plane->degamma_mode)
> +			goto error_cleanup_plane;
> +
> +		drm_object_attach_property(&plane->base.base,
> +					   plane->degamma_mode,
> +					   VS_DEGAMMA_DISABLE);
> +	}
> +
> +	if (info->rotation) {
> +		ret = drm_plane_create_rotation_property(&plane->base,
> +							 DRM_MODE_ROTATE_0,
> +							 info->rotation);
> +		if (ret)
> +			goto error_cleanup_plane;
> +	}
> +
> +	if (info->blend_mode) {
> +		ret = drm_plane_create_blend_mode_property(&plane->base,
> +							   info->blend_mode);
> +		if (ret)
> +			goto error_cleanup_plane;
> +		ret = drm_plane_create_alpha_property(&plane->base);
> +		if (ret)
> +			goto error_cleanup_plane;
> +	}
> +
> +	if (info->color_encoding) {
> +		ret = drm_plane_create_color_properties(&plane->base,
> +							info->color_encoding,
> +							BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
> +							DRM_COLOR_YCBCR_BT709,
> +							DRM_COLOR_YCBCR_LIMITED_RANGE);
> +		if (ret)
> +			goto error_cleanup_plane;
> +	}
> +
> +	if (info->zpos != 255) {
> +		ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0,
> +						     layer_num - 1);
> +		if (ret)
> +			goto error_cleanup_plane;
> +	} else {
> +		ret = drm_plane_create_zpos_immutable_property(&plane->base,
> +							       info->zpos);
> +		if (ret)
> +			goto error_cleanup_plane;
> +	}
> +
> +	if (info->watermark) {
> +		plane->watermark_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
> +							    "WATERMARK", 0);
> +		if (!plane->watermark_prop)
> +			goto error_cleanup_plane;
> +
> +		drm_object_attach_property(&plane->base.base, plane->watermark_prop, 0);
> +	}
> +
> +	if (info->color_mgmt) {
> +		plane->color_mgmt_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
> +							     "COLOR_CONFIG", 0);
> +		if (!plane->color_mgmt_prop)
> +			goto error_cleanup_plane;
> +
> +		drm_object_attach_property(&plane->base.base, plane->color_mgmt_prop, 0);
> +	}
> +
> +	if (info->roi) {
> +		plane->roi_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
> +						      "ROI", 0);
> +		if (!plane->roi_prop)
> +			goto error_cleanup_plane;
> +
> +		drm_object_attach_property(&plane->base.base, plane->roi_prop, 0);
> +	}
> +
> +	return plane;
> +
> +error_cleanup_plane:
> +	drm_plane_cleanup(&plane->base);
> +err_free_plane:
> +	kfree(plane);
> +	return NULL;
> +}
> diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h
> new file mode 100644
> index 000000000000..76ef3c3de045
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_plane.h
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_PLANE_H__
> +#define __VS_PLANE_H__
> +
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include "vs_fb.h"
> +#include "vs_type.h"
> +
> +struct vs_plane;
> +
> +struct vs_plane_funcs {
> +	void (*update)(struct device *dev, struct vs_plane *plane, struct drm_plane *drm_plane,
> +		       struct drm_atomic_state *state);
> +	void (*disable)(struct device *dev, struct vs_plane *plane,
> +			struct drm_plane_state *old_state);
> +	int (*check)(struct device *dev, struct drm_plane *plane,
> +		     struct drm_atomic_state *state);
> +};

Your own internal API. Exactly the same problems as in the CRTC case.

> +
> +struct vs_plane_status {
> +	u32 tile_mode;
> +	struct drm_rect src;
> +	struct drm_rect dest;
> +};
> +
> +struct vs_plane_state {
> +	struct drm_plane_state base;
> +	struct vs_plane_status status; /* for debugfs */
> +
> +	struct drm_property_blob *watermark;
> +	struct drm_property_blob *color_mgmt;
> +	struct drm_property_blob *roi;
> +
> +	u32 degamma;
> +	bool degamma_changed;
> +};
> +
> +struct vs_plane {
> +	struct drm_plane base;
> +	u8 id;

I'm not sure what this is for. It's used for zpos. If that's the 
purpose, I'd rather call it default_zpos.

Best regards
Thomas

> +	dma_addr_t dma_addr[MAX_NUM_PLANES];
> +
> +	struct drm_property *degamma_mode;
> +	struct drm_property *watermark_prop;
> +	struct drm_property *color_mgmt_prop;
> +	struct drm_property *roi_prop;
> +
> +	const struct vs_plane_funcs *funcs;
> +};
> +
> +void vs_plane_destory(struct drm_plane *plane);
> +
> +struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
> +				 struct vs_plane_info *info,
> +				 unsigned int layer_num,
> +				 unsigned int possible_crtcs);
> +
> +static inline struct vs_plane *to_vs_plane(struct drm_plane *plane)
> +{
> +	return container_of(plane, struct vs_plane, base);
> +}
> +
> +static inline struct vs_plane_state *
> +to_vs_plane_state(struct drm_plane_state *state)
> +{
> +	return container_of(state, struct vs_plane_state, base);
> +}
> +#endif /* __VS_PLANE_H__ */

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH 8/9] drm/verisilicon: Add verisilicon dc controller driver
  2023-06-02  7:40 ` [PATCH 8/9] drm/verisilicon: Add verisilicon dc controller driver Keith Zhao
@ 2023-06-30 12:36   ` Thomas Zimmermann
  0 siblings, 0 replies; 46+ messages in thread
From: Thomas Zimmermann @ 2023-06-30 12:36 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Heiko Stuebner, Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu,
	Shengyang Chen, Changhuang Liang


[-- Attachment #1.1: Type: text/plain, Size: 117111 bytes --]



Am 02.06.23 um 09:40 schrieb Keith Zhao:
> Add DC8200 display controller driver for StarFive JH7110 SoC.
> 
> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> ---
>   drivers/gpu/drm/verisilicon/Makefile   |    4 +-
>   drivers/gpu/drm/verisilicon/vs_dc.c    | 1040 ++++++++++++
>   drivers/gpu/drm/verisilicon/vs_dc.h    |   62 +
>   drivers/gpu/drm/verisilicon/vs_dc_hw.c | 2008 ++++++++++++++++++++++++
>   drivers/gpu/drm/verisilicon/vs_dc_hw.h |  496 ++++++
>   drivers/gpu/drm/verisilicon/vs_drv.c   |    2 +
>   6 files changed, 3611 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.c
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.h
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
> 
> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> index d96ad9399fc7..0ed25b5e3062 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -1,7 +1,9 @@
>   # SPDX-License-Identifier: GPL-2.0
>   
> -vs_drm-objs := vs_drv.o \
> +vs_drm-objs := vs_dc_hw.o \
> +		vs_dc.o \
>   		vs_crtc.o \
> +		vs_drv.o \
>   		vs_fb.o \
>   		vs_gem.o \
>   		vs_plane.o
> diff --git a/drivers/gpu/drm/verisilicon/vs_dc.c b/drivers/gpu/drm/verisilicon/vs_dc.c
> new file mode 100644
> index 000000000000..a512aaa57f2f
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_dc.c
> @@ -0,0 +1,1040 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#include <linux/component.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/media-bus-format.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_blend.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_framebuffer.h>
> +#include <drm/drm_vblank.h>
> +#include <drm/vs_drm.h>
> +
> +#include "vs_crtc.h"
> +#include "vs_dc_hw.h"
> +#include "vs_dc.h"
> +#include "vs_drv.h"
> +#include "vs_type.h"
> +
> +static const char * const vout_clocks[] = {
> +	"clk_vout_noc_disp",
> +	"clk_vout_pix0",
> +	"clk_vout_pix1",
> +	"clk_vout_axi",
> +	"clk_vout_core",
> +	"clk_vout_vout_ahb",
> +	"hdmitx0_pixel",
> +	"clk_vout_dc8200",
> +
> +};
> +
> +static const char * const vout_resets[] = {
> +	"rst_vout_axi",
> +	"rst_vout_ahb",
> +	"rst_vout_core",
> +};
> +
> +static inline void update_format(u32 format, u64 mod, struct dc_hw_fb *fb)
> +{
> +	u8 f = FORMAT_A8R8G8B8;
> +
> +	switch (format) {
> +	case DRM_FORMAT_XRGB4444:
> +	case DRM_FORMAT_RGBX4444:
> +	case DRM_FORMAT_XBGR4444:
> +	case DRM_FORMAT_BGRX4444:
> +		f = FORMAT_X4R4G4B4;
> +		break;
> +	case DRM_FORMAT_ARGB4444:
> +	case DRM_FORMAT_RGBA4444:
> +	case DRM_FORMAT_ABGR4444:
> +	case DRM_FORMAT_BGRA4444:
> +		f = FORMAT_A4R4G4B4;
> +		break;
> +	case DRM_FORMAT_XRGB1555:
> +	case DRM_FORMAT_RGBX5551:
> +	case DRM_FORMAT_XBGR1555:
> +	case DRM_FORMAT_BGRX5551:
> +		f = FORMAT_X1R5G5B5;
> +		break;
> +	case DRM_FORMAT_ARGB1555:
> +	case DRM_FORMAT_RGBA5551:
> +	case DRM_FORMAT_ABGR1555:
> +	case DRM_FORMAT_BGRA5551:
> +		f = FORMAT_A1R5G5B5;
> +		break;
> +	case DRM_FORMAT_RGB565:
> +	case DRM_FORMAT_BGR565:
> +		f = FORMAT_R5G6B5;
> +		break;
> +	case DRM_FORMAT_XRGB8888:
> +	case DRM_FORMAT_RGBX8888:
> +	case DRM_FORMAT_XBGR8888:
> +	case DRM_FORMAT_BGRX8888:
> +		f = FORMAT_X8R8G8B8;
> +		break;
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_RGBA8888:
> +	case DRM_FORMAT_ABGR8888:
> +	case DRM_FORMAT_BGRA8888:
> +		f = FORMAT_A8R8G8B8;
> +		break;
> +	case DRM_FORMAT_YUYV:
> +	case DRM_FORMAT_YVYU:
> +		f = FORMAT_YUY2;
> +		break;
> +	case DRM_FORMAT_UYVY:
> +	case DRM_FORMAT_VYUY:
> +		f = FORMAT_UYVY;
> +		break;
> +	case DRM_FORMAT_YUV420:
> +	case DRM_FORMAT_YVU420:
> +		f = FORMAT_YV12;
> +		break;
> +	case DRM_FORMAT_NV21:
> +		f = FORMAT_NV12;
> +		break;
> +	case DRM_FORMAT_NV16:
> +	case DRM_FORMAT_NV61:
> +		f = FORMAT_NV16;
> +		break;
> +	case DRM_FORMAT_P010:
> +		f = FORMAT_P010;
> +		break;
> +	case DRM_FORMAT_ARGB2101010:
> +	case DRM_FORMAT_RGBA1010102:
> +	case DRM_FORMAT_ABGR2101010:
> +	case DRM_FORMAT_BGRA1010102:
> +		f = FORMAT_A2R10G10B10;
> +		break;
> +	case DRM_FORMAT_NV12:
> +		if (fourcc_mod_vs_get_type(mod) ==
> +			DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT)
> +			f = FORMAT_NV12_10BIT;
> +		else
> +			f = FORMAT_NV12;
> +		break;
> +	case DRM_FORMAT_YUV444:
> +		if (fourcc_mod_vs_get_type(mod) ==
> +			DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT)
> +			f = FORMAT_YUV444_10BIT;
> +		else
> +			f = FORMAT_YUV444;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	fb->format = f;
> +}
> +
> +static inline void update_swizzle(u32 format, struct dc_hw_fb *fb)
> +{
> +	fb->swizzle = SWIZZLE_ARGB;
> +	fb->uv_swizzle = 0;
> +
> +	switch (format) {
> +	case DRM_FORMAT_RGBX4444:
> +	case DRM_FORMAT_RGBA4444:
> +	case DRM_FORMAT_RGBX5551:
> +	case DRM_FORMAT_RGBA5551:
> +	case DRM_FORMAT_RGBX8888:
> +	case DRM_FORMAT_RGBA8888:
> +	case DRM_FORMAT_RGBA1010102:
> +		fb->swizzle = SWIZZLE_RGBA;
> +		break;
> +	case DRM_FORMAT_XBGR4444:
> +	case DRM_FORMAT_ABGR4444:
> +	case DRM_FORMAT_XBGR1555:
> +	case DRM_FORMAT_ABGR1555:
> +	case DRM_FORMAT_BGR565:
> +	case DRM_FORMAT_XBGR8888:
> +	case DRM_FORMAT_ABGR8888:
> +	case DRM_FORMAT_ABGR2101010:
> +		fb->swizzle = SWIZZLE_ABGR;
> +		break;
> +	case DRM_FORMAT_BGRX4444:
> +	case DRM_FORMAT_BGRA4444:
> +	case DRM_FORMAT_BGRX5551:
> +	case DRM_FORMAT_BGRA5551:
> +	case DRM_FORMAT_BGRX8888:
> +	case DRM_FORMAT_BGRA8888:
> +	case DRM_FORMAT_BGRA1010102:
> +		fb->swizzle = SWIZZLE_BGRA;
> +		break;
> +	case DRM_FORMAT_YVYU:
> +	case DRM_FORMAT_VYUY:
> +	case DRM_FORMAT_NV21:
> +	case DRM_FORMAT_NV61:
> +		fb->uv_swizzle = 1;
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +static inline void update_watermark(struct drm_property_blob *watermark,
> +				    struct dc_hw_fb *fb)
> +{
> +	struct drm_vs_watermark *data;
> +
> +	fb->water_mark = 0;
> +
> +	if (watermark) {
> +		data = watermark->data;
> +		fb->water_mark = data->watermark & 0xFFFFF;
> +	}
> +}
> +
> +static inline u8 to_vs_rotation(unsigned int rotation)
> +{
> +	u8 rot;
> +
> +	switch (rotation & DRM_MODE_REFLECT_MASK) {
> +	case DRM_MODE_REFLECT_X:
> +		rot = FLIP_X;
> +		return rot;
> +	case DRM_MODE_REFLECT_Y:
> +		rot = FLIP_Y;
> +		return rot;
> +	case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
> +		rot = FLIP_XY;
> +		return rot;
> +	default:
> +		break;
> +	}
> +
> +	switch (rotation & DRM_MODE_ROTATE_MASK) {
> +	case DRM_MODE_ROTATE_0:
> +		rot = ROT_0;
> +		break;
> +	case DRM_MODE_ROTATE_90:
> +		rot = ROT_90;
> +		break;
> +	case DRM_MODE_ROTATE_180:
> +		rot = ROT_180;
> +		break;
> +	case DRM_MODE_ROTATE_270:
> +		rot = ROT_270;
> +		break;
> +	default:
> +		rot = ROT_0;
> +		break;
> +	}
> +
> +	return rot;
> +}
> +
> +static inline u8 to_vs_yuv_color_space(u32 color_space)
> +{
> +	u8 cs;
> +
> +	switch (color_space) {
> +	case DRM_COLOR_YCBCR_BT601:
> +		cs = COLOR_SPACE_601;
> +		break;
> +	case DRM_COLOR_YCBCR_BT709:
> +		cs = COLOR_SPACE_709;
> +		break;
> +	case DRM_COLOR_YCBCR_BT2020:
> +		cs = COLOR_SPACE_2020;
> +		break;
> +	default:
> +		cs = COLOR_SPACE_601;
> +		break;
> +	}
> +
> +	return cs;
> +}
> +
> +static inline u8 to_vs_tile_mode(u64 modifier)
> +{
> +	return (u8)(modifier & DRM_FORMAT_MOD_VS_NORM_MODE_MASK);
> +}
> +
> +static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc)
> +{
> +	u8 panel_num = dc->hw.info->panel_num;
> +	u32 index = drm_crtc_index(crtc);
> +	int i;
> +
> +	for (i = 0; i < panel_num; i++) {
> +		if (index == dc->crtc[i]->base.index)
> +			return i;
> +	}
> +
> +	return 0;
> +}
> +
> +static int plda_clk_rst_init(struct device *dev)
> +{
> +	int ret = 0;
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +
> +	ret = clk_bulk_prepare_enable(dc->nclks, dc->clk_vout);
> +	if (ret) {
> +		dev_err(dev, "failed to enable clocks\n");
> +		return ret;
> +	}
> +
> +	ret = reset_control_bulk_deassert(dc->nrsts, dc->rst_vout);
> +	return ret;
> +}
> +
> +static void plda_clk_rst_deinit(struct device *dev)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +
> +	reset_control_bulk_assert(dc->nrsts, dc->rst_vout);
> +	clk_bulk_disable_unprepare(dc->nclks, dc->clk_vout);
> +}
> +
> +static void dc_deinit(struct device *dev)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +
> +	dc_hw_enable_interrupt(&dc->hw, 0);
> +	dc_hw_deinit(&dc->hw);
> +	plda_clk_rst_deinit(dev);
> +}
> +
> +static int dc_init(struct device *dev)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +	int ret;
> +
> +	dc->first_frame = true;
> +
> +	ret = plda_clk_rst_init(dev);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to init dc clk reset: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = dc_hw_init(&dc->hw);
> +	if (ret) {
> +		dev_err(dev, "failed to init DC HW\n");
> +		return ret;
> +	}
> +	return 0;
> +}
> +
> +static void vs_dc_enable(struct device *dev, struct drm_crtc *crtc)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +	struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
> +	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> +	struct dc_hw_display display;
> +
> +	display.bus_format = crtc_state->output_fmt;
> +	display.h_active = mode->hdisplay;
> +	display.h_total = mode->htotal;
> +	display.h_sync_start = mode->hsync_start;
> +	display.h_sync_end = mode->hsync_end;
> +	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
> +		display.h_sync_polarity = true;
> +	else
> +		display.h_sync_polarity = false;
> +
> +	display.v_active = mode->vdisplay;
> +	display.v_total = mode->vtotal;
> +	display.v_sync_start = mode->vsync_start;
> +	display.v_sync_end = mode->vsync_end;
> +
> +	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
> +		display.v_sync_polarity = true;
> +	else
> +		display.v_sync_polarity = false;
> +
> +	display.sync_mode = crtc_state->sync_mode;
> +	display.bg_color = crtc_state->bg_color;
> +
> +	display.id = to_vs_display_id(dc, crtc);
> +	display.sync_enable = crtc_state->sync_enable;
> +	display.dither_enable = crtc_state->dither_enable;
> +
> +	display.enable = true;
> +
> +	if (crtc_state->encoder_type == DRM_MODE_ENCODER_DSI) {
> +		dc_hw_set_out(&dc->hw, OUT_DPI, display.id);
> +		clk_set_rate(dc->clk_vout[CLK_VOUT_SOC_PIX].clk, mode->clock * 1000);
> +		clk_set_parent(dc->clk_vout[CLK_VOUT_PIX1].clk,
> +			       dc->clk_vout[CLK_VOUT_SOC_PIX].clk);
> +	} else {
> +		dc_hw_set_out(&dc->hw, OUT_DP, display.id);
> +		clk_set_parent(dc->clk_vout[CLK_VOUT_PIX0].clk,
> +			       dc->clk_vout[CLK_VOUT_HDMI_PIX].clk);
> +	}
> +
> +	dc_hw_setup_display(&dc->hw, &display);
> +}
> +
> +static void vs_dc_disable(struct device *dev, struct drm_crtc *crtc)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +	struct dc_hw_display display;
> +
> +	display.id = to_vs_display_id(dc, crtc);
> +	display.enable = false;
> +
> +	dc_hw_setup_display(&dc->hw, &display);
> +}
> +
> +static bool vs_dc_mode_fixup(struct device *dev,
> +			     const struct drm_display_mode *mode,
> +			     struct drm_display_mode *adjusted_mode)
> +{
> +	return true;
> +}
> +
> +static void vs_dc_set_gamma(struct device *dev, struct drm_crtc *crtc,
> +			    struct drm_color_lut *lut, unsigned int size)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +	u16 i, r, g, b;
> +	u8 bits, id;
> +
> +	if (size != dc->hw.info->gamma_size) {
> +		dev_err(dev, "gamma size does not match!\n");
> +		return;
> +	}
> +
> +	id = to_vs_display_id(dc, crtc);
> +
> +	bits = dc->hw.info->gamma_bits;
> +	for (i = 0; i < size; i++) {
> +		r = drm_color_lut_extract(lut[i].red, bits);
> +		g = drm_color_lut_extract(lut[i].green, bits);
> +		b = drm_color_lut_extract(lut[i].blue, bits);
> +		dc_hw_update_gamma(&dc->hw, id, i, r, g, b);
> +	}
> +}
> +
> +static void vs_dc_enable_gamma(struct device *dev, struct drm_crtc *crtc,
> +			       bool enable)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +	u8 id;
> +
> +	id = to_vs_display_id(dc, crtc);
> +	dc_hw_enable_gamma(&dc->hw, id, enable);
> +}
> +
> +static void vs_dc_enable_vblank(struct device *dev, bool enable)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +
> +	dc_hw_enable_interrupt(&dc->hw, enable);
> +}
> +
> +static u32 calc_factor(u32 src, u32 dest)
> +{
> +	u32 factor = 1 << 16;
> +
> +	if (src > 1 && dest > 1)
> +		factor = ((src - 1) << 16) / (dest - 1);
> +
> +	return factor;
> +}
> +
> +static void update_scale(struct drm_plane_state *state, struct dc_hw_roi *roi,
> +			 struct dc_hw_scale *scale)
> +{
> +	int dst_w = drm_rect_width(&state->dst);
> +	int dst_h = drm_rect_height(&state->dst);
> +	int src_w, src_h, temp;
> +
> +	scale->enable = false;
> +
> +	if (roi->enable) {
> +		src_w = roi->width;
> +		src_h = roi->height;
> +	} else {
> +		src_w = drm_rect_width(&state->src) >> 16;
> +		src_h = drm_rect_height(&state->src) >> 16;
> +	}
> +
> +	if (drm_rotation_90_or_270(state->rotation)) {
> +		temp = src_w;
> +		src_w = src_h;
> +		src_h = temp;
> +	}
> +
> +	if (src_w != dst_w) {
> +		scale->scale_factor_x = calc_factor(src_w, dst_w);
> +		scale->enable = true;
> +	} else {
> +		scale->scale_factor_x = 1 << 16;
> +	}
> +	if (src_h != dst_h) {
> +		scale->scale_factor_y = calc_factor(src_h, dst_h);
> +		scale->enable = true;
> +	} else {
> +		scale->scale_factor_y = 1 << 16;
> +	}
> +}
> +
> +static void update_fb(struct vs_plane *plane, u8 display_id,
> +		      struct dc_hw_fb *fb, struct drm_plane_state *state)
> +{
> +	struct vs_plane_state *plane_state = to_vs_plane_state(state);
> +	struct drm_framebuffer *drm_fb = state->fb;
> +	struct drm_rect *src = &state->src;
> +
> +	fb->display_id = display_id;
> +	fb->y_address = plane->dma_addr[0];
> +	fb->y_stride = drm_fb->pitches[0];
> +	if (drm_fb->format->format == DRM_FORMAT_YVU420) {
> +		fb->u_address = plane->dma_addr[2];
> +		fb->v_address = plane->dma_addr[1];
> +		fb->u_stride = drm_fb->pitches[2];
> +		fb->v_stride = drm_fb->pitches[1];
> +	} else {
> +		fb->u_address = plane->dma_addr[1];
> +		fb->v_address = plane->dma_addr[2];
> +		fb->u_stride = drm_fb->pitches[1];
> +		fb->v_stride = drm_fb->pitches[2];
> +	}
> +	fb->width = drm_rect_width(src) >> 16;
> +	fb->height = drm_rect_height(src) >> 16;
> +	fb->tile_mode = to_vs_tile_mode(drm_fb->modifier);
> +	fb->rotation = to_vs_rotation(state->rotation);
> +	fb->yuv_color_space = to_vs_yuv_color_space(state->color_encoding);
> +	fb->zpos = state->zpos;
> +	fb->enable = state->visible;
> +	update_format(drm_fb->format->format, drm_fb->modifier, fb);
> +	update_swizzle(drm_fb->format->format, fb);
> +	update_watermark(plane_state->watermark, fb);
> +	plane_state->status.tile_mode = fb->tile_mode;
> +}
> +
> +static void update_degamma(struct vs_dc *dc, struct vs_plane *plane,
> +			   struct vs_plane_state *plane_state)
> +{
> +	dc_hw_update_degamma(&dc->hw, plane->id, plane_state->degamma);
> +	plane_state->degamma_changed = false;
> +}
> +
> +static void update_roi(struct vs_dc *dc, u8 id,
> +		       struct vs_plane_state *plane_state,
> +		       struct dc_hw_roi *roi,
> +		       struct drm_plane_state *state)
> +{
> +	struct drm_vs_roi *data;
> +	struct drm_rect *src = &state->src;
> +	u16 src_w = drm_rect_width(src) >> 16;
> +	u16 src_h = drm_rect_height(src) >> 16;
> +
> +	if (plane_state->roi) {
> +		data = plane_state->roi->data;
> +
> +		if (data->enable) {
> +			roi->x = data->roi_x;
> +			roi->y = data->roi_y;
> +			roi->width = (data->roi_x + data->roi_w > src_w) ?
> +						 (src_w - data->roi_x) : data->roi_w;
> +			roi->height = (data->roi_y + data->roi_h > src_h) ?
> +						  (src_h - data->roi_y) : data->roi_h;
> +			roi->enable = true;
> +		} else {
> +			roi->enable = false;
> +		}
> +
> +		dc_hw_update_roi(&dc->hw, id, roi);
> +	} else {
> +		roi->enable = false;
> +	}
> +}
> +
> +static void update_color_mgmt(struct vs_dc *dc, u8 id,
> +			      struct dc_hw_fb *fb,
> +			      struct vs_plane_state *plane_state)
> +{
> +	struct drm_vs_color_mgmt *data;
> +	struct dc_hw_colorkey colorkey;
> +
> +	if (plane_state->color_mgmt) {
> +		data = plane_state->color_mgmt->data;
> +
> +		fb->clear_enable = data->clear_enable;
> +		fb->clear_value = data->clear_value;
> +
> +		if (data->colorkey > data->colorkey_high)
> +			data->colorkey = data->colorkey_high;
> +
> +		colorkey.colorkey = data->colorkey;
> +		colorkey.colorkey_high = data->colorkey_high;
> +		colorkey.transparency = (data->transparency) ?
> +				DC_TRANSPARENCY_KEY : DC_TRANSPARENCY_OPAQUE;
> +		dc_hw_update_colorkey(&dc->hw, id, &colorkey);
> +	}
> +}
> +
> +static void update_plane(struct vs_dc *dc, struct vs_plane *plane,
> +			 struct drm_plane *drm_plane,
> +			 struct drm_atomic_state *drm_state)
> +{
> +	struct dc_hw_fb fb = {0};
> +	struct dc_hw_scale scale;
> +	struct dc_hw_position pos;
> +	struct dc_hw_blend blend;
> +	struct dc_hw_roi roi;
> +	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
> +									   drm_plane);
> +	struct vs_plane_state *plane_state = to_vs_plane_state(state);
> +	struct drm_rect *dest = &state->dst;
> +	bool dec_enable = false;
> +	u8 display_id = 0;
> +
> +	display_id = to_vs_display_id(dc, state->crtc);
> +	update_fb(plane, display_id, &fb, state);
> +	fb.dec_enable = dec_enable;
> +
> +	update_roi(dc, plane->id, plane_state, &roi, state);
> +
> +	update_scale(state, &roi, &scale);
> +
> +	if (plane_state->degamma_changed)
> +		update_degamma(dc, plane, plane_state);
> +
> +	pos.start_x = dest->x1;
> +	pos.start_y = dest->y1;
> +	pos.end_x = dest->x2;
> +	pos.end_y = dest->y2;
> +
> +	blend.alpha = (u8)(state->alpha >> 8);
> +	blend.blend_mode = (u8)(state->pixel_blend_mode);
> +
> +	update_color_mgmt(dc, plane->id, &fb, plane_state);
> +
> +	dc_hw_update_plane(&dc->hw, plane->id, &fb, &scale, &pos, &blend);
> +}
> +
> +static void update_qos(struct vs_dc *dc, struct vs_plane *plane,
> +		       struct drm_plane *drm_plane,
> +		       struct drm_atomic_state *drm_state)
> +{
> +	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
> +									   drm_plane);
> +	struct vs_plane_state *plane_state = to_vs_plane_state(state);
> +	struct drm_vs_watermark *data;
> +	struct dc_hw_qos qos;
> +
> +	if (plane_state->watermark) {
> +		data = plane_state->watermark->data;
> +
> +		if (data->qos_high) {
> +			if (data->qos_low > data->qos_high)
> +				data->qos_low = data->qos_high;
> +
> +			qos.low_value = data->qos_low & 0x0F;
> +			qos.high_value = data->qos_high & 0x0F;
> +			dc_hw_update_qos(&dc->hw, &qos);
> +		}
> +	}
> +}
> +
> +static void update_cursor_size(struct drm_plane_state *state, struct dc_hw_cursor *cursor)
> +{
> +	u8 size_type;
> +
> +	switch (state->crtc_w) {
> +	case 32:
> +		size_type = CURSOR_SIZE_32X32;
> +		break;
> +	case 64:
> +		size_type = CURSOR_SIZE_64X64;
> +		break;
> +	default:
> +		size_type = CURSOR_SIZE_32X32;
> +		break;
> +	}
> +
> +	cursor->size = size_type;
> +}
> +
> +static void update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
> +				struct drm_plane *drm_plane,
> +				struct drm_atomic_state *drm_state)
> +{
> +	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
> +								       drm_plane);
> +	struct drm_framebuffer *drm_fb = state->fb;
> +	struct dc_hw_cursor cursor;
> +
> +	cursor.address = plane->dma_addr[0];
> +	cursor.x = state->crtc_x;
> +	cursor.y = state->crtc_y;
> +	cursor.hot_x = drm_fb->hot_x;
> +	cursor.hot_y = drm_fb->hot_y;
> +	cursor.display_id = to_vs_display_id(dc, state->crtc);
> +	update_cursor_size(state, &cursor);
> +	cursor.enable = true;
> +
> +	dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
> +}
> +
> +static void vs_dc_update_plane(struct device *dev, struct vs_plane *plane,
> +			       struct drm_plane *drm_plane,
> +			       struct drm_atomic_state *drm_state)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +	enum drm_plane_type type = plane->base.type;
> +
> +	switch (type) {
> +	case DRM_PLANE_TYPE_PRIMARY:
> +	case DRM_PLANE_TYPE_OVERLAY:
> +		update_plane(dc, plane, drm_plane, drm_state);
> +		update_qos(dc, plane, drm_plane, drm_state);
> +		break;
> +	case DRM_PLANE_TYPE_CURSOR:
> +		update_cursor_plane(dc, plane, drm_plane, drm_state);
> +		break;
> +	default:
> +		break;
> +	}

This switch statement, and all the similar code below, is another 
instance of the internal-API problem.

You have one multiplexer function that switches among primary, overlay 
and cursor planes. You've replicated the functionality of the DRM core 
and helpers in your driver.

It is much better to implement a function for each type of plane: 
vs_dc_update_primary_plane(), vs_dc_update_overlay_plane(), 
vs_dc_update_cursor_plane(). Then make an instance of 
drm_plane_helper_func for each type of plane:

struct drm_plane_helper_funcs primary_plane_helpers = {
     vs_dc_update_primary_plane
};

struct drm_plane_helper_funcs overlay_plane_helpers = {
     vs_dc_update_overlay_plane
};

struct drm_plane_helper_funcs cursor_plane_helpers = {
     vs_dc_update_cursor_plane
};

Each of these helper_funcs instances handle exactly their own type of 
plane. When you create your modesetting pipeline, just use the correct 
helpers for each instanciated plane.  You'll have less boiler plate 
code, less indirection, and adding new and different planes is really easy.


> +}
> +
> +static void vs_dc_disable_plane(struct device *dev, struct vs_plane *plane,
> +				struct drm_plane_state *old_state)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +	enum drm_plane_type type = plane->base.type;
> +	struct dc_hw_fb fb = {0};
> +	struct dc_hw_cursor cursor = {0};
> +
> +	switch (type) {
> +	case DRM_PLANE_TYPE_PRIMARY:
> +	case DRM_PLANE_TYPE_OVERLAY:
> +		fb.enable = false;
> +		dc_hw_update_plane(&dc->hw, plane->id, &fb, NULL, NULL, NULL);
> +		break;
> +
> +	case DRM_PLANE_TYPE_CURSOR:
> +		cursor.enable = false;
> +		cursor.display_id = to_vs_display_id(dc, old_state->crtc);
> +		dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +static bool vs_dc_mod_supported(const struct vs_plane_info *plane_info,
> +				u64 modifier)
> +{
> +	const u64 *mods;
> +
> +	if (!plane_info->modifiers)
> +		return false;
> +
> +	for (mods = plane_info->modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) {
> +		if (*mods == modifier)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static int vs_dc_check_plane(struct device *dev, struct drm_plane *plane,
> +			     struct drm_atomic_state *state)
> +{
> +	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> +										 plane);
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +	struct drm_framebuffer *fb = new_plane_state->fb;
> +	const struct vs_plane_info *plane_info;
> +	struct drm_crtc *crtc = new_plane_state->crtc;
> +	struct drm_crtc_state *crtc_state;
> +	struct vs_plane *vs_plane = to_vs_plane(plane);
> +
> +	plane_info = &dc->hw.info->planes[vs_plane->id];
> +	if (!plane_info)

I'd say this cannot be NULL.

> +		return -EINVAL;
> +
> +	if (fb->width < plane_info->min_width ||
> +	    fb->width > plane_info->max_width ||
> +	    fb->height < plane_info->min_height ||
> +	    fb->height > plane_info->max_height)
> +		dev_err_once(dev, "buffer size may not support on plane%d.\n",
> +			     vs_plane->id);
> +
> +	if (vs_plane->base.type != DRM_PLANE_TYPE_CURSOR &&

Internal-API problem: there should be a separate check function for cursors.

> +	    (!vs_dc_mod_supported(plane_info, fb->modifier))) {
> +		dev_err(dev, "unsupported modifier on plane%d.\n", vs_plane->id);
> +		return -EINVAL;
> +	}
> +
> +	crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
> +	if (IS_ERR(crtc_state))
> +		return -EINVAL;

This cannot fail.

Best regards
Thomas

> +
> +	return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> +						  plane_info->min_scale,
> +						  plane_info->max_scale,
> +						  true, true);
> +}
> +
> +static irqreturn_t dc_isr(int irq, void *data)
> +{
> +	struct vs_dc *dc = data;
> +	struct vs_dc_info *dc_info = dc->hw.info;
> +	u32 i, ret;
> +
> +	ret = dc_hw_get_interrupt(&dc->hw);
> +
> +	for (i = 0; i < dc_info->panel_num; i++)
> +		vs_crtc_handle_vblank(&dc->crtc[i]->base, dc_hw_check_underflow(&dc->hw));
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void vs_dc_commit(struct device *dev)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +
> +	dc_hw_enable_shadow_register(&dc->hw, false);
> +
> +	dc_hw_commit(&dc->hw);
> +
> +	if (dc->first_frame)
> +		dc->first_frame = false;
> +
> +	dc_hw_enable_shadow_register(&dc->hw, true);
> +}
> +
> +static const struct vs_crtc_funcs dc_crtc_funcs = {
> +	.enable			= vs_dc_enable,
> +	.disable		= vs_dc_disable,
> +	.mode_fixup		= vs_dc_mode_fixup,
> +	.set_gamma		= vs_dc_set_gamma,
> +	.enable_gamma	= vs_dc_enable_gamma,
> +	.enable_vblank	= vs_dc_enable_vblank,
> +	.commit			= vs_dc_commit,
> +};
> +
> +static const struct vs_plane_funcs dc_plane_funcs = {
> +	.update			= vs_dc_update_plane,
> +	.disable		= vs_dc_disable_plane,
> +	.check			= vs_dc_check_plane,
> +};
> +
> +static int dc_bind(struct device *dev, struct device *master, void *data)
> +{
> +	struct drm_device *drm_dev = data;
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +	struct device_node *port;
> +	struct vs_crtc *crtc;
> +	struct drm_crtc *drm_crtc;
> +	struct vs_dc_info *dc_info;
> +	struct vs_plane *plane;
> +	struct drm_plane *drm_plane, *tmp;
> +	struct vs_plane_info *plane_info;
> +	int i, ret;
> +	u32 ctrc_mask = 0;
> +
> +	if (!drm_dev || !dc) {
> +		dev_err(dev, "devices are not created.\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = dc_init(dev);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to initialize DC hardware.\n");
> +		return ret;
> +	}
> +
> +	port = of_get_child_by_name(dev->of_node, "port");
> +	if (!port) {
> +		dev_err(dev, "no port node found\n");
> +		return -ENODEV;
> +	}
> +	of_node_put(port);
> +
> +	dc_info = dc->hw.info;
> +
> +	for (i = 0; i < dc_info->panel_num; i++) {
> +		crtc = vs_crtc_create(drm_dev, dc_info);
> +		if (!crtc) {
> +			dev_err(dev, "Failed to create CRTC.\n");
> +			ret = -ENOMEM;
> +			return ret;
> +		}
> +
> +		crtc->base.port = port;
> +		crtc->dev = dev;
> +		crtc->funcs = &dc_crtc_funcs;
> +		dc->crtc[i] = crtc;
> +		ctrc_mask |= drm_crtc_mask(&crtc->base);
> +	}
> +
> +	for (i = 0; i < dc_info->plane_num; i++) {
> +		plane_info = (struct vs_plane_info *)&dc_info->planes[i];
> +
> +		if (!strcmp(plane_info->name, "Primary") || !strcmp(plane_info->name, "Cursor")) {
> +			plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
> +						drm_crtc_mask(&dc->crtc[0]->base));
> +		} else if (!strcmp(plane_info->name, "Primary_1") ||
> +				   !strcmp(plane_info->name, "Cursor_1")) {
> +			plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
> +						drm_crtc_mask(&dc->crtc[1]->base));
> +		} else {
> +			plane = vs_plane_create(drm_dev, plane_info,
> +						dc_info->layer_num, ctrc_mask);
> +		}
> +
> +		if (!plane)
> +			goto err_cleanup_planes;
> +
> +		plane->id = i;
> +		dc->planes[i].id = plane_info->id;
> +
> +		plane->funcs = &dc_plane_funcs;
> +
> +		if (plane_info->type == DRM_PLANE_TYPE_PRIMARY) {
> +			if (!strcmp(plane_info->name, "Primary"))
> +				dc->crtc[0]->base.primary = &plane->base;
> +			else
> +				dc->crtc[1]->base.primary = &plane->base;
> +			drm_dev->mode_config.min_width = plane_info->min_width;
> +			drm_dev->mode_config.min_height =
> +							plane_info->min_height;
> +			drm_dev->mode_config.max_width = plane_info->max_width;
> +			drm_dev->mode_config.max_height =
> +							plane_info->max_height;
> +		}
> +
> +		if (plane_info->type == DRM_PLANE_TYPE_CURSOR) {
> +			if (!strcmp(plane_info->name, "Cursor"))
> +				dc->crtc[0]->base.cursor = &plane->base;
> +			else
> +				dc->crtc[1]->base.cursor = &plane->base;
> +			drm_dev->mode_config.cursor_width =
> +							plane_info->max_width;
> +			drm_dev->mode_config.cursor_height =
> +							plane_info->max_height;
> +		}
> +	}
> +
> +	vs_drm_update_pitch_alignment(drm_dev, dc_info->pitch_alignment);
> +
> +	return 0;
> +
> +err_cleanup_planes:
> +	list_for_each_entry_safe(drm_plane, tmp,
> +				 &drm_dev->mode_config.plane_list, head)
> +		if (drm_plane->possible_crtcs & ctrc_mask)
> +			vs_plane_destory(drm_plane);
> +
> +	drm_for_each_crtc(drm_crtc, drm_dev)
> +		vs_crtc_destroy(drm_crtc);
> +
> +	return ret;
> +}
> +
> +static void dc_unbind(struct device *dev, struct device *master, void *data)
> +{
> +	dc_deinit(dev);
> +}
> +
> +const struct component_ops dc_component_ops = {
> +	.bind = dc_bind,
> +	.unbind = dc_unbind,
> +};
> +
> +static const struct of_device_id dc_driver_dt_match[] = {
> +	{ .compatible = "verisilicon,dc8200", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, dc_driver_dt_match);
> +
> +static int dc_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct vs_dc *dc;
> +	int irq, ret, i;
> +
> +	dc = devm_kzalloc(dev, sizeof(*dc), GFP_KERNEL);
> +	if (!dc)
> +		return -ENOMEM;
> +
> +	dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(dc->hw.hi_base))
> +		return PTR_ERR(dc->hw.hi_base);
> +
> +	dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1);
> +	if (IS_ERR(dc->hw.reg_base))
> +		return PTR_ERR(dc->hw.reg_base);
> +
> +	dc->dss_reg = devm_platform_ioremap_resource(pdev, 2);
> +	if (IS_ERR(dc->dss_reg))
> +		return PTR_ERR(dc->dss_reg);
> +
> +	dc->nclks = ARRAY_SIZE(dc->clk_vout);
> +	for (i = 0; i < dc->nclks; ++i)
> +		dc->clk_vout[i].id = vout_clocks[i];
> +	ret = devm_clk_bulk_get(dev, dc->nclks, dc->clk_vout);
> +	if (ret) {
> +		dev_err(dev, "Failed to get clk controls\n");
> +		return ret;
> +	}
> +
> +	dc->nrsts = ARRAY_SIZE(dc->rst_vout);
> +	for (i = 0; i < dc->nrsts; ++i)
> +		dc->rst_vout[i].id = vout_resets[i];
> +	ret = devm_reset_control_bulk_get_shared(dev, dc->nrsts,
> +						 dc->rst_vout);
> +	if (ret) {
> +		dev_err(dev, "Failed to get reset controls\n");
> +		return ret;
> +	}
> +
> +	irq = platform_get_irq(pdev, 0);
> +
> +	ret = devm_request_irq(dev, irq, dc_isr, 0, dev_name(dev), dc);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to install irq:%u.\n", irq);
> +		return ret;
> +	}
> +
> +	dev_set_drvdata(dev, dc);
> +
> +	return component_add(dev, &dc_component_ops);
> +}
> +
> +static int dc_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +
> +	component_del(dev, &dc_component_ops);
> +
> +	dev_set_drvdata(dev, NULL);
> +
> +	return 0;
> +}
> +
> +struct platform_driver dc_platform_driver = {
> +	.probe = dc_probe,
> +	.remove = dc_remove,
> +	.driver = {
> +		.name = "vs-dc",
> +		.of_match_table = of_match_ptr(dc_driver_dt_match),
> +	},
> +};
> +
> +MODULE_AUTHOR("StarFive Corporation");
> +MODULE_AUTHOR("Verisilicon Corporation");
> +MODULE_DESCRIPTION("VeriSilicon DC Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/verisilicon/vs_dc.h b/drivers/gpu/drm/verisilicon/vs_dc.h
> new file mode 100644
> index 000000000000..ab76ac1e9943
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_dc.h
> @@ -0,0 +1,62 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_DC_H__
> +#define __VS_DC_H__
> +
> +#include <linux/clk.h>
> +#include <linux/mm_types.h>
> +#include <linux/reset.h>
> +#include <linux/version.h>
> +
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_modes.h>
> +
> +#include "vs_crtc.h"
> +#include "vs_dc_hw.h"
> +#include "vs_plane.h"
> +
> +#define fourcc_mod_vs_get_type(val) \
> +			(((val) & DRM_FORMAT_MOD_VS_TYPE_MASK) >> 54)
> +
> +struct vs_dc_plane {
> +	enum dc_hw_plane_id id;
> +};
> +
> +enum vout_clk {
> +	CLK_VOUT_NOC_DISP = 0,
> +	CLK_VOUT_PIX0,
> +	CLK_VOUT_PIX1,
> +	CLK_VOUT_AXI,
> +	CLK_VOUT_CORE,
> +	CLK_VOUT_AHB,
> +	CLK_VOUT_HDMI_PIX,
> +	CLK_VOUT_SOC_PIX,
> +	CLK_VOUT_NUM
> +};
> +
> +enum rst_vout {
> +	RST_VOUT_AXI = 0,
> +	RST_VOUT_AHB,
> +	RST_VOUT_CORE,
> +	RST_VOUT_NUM
> +};
> +
> +struct vs_dc {
> +	struct vs_crtc		*crtc[DC_DISPLAY_NUM];
> +	struct dc_hw		hw;
> +	void __iomem        *dss_reg;
> +	bool			    first_frame;
> +
> +	struct vs_dc_plane  planes[PLANE_NUM];
> +	struct clk_bulk_data clk_vout[CLK_VOUT_NUM];
> +	int nclks;
> +	struct reset_control_bulk_data rst_vout[RST_VOUT_NUM];
> +	int nrsts;
> +};
> +
> +extern struct platform_driver dc_platform_driver;
> +
> +#endif /* __VS_DC_H__ */
> diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.c b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
> new file mode 100644
> index 000000000000..d370dd401084
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
> @@ -0,0 +1,2008 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/io.h>
> +#include <linux/media-bus-format.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_blend.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/vs_drm.h>
> +
> +#include "vs_dc_hw.h"
> +#include "vs_type.h"
> +
> +static const u32 horkernel[] = {
> +	0x00000000, 0x20000000, 0x00002000, 0x00000000,
> +	0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
> +	0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
> +	0x00000000, 0x00000000, 0x00000000, 0x2b981468,
> +	0x00000000, 0x00000000, 0x00000000, 0x10f00000,
> +	0x00002f10, 0x00000000, 0x00000000, 0x00000000,
> +	0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
> +	0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
> +	0x00000000, 0x3781087f, 0x00000000, 0x00000000,
> +	0x00000000, 0x06660000, 0x0000399a, 0x00000000,
> +	0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
> +	0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
> +	0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
> +	0x00000000, 0x00000000, 0x00000000, 0x01470000,
> +	0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
> +	0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
> +	0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
> +	0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
> +	0x00000000, 0x00000000, 0x00004000, 0x00000000,
> +	0x00000000, 0x00000000, 0x20002000, 0x00000000,
> +	0x00000000, 0x00000000, 0x1c030000, 0x000023fd,
> +	0x00000000, 0x00000000, 0x00000000, 0x27e1181f,
> +	0x00000000, 0x00000000, 0x00000000, 0x14680000,
> +	0x00002b98, 0x00000000, 0x00000000, 0x00000000,
> +	0x2f1010f0, 0x00000000, 0x00000000, 0x00000000,
> +	0x0dc70000, 0x00003239, 0x00000000, 0x00000000,
> +	0x00000000, 0x350b0af5, 0x00000000, 0x00000000,
> +	0x00000000, 0x087f0000, 0x00003781, 0x00000000,
> +	0x00000000, 0x00000000, 0x399a0666, 0x00000000,
> +	0x00000000, 0x00000000, 0x04a70000, 0x00003b59,
> +	0x00000000, 0x00000000, 0x00000000, 0x3cc4033c,
> +	0x00000000, 0x00000000, 0x00000000, 0x021f0000,
> +};
> +
> +#define H_COEF_SIZE (sizeof(horkernel) / sizeof(u32))
> +
> +static const u32 verkernel[] = {
> +	0x00000000, 0x20000000, 0x00002000, 0x00000000,
> +	0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
> +	0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
> +	0x00000000, 0x00000000, 0x00000000, 0x2b981468,
> +	0x00000000, 0x00000000, 0x00000000, 0x10f00000,
> +	0x00002f10, 0x00000000, 0x00000000, 0x00000000,
> +	0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
> +	0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
> +	0x00000000, 0x3781087f, 0x00000000, 0x00000000,
> +	0x00000000, 0x06660000, 0x0000399a, 0x00000000,
> +	0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
> +	0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
> +	0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
> +	0x00000000, 0x00000000, 0x00000000, 0x01470000,
> +	0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
> +	0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
> +	0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
> +	0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
> +	0x00000000, 0x00000000, 0x00004000, 0x00000000,
> +	0xcdcd0000, 0xfdfdfdfd, 0xabababab, 0xabababab,
> +	0x00000000, 0x00000000, 0x5ff5f456, 0x000f5f58,
> +	0x02cc6c78, 0x02cc0c28, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +};
> +
> +#define V_COEF_SIZE (sizeof(verkernel) / sizeof(u32))
> +
> +/*
> + * RGB 709->2020 conversion parameters
> + */
> +static u16 RGB2RGB[RGB_TO_RGB_TABLE_SIZE] = {
> +	10279,	5395,	709,
> +	1132,	15065,	187,
> +	269,	1442,	14674
> +};
> +
> +/*
> + * YUV601 to RGB conversion parameters
> + * YUV2RGB[0]  - [8] : C0 - C8;
> + * YUV2RGB[9]  - [11]: D0 - D2;
> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> + */
> +static s32 YUV601_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> +	1196,	0,			1640,	1196,
> +	-404,	-836,		1196,	2076,
> +	0,		-916224,	558336,	-1202944,
> +	64,		 940,		64,		960
> +};
> +
> +/*
> + * YUV709 to RGB conversion parameters
> + * YUV2RGB[0]  - [8] : C0 - C8;
> + * YUV2RGB[9]  - [11]: D0 - D2;
> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> + */
> +static s32 YUV709_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> +	1196,		0,		1844,	1196,
> +	-220,		-548,	1196,	2172,
> +	0,			-1020672, 316672,  -1188608,
> +	64,			940,		64,		960
> +};
> +
> +/*
> + * YUV2020 to RGB conversion parameters
> + * YUV2RGB[0]  - [8] : C0 - C8;
> + * YUV2RGB[9]  - [11]: D0 - D2;
> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> + */
> +static s32 YUV2020_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> +	1196, 0, 1724, 1196,
> +	-192, -668, 1196, 2200,
> +	0, -959232, 363776, -1202944,
> +	64, 940, 64, 960
> +};
> +
> +/*
> + * RGB to YUV2020 conversion parameters
> + * RGB2YUV[0] - [8] : C0 - C8;
> + * RGB2YUV[9] - [11]: D0 - D2;
> + */
> +static s16 RGB2YUV[RGB_TO_YUV_TABLE_SIZE] = {
> +	230,	594,	52,
> +	-125,  -323,	448,
> +	448,   -412,   -36,
> +	64,		512,	512
> +};
> +
> +/*
> + * Degamma table for 709 color space data.
> + */
> +static u16 DEGAMMA_709[DEGAMMA_SIZE] = {
> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0005,
> +	0x0007, 0x000a, 0x000d, 0x0011, 0x0015, 0x0019, 0x001e, 0x0024,
> +	0x002a, 0x0030, 0x0038, 0x003f, 0x0048, 0x0051, 0x005a, 0x0064,
> +	0x006f, 0x007b, 0x0087, 0x0094, 0x00a1, 0x00af, 0x00be, 0x00ce,
> +	0x00de, 0x00ef, 0x0101, 0x0114, 0x0127, 0x013b, 0x0150, 0x0166,
> +	0x017c, 0x0193, 0x01ac, 0x01c4, 0x01de, 0x01f9, 0x0214, 0x0230,
> +	0x024d, 0x026b, 0x028a, 0x02aa, 0x02ca, 0x02ec, 0x030e, 0x0331,
> +	0x0355, 0x037a, 0x03a0, 0x03c7, 0x03ef, 0x0418, 0x0441, 0x046c,
> +	0x0498, 0x04c4, 0x04f2, 0x0520, 0x0550, 0x0581, 0x05b2, 0x05e5,
> +	0x0618, 0x064d, 0x0682, 0x06b9, 0x06f0, 0x0729, 0x0763, 0x079d,
> +	0x07d9, 0x0816, 0x0854, 0x0893, 0x08d3, 0x0914, 0x0956, 0x0999,
> +	0x09dd, 0x0a23, 0x0a69, 0x0ab1, 0x0afa, 0x0b44, 0x0b8f, 0x0bdb,
> +	0x0c28, 0x0c76, 0x0cc6, 0x0d17, 0x0d69, 0x0dbb, 0x0e10, 0x0e65,
> +	0x0ebb, 0x0f13, 0x0f6c, 0x0fc6, 0x1021, 0x107d, 0x10db, 0x113a,
> +	0x119a, 0x11fb, 0x125d, 0x12c1, 0x1325, 0x138c, 0x13f3, 0x145b,
> +	0x14c5, 0x1530, 0x159c, 0x160a, 0x1678, 0x16e8, 0x175a, 0x17cc,
> +	0x1840, 0x18b5, 0x192b, 0x19a3, 0x1a1c, 0x1a96, 0x1b11, 0x1b8e,
> +	0x1c0c, 0x1c8c, 0x1d0c, 0x1d8e, 0x1e12, 0x1e96, 0x1f1c, 0x1fa3,
> +	0x202c, 0x20b6, 0x2141, 0x21ce, 0x225c, 0x22eb, 0x237c, 0x240e,
> +	0x24a1, 0x2536, 0x25cc, 0x2664, 0x26fc, 0x2797, 0x2832, 0x28cf,
> +	0x296e, 0x2a0e, 0x2aaf, 0x2b51, 0x2bf5, 0x2c9b, 0x2d41, 0x2dea,
> +	0x2e93, 0x2f3e, 0x2feb, 0x3099, 0x3148, 0x31f9, 0x32ab, 0x335f,
> +	0x3414, 0x34ca, 0x3582, 0x363c, 0x36f7, 0x37b3, 0x3871, 0x3930,
> +	0x39f1, 0x3ab3, 0x3b77, 0x3c3c, 0x3d02, 0x3dcb, 0x3e94, 0x3f5f,
> +	0x402c, 0x40fa, 0x41ca, 0x429b, 0x436d, 0x4442, 0x4517, 0x45ee,
> +	0x46c7, 0x47a1, 0x487d, 0x495a, 0x4a39, 0x4b19, 0x4bfb, 0x4cde,
> +	0x4dc3, 0x4eaa, 0x4f92, 0x507c, 0x5167, 0x5253, 0x5342, 0x5431,
> +	0x5523, 0x5616, 0x570a, 0x5800, 0x58f8, 0x59f1, 0x5aec, 0x5be9,
> +	0x5ce7, 0x5de6, 0x5ee7, 0x5fea, 0x60ef, 0x61f5, 0x62fc, 0x6406,
> +	0x6510, 0x661d, 0x672b, 0x683b, 0x694c, 0x6a5f, 0x6b73, 0x6c8a,
> +	0x6da2, 0x6ebb, 0x6fd6, 0x70f3, 0x7211, 0x7331, 0x7453, 0x7576,
> +	0x769b, 0x77c2, 0x78ea, 0x7a14, 0x7b40, 0x7c6d, 0x7d9c, 0x7ecd,
> +	0x3f65, 0x3f8c, 0x3fb2, 0x3fd8
> +};
> +
> +/*
> + * Degamma table for 2020 color space data.
> + */
> +static u16 DEGAMMA_2020[DEGAMMA_SIZE] = {
> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
> +	0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
> +	0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003,
> +	0x0003, 0x0003, 0x0004, 0x0004, 0x0004, 0x0005, 0x0005, 0x0006,
> +	0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, 0x0009, 0x000a,
> +	0x000a, 0x000b, 0x000c, 0x000c, 0x000d, 0x000e, 0x000f, 0x000f,
> +	0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0016, 0x0017, 0x0018,
> +	0x0019, 0x001b, 0x001c, 0x001e, 0x001f, 0x0021, 0x0022, 0x0024,
> +	0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, 0x0033, 0x0035,
> +	0x0038, 0x003a, 0x003d, 0x0040, 0x0043, 0x0046, 0x0049, 0x004d,
> +	0x0050, 0x0054, 0x0057, 0x005b, 0x005f, 0x0064, 0x0068, 0x006d,
> +	0x0071, 0x0076, 0x007c, 0x0081, 0x0086, 0x008c, 0x0092, 0x0098,
> +	0x009f, 0x00a5, 0x00ac, 0x00b4, 0x00bb, 0x00c3, 0x00cb, 0x00d3,
> +	0x00dc, 0x00e5, 0x00ee, 0x00f8, 0x0102, 0x010c, 0x0117, 0x0123,
> +	0x012e, 0x013a, 0x0147, 0x0154, 0x0161, 0x016f, 0x017e, 0x018d,
> +	0x019c, 0x01ac, 0x01bd, 0x01ce, 0x01e0, 0x01f3, 0x0206, 0x021a,
> +	0x022f, 0x0244, 0x025a, 0x0272, 0x0289, 0x02a2, 0x02bc, 0x02d6,
> +	0x02f2, 0x030f, 0x032c, 0x034b, 0x036b, 0x038b, 0x03ae, 0x03d1,
> +	0x03f5, 0x041b, 0x0443, 0x046b, 0x0495, 0x04c1, 0x04ee, 0x051d,
> +	0x054e, 0x0580, 0x05b4, 0x05ea, 0x0622, 0x065c, 0x0698, 0x06d6,
> +	0x0717, 0x075a, 0x079f, 0x07e7, 0x0831, 0x087e, 0x08cd, 0x0920,
> +	0x0976, 0x09ce, 0x0a2a, 0x0a89, 0x0aec, 0x0b52, 0x0bbc, 0x0c2a,
> +	0x0c9b, 0x0d11, 0x0d8b, 0x0e0a, 0x0e8d, 0x0f15, 0x0fa1, 0x1033,
> +	0x10ca, 0x1167, 0x120a, 0x12b2, 0x1360, 0x1415, 0x14d1, 0x1593,
> +	0x165d, 0x172e, 0x1806, 0x18e7, 0x19d0, 0x1ac1, 0x1bbb, 0x1cbf,
> +	0x1dcc, 0x1ee3, 0x2005, 0x2131, 0x2268, 0x23ab, 0x24fa, 0x2656,
> +	0x27be, 0x2934, 0x2ab8, 0x2c4a, 0x2dec, 0x2f9d, 0x315f, 0x3332,
> +	0x3516, 0x370d, 0x3916, 0x3b34, 0x3d66, 0x3fad, 0x420b, 0x4480,
> +	0x470d, 0x49b3, 0x4c73, 0x4f4e, 0x5246, 0x555a, 0x588e, 0x5be1,
> +	0x5f55, 0x62eb, 0x66a6, 0x6a86, 0x6e8c, 0x72bb, 0x7714, 0x7b99,
> +	0x3dcb, 0x3e60, 0x3ef5, 0x3f8c
> +};
> +
> +/* one is for primary plane and the other is for all overlay planes */
> +static const struct dc_hw_plane_reg dc_plane_reg[] = {
> +	{
> +	.y_address		= DC_FRAMEBUFFER_ADDRESS,
> +	.u_address		= DC_FRAMEBUFFER_U_ADDRESS,
> +	.v_address		= DC_FRAMEBUFFER_V_ADDRESS,
> +	.y_stride		= DC_FRAMEBUFFER_STRIDE,
> +	.u_stride		= DC_FRAMEBUFFER_U_STRIDE,
> +	.v_stride		= DC_FRAMEBUFFER_V_STRIDE,
> +	.size			= DC_FRAMEBUFFER_SIZE,
> +	.top_left		= DC_FRAMEBUFFER_TOP_LEFT,
> +	.bottom_right	= DC_FRAMEBUFFER_BOTTOM_RIGHT,
> +	.scale_factor_x			= DC_FRAMEBUFFER_SCALE_FACTOR_X,
> +	.scale_factor_y			= DC_FRAMEBUFFER_SCALE_FACTOR_Y,
> +	.h_filter_coef_index	= DC_FRAMEBUFFER_H_FILTER_COEF_INDEX,
> +	.h_filter_coef_data		= DC_FRAMEBUFFER_H_FILTER_COEF_DATA,
> +	.v_filter_coef_index	= DC_FRAMEBUFFER_V_FILTER_COEF_INDEX,
> +	.v_filter_coef_data		= DC_FRAMEBUFFER_V_FILTER_COEF_DATA,
> +	.init_offset			= DC_FRAMEBUFFER_INIT_OFFSET,
> +	.color_key				= DC_FRAMEBUFFER_COLOR_KEY,
> +	.color_key_high			= DC_FRAMEBUFFER_COLOR_KEY_HIGH,
> +	.clear_value			= DC_FRAMEBUFFER_CLEAR_VALUE,
> +	.color_table_index		= DC_FRAMEBUFFER_COLOR_TABLE_INDEX,
> +	.color_table_data		= DC_FRAMEBUFFER_COLOR_TABLE_DATA,
> +	.scale_config			= DC_FRAMEBUFFER_SCALE_CONFIG,
> +	.water_mark				= DC_FRAMEBUFFER_WATER_MARK,
> +	.degamma_index			= DC_FRAMEBUFFER_DEGAMMA_INDEX,
> +	.degamma_data			= DC_FRAMEBUFFER_DEGAMMA_DATA,
> +	.degamma_ex_data		= DC_FRAMEBUFFER_DEGAMMA_EX_DATA,
> +	.src_global_color		= DC_FRAMEBUFFER_SRC_GLOBAL_COLOR,
> +	.dst_global_color		= DC_FRAMEBUFFER_DST_GLOBAL_COLOR,
> +	.blend_config			= DC_FRAMEBUFFER_BLEND_CONFIG,
> +	.roi_origin				= DC_FRAMEBUFFER_ROI_ORIGIN,
> +	.roi_size				= DC_FRAMEBUFFER_ROI_SIZE,
> +	.yuv_to_rgb_coef0			= DC_FRAMEBUFFER_YUVTORGB_COEF0,
> +	.yuv_to_rgb_coef1			= DC_FRAMEBUFFER_YUVTORGB_COEF1,
> +	.yuv_to_rgb_coef2			= DC_FRAMEBUFFER_YUVTORGB_COEF2,
> +	.yuv_to_rgb_coef3			= DC_FRAMEBUFFER_YUVTORGB_COEF3,
> +	.yuv_to_rgb_coef4			= DC_FRAMEBUFFER_YUVTORGB_COEF4,
> +	.yuv_to_rgb_coefd0			= DC_FRAMEBUFFER_YUVTORGB_COEFD0,
> +	.yuv_to_rgb_coefd1			= DC_FRAMEBUFFER_YUVTORGB_COEFD1,
> +	.yuv_to_rgb_coefd2			= DC_FRAMEBUFFER_YUVTORGB_COEFD2,
> +	.y_clamp_bound				= DC_FRAMEBUFFER_Y_CLAMP_BOUND,
> +	.uv_clamp_bound				= DC_FRAMEBUFFER_UV_CLAMP_BOUND,
> +	.rgb_to_rgb_coef0			= DC_FRAMEBUFFER_RGBTORGB_COEF0,
> +	.rgb_to_rgb_coef1			= DC_FRAMEBUFFER_RGBTORGB_COEF1,
> +	.rgb_to_rgb_coef2			= DC_FRAMEBUFFER_RGBTORGB_COEF2,
> +	.rgb_to_rgb_coef3			= DC_FRAMEBUFFER_RGBTORGB_COEF3,
> +	.rgb_to_rgb_coef4			= DC_FRAMEBUFFER_RGBTORGB_COEF4,
> +	},
> +	{
> +	.y_address		= DC_OVERLAY_ADDRESS,
> +	.u_address		= DC_OVERLAY_U_ADDRESS,
> +	.v_address		= DC_OVERLAY_V_ADDRESS,
> +	.y_stride		= DC_OVERLAY_STRIDE,
> +	.u_stride		= DC_OVERLAY_U_STRIDE,
> +	.v_stride		= DC_OVERLAY_V_STRIDE,
> +	.size			= DC_OVERLAY_SIZE,
> +	.top_left		= DC_OVERLAY_TOP_LEFT,
> +	.bottom_right	= DC_OVERLAY_BOTTOM_RIGHT,
> +	.scale_factor_x	= DC_OVERLAY_SCALE_FACTOR_X,
> +	.scale_factor_y	= DC_OVERLAY_SCALE_FACTOR_Y,
> +	.h_filter_coef_index = DC_OVERLAY_H_FILTER_COEF_INDEX,
> +	.h_filter_coef_data  = DC_OVERLAY_H_FILTER_COEF_DATA,
> +	.v_filter_coef_index = DC_OVERLAY_V_FILTER_COEF_INDEX,
> +	.v_filter_coef_data  = DC_OVERLAY_V_FILTER_COEF_DATA,
> +	.init_offset		 = DC_OVERLAY_INIT_OFFSET,
> +	.color_key			 = DC_OVERLAY_COLOR_KEY,
> +	.color_key_high			= DC_OVERLAY_COLOR_KEY_HIGH,
> +	.clear_value		 = DC_OVERLAY_CLEAR_VALUE,
> +	.color_table_index	 = DC_OVERLAY_COLOR_TABLE_INDEX,
> +	.color_table_data	 = DC_OVERLAY_COLOR_TABLE_DATA,
> +	.scale_config		 = DC_OVERLAY_SCALE_CONFIG,
> +	.water_mark				= DC_OVERLAY_WATER_MARK,
> +	.degamma_index		 = DC_OVERLAY_DEGAMMA_INDEX,
> +	.degamma_data		 = DC_OVERLAY_DEGAMMA_DATA,
> +	.degamma_ex_data	 = DC_OVERLAY_DEGAMMA_EX_DATA,
> +	.src_global_color	 = DC_OVERLAY_SRC_GLOBAL_COLOR,
> +	.dst_global_color	 = DC_OVERLAY_DST_GLOBAL_COLOR,
> +	.blend_config		 = DC_OVERLAY_BLEND_CONFIG,
> +	.roi_origin				= DC_OVERLAY_ROI_ORIGIN,
> +	.roi_size				= DC_OVERLAY_ROI_SIZE,
> +	.yuv_to_rgb_coef0		 = DC_OVERLAY_YUVTORGB_COEF0,
> +	.yuv_to_rgb_coef1		 = DC_OVERLAY_YUVTORGB_COEF1,
> +	.yuv_to_rgb_coef2		 = DC_OVERLAY_YUVTORGB_COEF2,
> +	.yuv_to_rgb_coef3		 = DC_OVERLAY_YUVTORGB_COEF3,
> +	.yuv_to_rgb_coef4			= DC_OVERLAY_YUVTORGB_COEF4,
> +	.yuv_to_rgb_coefd0			= DC_OVERLAY_YUVTORGB_COEFD0,
> +	.yuv_to_rgb_coefd1			= DC_OVERLAY_YUVTORGB_COEFD1,
> +	.yuv_to_rgb_coefd2			= DC_OVERLAY_YUVTORGB_COEFD2,
> +	.y_clamp_bound		 = DC_OVERLAY_Y_CLAMP_BOUND,
> +	.uv_clamp_bound		 = DC_OVERLAY_UV_CLAMP_BOUND,
> +	.rgb_to_rgb_coef0		 = DC_OVERLAY_RGBTORGB_COEF0,
> +	.rgb_to_rgb_coef1		 = DC_OVERLAY_RGBTORGB_COEF1,
> +	.rgb_to_rgb_coef2		 = DC_OVERLAY_RGBTORGB_COEF2,
> +	.rgb_to_rgb_coef3		 = DC_OVERLAY_RGBTORGB_COEF3,
> +	.rgb_to_rgb_coef4		 = DC_OVERLAY_RGBTORGB_COEF4,
> +	},
> +};
> +
> +static const u32 primary_overlay_format0[] = {
> +	DRM_FORMAT_XRGB4444,
> +	DRM_FORMAT_XBGR4444,
> +	DRM_FORMAT_RGBX4444,
> +	DRM_FORMAT_BGRX4444,
> +	DRM_FORMAT_ARGB4444,
> +	DRM_FORMAT_ABGR4444,
> +	DRM_FORMAT_RGBA4444,
> +	DRM_FORMAT_BGRA4444,
> +	DRM_FORMAT_XRGB1555,
> +	DRM_FORMAT_XBGR1555,
> +	DRM_FORMAT_RGBX5551,
> +	DRM_FORMAT_BGRX5551,
> +	DRM_FORMAT_ARGB1555,
> +	DRM_FORMAT_ABGR1555,
> +	DRM_FORMAT_RGBA5551,
> +	DRM_FORMAT_BGRA5551,
> +	DRM_FORMAT_RGB565,
> +	DRM_FORMAT_BGR565,
> +	DRM_FORMAT_XRGB8888,
> +	DRM_FORMAT_XBGR8888,
> +	DRM_FORMAT_RGBX8888,
> +	DRM_FORMAT_BGRX8888,
> +	DRM_FORMAT_ARGB8888,
> +	DRM_FORMAT_ABGR8888,
> +	DRM_FORMAT_RGBA8888,
> +	DRM_FORMAT_BGRA8888,
> +	DRM_FORMAT_ARGB2101010,
> +	DRM_FORMAT_ABGR2101010,
> +	DRM_FORMAT_RGBA1010102,
> +	DRM_FORMAT_BGRA1010102,
> +	DRM_FORMAT_YUYV,
> +	DRM_FORMAT_YVYU,
> +	DRM_FORMAT_UYVY,
> +	DRM_FORMAT_VYUY,
> +	DRM_FORMAT_YVU420,
> +	DRM_FORMAT_YUV420,
> +	DRM_FORMAT_NV12,
> +	DRM_FORMAT_NV21,
> +	DRM_FORMAT_NV16,
> +	DRM_FORMAT_NV61,
> +	DRM_FORMAT_P010,
> +};
> +
> +static const u32 primary_overlay_format1[] = {
> +	DRM_FORMAT_XRGB8888,
> +	DRM_FORMAT_XBGR8888,
> +	DRM_FORMAT_RGBX8888,
> +	DRM_FORMAT_BGRX8888,
> +	DRM_FORMAT_ARGB8888,
> +	DRM_FORMAT_ABGR8888,
> +	DRM_FORMAT_RGBA8888,
> +	DRM_FORMAT_BGRA8888,
> +	DRM_FORMAT_ARGB2101010,
> +	DRM_FORMAT_ABGR2101010,
> +	DRM_FORMAT_RGBA1010102,
> +	DRM_FORMAT_BGRA1010102,
> +	DRM_FORMAT_NV12,
> +	DRM_FORMAT_NV21,
> +	DRM_FORMAT_YUV444,
> +};
> +
> +static const u32 cursor_formats[] = {
> +	DRM_FORMAT_ARGB8888
> +};
> +
> +static const u64 format_modifier0[] = {
> +	DRM_FORMAT_MOD_LINEAR,
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_LINEAR),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_TILE_8X8),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_TILE_8X4),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8),
> +	DRM_FORMAT_MOD_INVALID
> +};
> +
> +static const u64 format_modifier1[] = {
> +	DRM_FORMAT_MOD_LINEAR,
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_LINEAR),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_TILE_8X8),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_TILE_8X4),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VS_TILE_MODE4X4),
> +	fourcc_mod_vs_custom_code(DRM_FORMAT_MOD_VS_TILE_MODE4X4),
> +	DRM_FORMAT_MOD_INVALID
> +};
> +
> +static const u64 secondary_format_modifiers[] = {
> +	DRM_FORMAT_MOD_LINEAR,
> +	DRM_FORMAT_MOD_INVALID
> +};
> +
> +#define FRAC_16_16(mult, div)	 (((mult) << 16) / (div))
> +
> +static const struct vs_plane_info dc_hw_planes[][PLANE_NUM] = {
> +	{
> +		/* DC_REV_0 */
> +		{
> +		.name			= "Primary",
> +		.id				= PRIMARY_PLANE_0,
> +		.type			= DRM_PLANE_TYPE_PRIMARY,
> +		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
> +		.formats		= primary_overlay_format0,
> +		.num_modifiers	= ARRAY_SIZE(format_modifier0),
> +		.modifiers		= format_modifier0,
> +		.min_width		= 0,
> +		.min_height		= 0,
> +		.max_width		= 4096,
> +		.max_height		= 4096,
> +		.rotation		= DRM_MODE_ROTATE_0 |
> +							DRM_MODE_ROTATE_90 |
> +							DRM_MODE_ROTATE_180 |
> +							DRM_MODE_ROTATE_270 |
> +							DRM_MODE_REFLECT_X |
> +							DRM_MODE_REFLECT_Y,
> +		.blend_mode		= BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +							BIT(DRM_MODE_BLEND_PREMULTI) |
> +							BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 0,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name			= "Overlay",
> +		.id				= OVERLAY_PLANE_0,
> +		.type			= DRM_PLANE_TYPE_OVERLAY,
> +		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
> +		.formats		= primary_overlay_format0,
> +		.num_modifiers	= ARRAY_SIZE(format_modifier0),
> +		.modifiers		= format_modifier0,
> +		.min_width		= 0,
> +		.min_height		= 0,
> +		.max_width		= 4096,
> +		.max_height		= 4096,
> +		.rotation	 = DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_ROTATE_90 |
> +					   DRM_MODE_ROTATE_180 |
> +					   DRM_MODE_ROTATE_270 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 1,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name			= "Overlay_1",
> +		.id				= OVERLAY_PLANE_1,
> +		.type			= DRM_PLANE_TYPE_OVERLAY,
> +		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
> +		.formats		= primary_overlay_format0,
> +		.num_modifiers	= ARRAY_SIZE(secondary_format_modifiers),
> +		.modifiers		= secondary_format_modifiers,
> +		.min_width		= 0,
> +		.min_height		= 0,
> +		.max_width		= 4096,
> +		.max_height		= 4096,
> +		.rotation		= 0,
> +		.blend_mode		= BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +							BIT(DRM_MODE_BLEND_PREMULTI) |
> +							BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = DRM_PLANE_NO_SCALING,
> +		.max_scale	 = DRM_PLANE_NO_SCALING,
> +		.zpos		 = 2,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Primary_1",
> +		.id				= PRIMARY_PLANE_1,
> +		.type		 = DRM_PLANE_TYPE_PRIMARY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
> +		.formats	 = primary_overlay_format0,
> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
> +		.modifiers	 = format_modifier0,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_ROTATE_90 |
> +					   DRM_MODE_ROTATE_180 |
> +					   DRM_MODE_ROTATE_270 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 3,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Overlay_2",
> +		.id				= OVERLAY_PLANE_2,
> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
> +		.formats	 = primary_overlay_format0,
> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
> +		.modifiers	 = format_modifier0,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_ROTATE_90 |
> +					   DRM_MODE_ROTATE_180 |
> +					   DRM_MODE_ROTATE_270 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 4,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Overlay_3",
> +		.id			= OVERLAY_PLANE_3,
> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
> +		.formats	 = primary_overlay_format0,
> +		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
> +		.modifiers	 = secondary_format_modifiers,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = 0,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = DRM_PLANE_NO_SCALING,
> +		.max_scale	 = DRM_PLANE_NO_SCALING,
> +		.zpos		 = 5,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Cursor",
> +		.id				= CURSOR_PLANE_0,
> +		.type		 = DRM_PLANE_TYPE_CURSOR,
> +		.num_formats = ARRAY_SIZE(cursor_formats),
> +		.formats	 = cursor_formats,
> +		.num_modifiers = 0,
> +		.modifiers	 = NULL,
> +		.min_width	 = 32,
> +		.min_height  = 32,
> +		.max_width	 = 64,
> +		.max_height  = 64,
> +		.rotation	 = 0,
> +		.degamma_size = 0,
> +		.min_scale	 = DRM_PLANE_NO_SCALING,
> +		.max_scale	 = DRM_PLANE_NO_SCALING,
> +		.zpos		 = 255,
> +		.watermark	 = false,
> +		.color_mgmt  = false,
> +		.roi		 = false,
> +		},
> +		{
> +		.name		 = "Cursor_1",
> +		.id				= CURSOR_PLANE_1,
> +		.type		 = DRM_PLANE_TYPE_CURSOR,
> +		.num_formats = ARRAY_SIZE(cursor_formats),
> +		.formats	 = cursor_formats,
> +		.num_modifiers = 0,
> +		.modifiers	 = NULL,
> +		.min_width	 = 32,
> +		.min_height  = 32,
> +		.max_width	 = 64,
> +		.max_height  = 64,
> +		.rotation	 = 0,
> +		.degamma_size = 0,
> +		.min_scale	 = DRM_PLANE_NO_SCALING,
> +		.max_scale	 = DRM_PLANE_NO_SCALING,
> +		.zpos		 = 255,
> +		.watermark	 = false,
> +		.color_mgmt  = false,
> +		.roi		 = false,
> +		},
> +	},
> +	{
> +		/* DC_REV_1 */
> +		{
> +		.name		 = "Primary",
> +		.id				= PRIMARY_PLANE_0,
> +		.type		 = DRM_PLANE_TYPE_PRIMARY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
> +		.formats	 = primary_overlay_format0,
> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
> +		.modifiers	 = format_modifier0,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_ROTATE_90 |
> +					   DRM_MODE_ROTATE_180 |
> +					   DRM_MODE_ROTATE_270 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 0,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Overlay",
> +		.id				= OVERLAY_PLANE_0,
> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
> +		.formats	 = primary_overlay_format0,
> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
> +		.modifiers	 = format_modifier0,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_ROTATE_90 |
> +					   DRM_MODE_ROTATE_180 |
> +					   DRM_MODE_ROTATE_270 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 1,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Primary_1",
> +		.id				= PRIMARY_PLANE_1,
> +		.type		 = DRM_PLANE_TYPE_PRIMARY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
> +		.formats	 = primary_overlay_format0,
> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
> +		.modifiers	 = format_modifier0,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_ROTATE_90 |
> +					   DRM_MODE_ROTATE_180 |
> +					   DRM_MODE_ROTATE_270 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 2,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Overlay_2",
> +		.id				= OVERLAY_PLANE_2,
> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
> +		.formats	 = primary_overlay_format0,
> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
> +		.modifiers	 = format_modifier0,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_ROTATE_90 |
> +					   DRM_MODE_ROTATE_180 |
> +					   DRM_MODE_ROTATE_270 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 3,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Cursor",
> +		.id				= CURSOR_PLANE_0,
> +		.type		 = DRM_PLANE_TYPE_CURSOR,
> +		.num_formats = ARRAY_SIZE(cursor_formats),
> +		.formats	 = cursor_formats,
> +		.num_modifiers = 0,
> +		.modifiers	 = NULL,
> +		.min_width	 = 32,
> +		.min_height  = 32,
> +		.max_width	 = 64,
> +		.max_height  = 64,
> +		.rotation	 = 0,
> +		.degamma_size = 0,
> +		.min_scale	 = DRM_PLANE_NO_SCALING,
> +		.max_scale	 = DRM_PLANE_NO_SCALING,
> +		.zpos		 = 255,
> +		.watermark	 = false,
> +		.color_mgmt  = false,
> +		.roi		 = false,
> +		},
> +		{
> +		.name		 = "Cursor_1",
> +		.id				= CURSOR_PLANE_1,
> +		.type		 = DRM_PLANE_TYPE_CURSOR,
> +		.num_formats = ARRAY_SIZE(cursor_formats),
> +		.formats	 = cursor_formats,
> +		.num_modifiers = 0,
> +		.modifiers	 = NULL,
> +		.min_width	 = 32,
> +		.min_height  = 32,
> +		.max_width	 = 64,
> +		.max_height  = 64,
> +		.rotation	 = 0,
> +		.degamma_size = 0,
> +		.min_scale	 = DRM_PLANE_NO_SCALING,
> +		.max_scale	 = DRM_PLANE_NO_SCALING,
> +		.zpos		 = 255,
> +		.watermark	 = false,
> +		.color_mgmt  = false,
> +		.roi		 = false,
> +		},
> +	},
> +	{
> +		/* DC_REV_2 */
> +		{
> +		.name		 = "Primary",
> +		.id				= PRIMARY_PLANE_0,
> +		.type		 = DRM_PLANE_TYPE_PRIMARY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
> +		.formats	 = primary_overlay_format1,
> +		.num_modifiers = ARRAY_SIZE(format_modifier1),
> +		.modifiers	 = format_modifier1,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_ROTATE_90 |
> +					   DRM_MODE_ROTATE_180 |
> +					   DRM_MODE_ROTATE_270 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 0,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Overlay",
> +		.id				= OVERLAY_PLANE_0,
> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
> +		.formats	 = primary_overlay_format1,
> +		.num_modifiers = ARRAY_SIZE(format_modifier1),
> +		.modifiers	 = format_modifier1,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_ROTATE_90 |
> +					   DRM_MODE_ROTATE_180 |
> +					   DRM_MODE_ROTATE_270 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 1,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Overlay_1",
> +		.id				= OVERLAY_PLANE_1,
> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
> +		.formats	 = primary_overlay_format1,
> +		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
> +		.modifiers	 = secondary_format_modifiers,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = 0,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = DRM_PLANE_NO_SCALING,
> +		.max_scale	 = DRM_PLANE_NO_SCALING,
> +		.zpos		 = 2,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Primary_1",
> +		.id				= PRIMARY_PLANE_1,
> +		.type		 = DRM_PLANE_TYPE_PRIMARY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
> +		.formats	 = primary_overlay_format1,
> +		.num_modifiers = ARRAY_SIZE(format_modifier1),
> +		.modifiers	 = format_modifier1,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_ROTATE_90 |
> +					   DRM_MODE_ROTATE_180 |
> +					   DRM_MODE_ROTATE_270 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 3,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Overlay_2",
> +		.id				= OVERLAY_PLANE_2,
> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
> +		.formats	 = primary_overlay_format1,
> +		.num_modifiers = ARRAY_SIZE(format_modifier1),
> +		.modifiers	 = format_modifier1,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_ROTATE_90 |
> +					   DRM_MODE_ROTATE_180 |
> +					   DRM_MODE_ROTATE_270 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = FRAC_16_16(1, 3),
> +		.max_scale	 = FRAC_16_16(10, 1),
> +		.zpos		 = 4,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Overlay_3",
> +		.id				= OVERLAY_PLANE_3,
> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
> +		.formats	 = primary_overlay_format1,
> +		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
> +		.modifiers	 = secondary_format_modifiers,
> +		.min_width	 = 0,
> +		.min_height  = 0,
> +		.max_width	 = 4096,
> +		.max_height  = 4096,
> +		.rotation	 = 0,
> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
> +					   BIT(DRM_MODE_BLEND_COVERAGE),
> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> +						  BIT(DRM_COLOR_YCBCR_BT2020),
> +		.degamma_size	= DEGAMMA_SIZE,
> +		.min_scale	 = DRM_PLANE_NO_SCALING,
> +		.max_scale	 = DRM_PLANE_NO_SCALING,
> +		.zpos		 = 5,
> +		.watermark	 = true,
> +		.color_mgmt  = true,
> +		.roi		 = true,
> +		},
> +		{
> +		.name		 = "Cursor",
> +		.id				= CURSOR_PLANE_0,
> +		.type		 = DRM_PLANE_TYPE_CURSOR,
> +		.num_formats = ARRAY_SIZE(cursor_formats),
> +		.formats	 = cursor_formats,
> +		.num_modifiers = 0,
> +		.modifiers	 = NULL,
> +		.min_width	 = 32,
> +		.min_height  = 32,
> +		.max_width	 = 64,
> +		.max_height  = 64,
> +		.rotation	 = 0,
> +		.degamma_size = 0,
> +		.min_scale	 = DRM_PLANE_NO_SCALING,
> +		.max_scale	 = DRM_PLANE_NO_SCALING,
> +		.zpos		 = 255,
> +		.watermark	 = false,
> +		.color_mgmt  = false,
> +		.roi		 = false,
> +		},
> +		{
> +		.name		 = "Cursor_1",
> +		.id				= CURSOR_PLANE_1,
> +		.type		 = DRM_PLANE_TYPE_CURSOR,
> +		.num_formats = ARRAY_SIZE(cursor_formats),
> +		.formats	 = cursor_formats,
> +		.num_modifiers = 0,
> +		.modifiers	 = NULL,
> +		.min_width	 = 32,
> +		.min_height  = 32,
> +		.max_width	 = 64,
> +		.max_height  = 64,
> +		.rotation	 = 0,
> +		.degamma_size = 0,
> +		.min_scale	 = DRM_PLANE_NO_SCALING,
> +		.max_scale	 = DRM_PLANE_NO_SCALING,
> +		.zpos		 = 255,
> +		.watermark	 = false,
> +		.color_mgmt  = false,
> +		.roi		 = false,
> +		},
> +	},
> +};
> +
> +static const struct vs_dc_info dc_info[] = {
> +	{
> +		/* DC_REV_0 */
> +		.name			= "DC8200",
> +		.panel_num		= 2,
> +		.plane_num		= 8,
> +		.planes			= dc_hw_planes[DC_REV_0],
> +		.layer_num		= 6,
> +		.max_bpc		= 10,
> +		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
> +						  DRM_COLOR_FORMAT_YCBCR444 |
> +						  DRM_COLOR_FORMAT_YCBCR422 |
> +						  DRM_COLOR_FORMAT_YCBCR420,
> +		.gamma_size		= GAMMA_EX_SIZE,
> +		.gamma_bits		= 12,
> +		.pitch_alignment	= 128,
> +		.pipe_sync		= false,
> +		.mmu_prefetch	= false,
> +		.background		= true,
> +		.panel_sync		= true,
> +		.cap_dec		= true,
> +	},
> +	{
> +		/* DC_REV_1 */
> +		.name			= "DC8200",
> +		.panel_num		= 2,
> +		.plane_num		= 6,
> +		.planes			= dc_hw_planes[DC_REV_1],
> +		.layer_num		= 4,
> +		.max_bpc		= 10,
> +		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
> +						  DRM_COLOR_FORMAT_YCBCR444 |
> +						  DRM_COLOR_FORMAT_YCBCR422 |
> +						  DRM_COLOR_FORMAT_YCBCR420,
> +		.gamma_size		= GAMMA_EX_SIZE,
> +		.gamma_bits		= 12,
> +		.pitch_alignment	= 128,
> +		.pipe_sync		= false,
> +		.mmu_prefetch	= false,
> +		.background		= true,
> +		.panel_sync		= true,
> +		.cap_dec		= true,
> +	},
> +	{
> +		/* DC_REV_2 */
> +		.name			= "DC8200",
> +		.panel_num		= 2,
> +		.plane_num		= 8,
> +		.planes			= dc_hw_planes[DC_REV_2],
> +		.layer_num		= 6,
> +		.max_bpc		= 10,
> +		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
> +						  DRM_COLOR_FORMAT_YCBCR444 |
> +						  DRM_COLOR_FORMAT_YCBCR422 |
> +						  DRM_COLOR_FORMAT_YCBCR420,
> +		.gamma_size		= GAMMA_EX_SIZE,
> +		.gamma_bits		= 12,
> +		.pitch_alignment	= 128,
> +		.pipe_sync		= false,
> +		.mmu_prefetch	= false,
> +		.background		= true,
> +		.panel_sync		= true,
> +		.cap_dec		= false,
> +	},
> +};
> +
> +static const struct dc_hw_funcs hw_func;
> +
> +static inline u32 hi_read(struct dc_hw *hw, u32 reg)
> +{
> +	return readl(hw->hi_base + reg);
> +}
> +
> +static inline void hi_write(struct dc_hw *hw, u32 reg, u32 value)
> +{
> +	writel(value, hw->hi_base + reg);
> +}
> +
> +static inline void dc_write(struct dc_hw *hw, u32 reg, u32 value)
> +{
> +	writel(value, hw->reg_base + reg - DC_REG_BASE);
> +}
> +
> +static inline u32 dc_read(struct dc_hw *hw, u32 reg)
> +{
> +	u32 value = readl(hw->reg_base + reg - DC_REG_BASE);
> +
> +	return value;
> +}
> +
> +static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32 set, u32 clear)
> +{
> +	u32 value = dc_read(hw, reg);
> +
> +	value &= ~clear;
> +	value |= set;
> +	dc_write(hw, reg, value);
> +}
> +
> +static void load_default_filter(struct dc_hw *hw,
> +				const struct dc_hw_plane_reg *reg, u32 offset)
> +{
> +	u8 i;
> +
> +	dc_write(hw, reg->scale_config + offset, 0x33);
> +	dc_write(hw, reg->init_offset + offset, 0x80008000);
> +	dc_write(hw, reg->h_filter_coef_index + offset, 0x00);
> +	for (i = 0; i < H_COEF_SIZE; i++)
> +		dc_write(hw, reg->h_filter_coef_data + offset, horkernel[i]);
> +
> +	dc_write(hw, reg->v_filter_coef_index + offset, 0x00);
> +	for (i = 0; i < V_COEF_SIZE; i++)
> +		dc_write(hw, reg->v_filter_coef_data + offset, verkernel[i]);
> +}
> +
> +static void load_rgb_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
> +			    u32 offset, u16 *table)
> +{
> +	dc_write(hw, reg->rgb_to_rgb_coef0 + offset, table[0] | (table[1] << 16));
> +	dc_write(hw, reg->rgb_to_rgb_coef1 + offset, table[2] | (table[3] << 16));
> +	dc_write(hw, reg->rgb_to_rgb_coef2 + offset, table[4] | (table[5] << 16));
> +	dc_write(hw, reg->rgb_to_rgb_coef3 + offset, table[6] | (table[7] << 16));
> +	dc_write(hw, reg->rgb_to_rgb_coef4 + offset, table[8]);
> +}
> +
> +static void load_yuv_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
> +			    u32 offset, s32 *table)
> +{
> +	dc_write(hw, reg->yuv_to_rgb_coef0 + offset,
> +		 (0xFFFF & table[0]) | (table[1] << 16));
> +	dc_write(hw, reg->yuv_to_rgb_coef1 + offset,
> +		 (0xFFFF & table[2]) | (table[3] << 16));
> +	dc_write(hw, reg->yuv_to_rgb_coef2 + offset,
> +		 (0xFFFF & table[4]) | (table[5] << 16));
> +	dc_write(hw, reg->yuv_to_rgb_coef3 + offset,
> +		 (0xFFFF & table[6]) | (table[7] << 16));
> +	dc_write(hw, reg->yuv_to_rgb_coef4 + offset, table[8]);
> +	dc_write(hw, reg->yuv_to_rgb_coefd0 + offset, table[9]);
> +	dc_write(hw, reg->yuv_to_rgb_coefd1 + offset, table[10]);
> +	dc_write(hw, reg->yuv_to_rgb_coefd2 + offset, table[11]);
> +	dc_write(hw, reg->y_clamp_bound + offset, table[12] | (table[13] << 16));
> +	dc_write(hw, reg->uv_clamp_bound + offset, table[14] | (table[15] << 16));
> +}
> +
> +static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16 *table)
> +{
> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF0 + offset,
> +		 table[0] | (table[1] << 16));
> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF1 + offset,
> +		 table[2] | (table[3] << 16));
> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF2 + offset,
> +		 table[4] | (table[5] << 16));
> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF3 + offset,
> +		 table[6] | (table[7] << 16));
> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF4 + offset, table[8]);
> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD0 + offset, table[9]);
> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD1 + offset, table[10]);
> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD2 + offset, table[11]);
> +}
> +
> +static bool is_rgb(enum dc_hw_color_format format)
> +{
> +	switch (format) {
> +	case FORMAT_X4R4G4B4:
> +	case FORMAT_A4R4G4B4:
> +	case FORMAT_X1R5G5B5:
> +	case FORMAT_A1R5G5B5:
> +	case FORMAT_R5G6B5:
> +	case FORMAT_X8R8G8B8:
> +	case FORMAT_A8R8G8B8:
> +	case FORMAT_A2R10G10B10:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static void load_degamma_table(struct dc_hw *hw,
> +			       const struct dc_hw_plane_reg *reg,
> +			       u32 offset, u16 *table)
> +{
> +	u16 i;
> +	u32 value;
> +
> +	dc_write(hw, reg->degamma_index + offset, 0);
> +
> +	for (i = 0; i < DEGAMMA_SIZE; i++) {
> +		value = table[i] | (table[i] << 16);
> +		dc_write(hw, reg->degamma_data + offset, value);
> +		dc_write(hw, reg->degamma_ex_data + offset, table[i]);
> +	}
> +}
> +
> +static u32 get_addr_offset(u32 id)
> +{
> +	u32 offset = 0;
> +
> +	switch (id) {
> +	case PRIMARY_PLANE_1:
> +	case OVERLAY_PLANE_1:
> +		offset = 0x04;
> +		break;
> +	case OVERLAY_PLANE_2:
> +		offset = 0x08;
> +		break;
> +	case OVERLAY_PLANE_3:
> +		offset = 0x0C;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return offset;
> +}
> +
> +int dc_hw_init(struct dc_hw *hw)
> +{
> +	u8 i, id, panel_num, layer_num;
> +	u32 offset;
> +	u32 revision = hi_read(hw, DC_HW_REVISION);
> +	u32 cid = hi_read(hw, DC_HW_CHIP_CID);
> +	const struct dc_hw_plane_reg *reg;
> +
> +	switch (revision) {
> +	case 0x5720:
> +		hw->rev = DC_REV_0;
> +		break;
> +	case 0x5721:
> +		switch (cid) {
> +		case 0x30B:
> +			hw->rev = DC_REV_1;
> +			break;
> +		case 0x310:
> +			hw->rev = DC_REV_2;
> +			break;
> +		default:
> +			hw->rev = DC_REV_0;
> +			break;
> +		}
> +		break;
> +	default:
> +		return -ENXIO;
> +	}
> +
> +	hw->info = (struct vs_dc_info *)&dc_info[hw->rev];
> +	hw->func = (struct dc_hw_funcs *)&hw_func;
> +
> +	layer_num = hw->info->layer_num;
> +	for (i = 0; i < layer_num; i++) {
> +		id = hw->info->planes[i].id;
> +		offset = get_addr_offset(id);
> +		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> +			reg = &dc_plane_reg[0];
> +		else
> +			reg = &dc_plane_reg[1];
> +
> +		load_default_filter(hw, reg, offset);
> +		load_rgb_to_rgb(hw, reg, offset, RGB2RGB);
> +	}
> +
> +	panel_num = hw->info->panel_num;
> +	for (i = 0; i < panel_num; i++) {
> +		offset = i << 2;
> +
> +		load_rgb_to_yuv(hw, offset, RGB2YUV);
> +		dc_write(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0x111);
> +
> +		offset = i ? DC_CURSOR_OFFSET : 0;
> +		dc_write(hw, DC_CURSOR_BACKGROUND + offset, 0x00FFFFFF);
> +		dc_write(hw, DC_CURSOR_FOREGROUND + offset, 0x00AAAAAA);
> +	}
> +
> +	return 0;
> +}
> +
> +void dc_hw_deinit(struct dc_hw *hw)
> +{
> +	/* Nothing to do */
> +}
> +
> +void dc_hw_update_plane(struct dc_hw *hw, u8 id,
> +			struct dc_hw_fb *fb, struct dc_hw_scale *scale,
> +			struct dc_hw_position *pos, struct dc_hw_blend *blend)
> +{
> +	struct dc_hw_plane *plane = &hw->plane[id];
> +
> +	if (plane) {
> +		if (fb) {
> +			if (!fb->enable)
> +				plane->fb.enable = false;
> +			else
> +				memcpy(&plane->fb, fb,
> +				       sizeof(*fb) - sizeof(fb->dirty));
> +			plane->fb.dirty = true;
> +		}
> +		if (scale) {
> +			memcpy(&plane->scale, scale,
> +			       sizeof(*scale) - sizeof(scale->dirty));
> +			plane->scale.dirty = true;
> +		}
> +		if (pos) {
> +			memcpy(&plane->pos, pos,
> +			       sizeof(*pos) - sizeof(pos->dirty));
> +			plane->pos.dirty = true;
> +		}
> +		if (blend) {
> +			memcpy(&plane->blend, blend,
> +			       sizeof(*blend) - sizeof(blend->dirty));
> +			plane->blend.dirty = true;
> +		}
> +	}
> +}
> +
> +void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode)
> +{
> +	struct dc_hw_plane *plane = &hw->plane[id];
> +
> +	if (plane) {
> +		if (hw->info->planes[id].degamma_size) {
> +			plane->degamma.mode = mode;
> +			plane->degamma.dirty = true;
> +		} else {
> +			plane->degamma.dirty = false;
> +		}
> +	}
> +}
> +
> +void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi)
> +{
> +	struct dc_hw_plane *plane = &hw->plane[id];
> +
> +	if (plane) {
> +		memcpy(&plane->roi, roi, sizeof(*roi) - sizeof(roi->dirty));
> +		plane->roi.dirty = true;
> +	}
> +}
> +
> +void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
> +			   struct dc_hw_colorkey *colorkey)
> +{
> +	struct dc_hw_plane *plane = &hw->plane[id];
> +
> +	if (plane) {
> +		memcpy(&plane->colorkey, colorkey,
> +		       sizeof(*colorkey) - sizeof(colorkey->dirty));
> +		plane->colorkey.dirty = true;
> +	}
> +}
> +
> +void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos)
> +{
> +	memcpy(&hw->qos, qos, sizeof(*qos) - sizeof(qos->dirty));
> +	hw->qos.dirty = true;
> +}
> +
> +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor)
> +{
> +	memcpy(&hw->cursor[id], cursor, sizeof(*cursor) - sizeof(cursor->dirty));
> +	hw->cursor[id].dirty = true;
> +}
> +
> +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
> +			u16 r, u16 g, u16 b)
> +{
> +	if (index >= hw->info->gamma_size)
> +		return;
> +
> +	hw->gamma[id].gamma[index][0] = r;
> +	hw->gamma[id].gamma[index][1] = g;
> +	hw->gamma[id].gamma[index][2] = b;
> +	hw->gamma[id].dirty = true;
> +}
> +
> +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable)
> +{
> +	hw->gamma[id].enable = enable;
> +	hw->gamma[id].dirty = true;
> +}
> +
> +void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display)
> +{
> +	u8 id = display->id;
> +
> +	memcpy(&hw->display[id], display, sizeof(*display));
> +
> +	hw->func->display(hw, display);
> +}
> +
> +void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable)
> +{
> +	if (enable)
> +		hi_write(hw, AQ_INTR_ENBL, 0xFFFFFFFF);
> +	else
> +		hi_write(hw, AQ_INTR_ENBL, 0);
> +}
> +
> +u32 dc_hw_get_interrupt(struct dc_hw *hw)
> +{
> +	return hi_read(hw, AQ_INTR_ACKNOWLEDGE);
> +}
> +
> +bool dc_hw_check_underflow(struct dc_hw *hw)
> +{
> +	return dc_read(hw, DC_FRAMEBUFFER_CONFIG) & BIT(5);
> +}
> +
> +void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable)
> +{
> +	u32 i, offset;
> +	u8 id, layer_num = hw->info->layer_num;
> +	u8 panel_num = hw->info->panel_num;
> +
> +	for (i = 0; i < layer_num; i++) {
> +		id = hw->info->planes[i].id;
> +		offset = get_addr_offset(id);
> +		if (enable) {
> +			if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, BIT(12), 0);
> +			else
> +				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, BIT(31), 0);
> +		} else {
> +			if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, 0, BIT(12));
> +			else
> +				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, 0, BIT(31));
> +		}
> +	}
> +
> +	for (i = 0; i < panel_num; i++) {
> +		offset = i << 2;
> +		if (enable)
> +			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, 0, BIT(0));
> +		else
> +			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, BIT(0), 0);
> +	}
> +}
> +
> +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id)
> +{
> +	if (out <= OUT_DP)
> +		hw->out[id] = out;
> +}
> +
> +static void gamma_ex_commit(struct dc_hw *hw)
> +{
> +	u8 panel_num = hw->info->panel_num;
> +	u16 i, j;
> +	u32 value;
> +
> +	for (j = 0; j < panel_num; j++) {
> +		if (hw->gamma[j].dirty) {
> +			if (hw->gamma[j].enable) {
> +				dc_write(hw, DC_DISPLAY_GAMMA_EX_INDEX + (j << 2), 0x00);
> +				for (i = 0; i < GAMMA_EX_SIZE; i++) {
> +					value = hw->gamma[j].gamma[i][2] |
> +						(hw->gamma[j].gamma[i][1] << 12);
> +					dc_write(hw, DC_DISPLAY_GAMMA_EX_DATA + (j << 2), value);
> +					dc_write(hw, DC_DISPLAY_GAMMA_EX_ONE_DATA + (j << 2),
> +						 hw->gamma[j].gamma[i][0]);
> +				}
> +				dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
> +					     BIT(13), 0);
> +			} else {
> +				dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
> +					     0, BIT(13));
> +			}
> +			hw->gamma[j].dirty = false;
> +		}
> +	}
> +}
> +
> +static void plane_commit(struct dc_hw *hw)
> +{
> +	struct dc_hw_plane *plane;
> +	const struct dc_hw_plane_reg *reg;
> +	bool primary = false;
> +	u8 id, layer_num = hw->info->layer_num;
> +	u32 i, offset;
> +
> +	for (i = 0; i < layer_num; i++) {
> +		plane = &hw->plane[i];
> +		id = hw->info->planes[i].id;
> +		offset = get_addr_offset(id);
> +		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
> +			reg = &dc_plane_reg[0];
> +			primary = true;
> +		} else {
> +			reg = &dc_plane_reg[1];
> +			primary = false;
> +		}
> +
> +		if (plane->fb.dirty) {
> +			if (plane->fb.enable) {
> +				dc_write(hw, reg->y_address + offset,
> +					 plane->fb.y_address);
> +				dc_write(hw, reg->u_address + offset,
> +					 plane->fb.u_address);
> +				dc_write(hw, reg->v_address + offset,
> +					 plane->fb.v_address);
> +				dc_write(hw, reg->y_stride + offset,
> +					 plane->fb.y_stride);
> +				dc_write(hw, reg->u_stride + offset,
> +					 plane->fb.u_stride);
> +				dc_write(hw, reg->v_stride + offset,
> +					 plane->fb.v_stride);
> +				dc_write(hw, reg->size + offset,
> +					 plane->fb.width |
> +					 (plane->fb.height << 15));
> +				dc_write(hw, reg->water_mark + offset,
> +					 plane->fb.water_mark);
> +
> +				if (plane->fb.clear_enable)
> +					dc_write(hw, reg->clear_value + offset,
> +						 plane->fb.clear_value);
> +			}
> +
> +			if (primary) {
> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
> +					     (plane->fb.format << 26) |
> +					     (plane->fb.uv_swizzle << 25) |
> +					     (plane->fb.swizzle << 23) |
> +					     (plane->fb.tile_mode << 17) |
> +					     (plane->fb.yuv_color_space << 14) |
> +					     (plane->fb.rotation << 11) |
> +					     (plane->fb.clear_enable << 8),
> +					     (0x1F << 26) |
> +					     BIT(25) |
> +					     (0x03 << 23) |
> +					     (0x1F << 17) |
> +					     (0x07 << 14) |
> +					     (0x07 << 11) |
> +					     BIT(8));
> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> +					     (plane->fb.dec_enable << 1) |
> +					     (plane->fb.enable << 13) |
> +					     (plane->fb.zpos << 16) |
> +					     (plane->fb.display_id << 19),
> +					     BIT(1) | BIT(13) | (0x07 << 16) | BIT(19));
> +			} else {
> +				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> +					     (plane->fb.dec_enable << 27) |
> +					     (plane->fb.clear_enable << 25) |
> +					     (plane->fb.enable << 24) |
> +					     (plane->fb.format << 16) |
> +					     (plane->fb.uv_swizzle << 15) |
> +					     (plane->fb.swizzle << 13) |
> +					     (plane->fb.tile_mode << 8) |
> +					     (plane->fb.yuv_color_space << 5) |
> +					     (plane->fb.rotation << 2),
> +					     BIT(27) |
> +					     BIT(25) |
> +					     BIT(24) |
> +					     (0x1F << 16) |
> +					     BIT(15) |
> +					     (0x03 << 13) |
> +					     (0x1F << 8) |
> +					     (0x07 << 5) |
> +					     (0x07 << 2));
> +				dc_set_clear(hw, DC_OVERLAY_CONFIG_EX + offset,
> +					     plane->fb.zpos | (plane->fb.display_id << 3),
> +					     0x07 | BIT(3));
> +			}
> +			plane->fb.dirty = false;
> +		}
> +
> +		if (plane->scale.dirty) {
> +			if (plane->scale.enable) {
> +				dc_write(hw, reg->scale_factor_x + offset,
> +					 plane->scale.scale_factor_x);
> +				dc_write(hw, reg->scale_factor_y + offset,
> +					 plane->scale.scale_factor_y);
> +				if (primary)
> +					dc_set_clear(hw,
> +						     DC_FRAMEBUFFER_CONFIG + offset,
> +						     BIT(22), 0);
> +				else
> +					dc_set_clear(hw,
> +						     DC_OVERLAY_SCALE_CONFIG + offset,
> +						     BIT(8), 0);
> +			} else {
> +				if (primary)
> +					dc_set_clear(hw,
> +						     DC_FRAMEBUFFER_CONFIG + offset,
> +						     0, BIT(22));
> +				else
> +					dc_set_clear(hw,
> +						     DC_OVERLAY_SCALE_CONFIG + offset,
> +						     0, BIT(8));
> +			}
> +			plane->scale.dirty = false;
> +		}
> +
> +		if (plane->pos.dirty) {
> +			dc_write(hw, reg->top_left + offset,
> +				 plane->pos.start_x |
> +				 (plane->pos.start_y << 15));
> +			dc_write(hw, reg->bottom_right + offset,
> +				 plane->pos.end_x |
> +				 (plane->pos.end_y << 15));
> +			plane->pos.dirty = false;
> +		}
> +
> +		if (plane->blend.dirty) {
> +			dc_write(hw, reg->src_global_color + offset,
> +				 plane->blend.alpha << 24);
> +			dc_write(hw, reg->dst_global_color + offset,
> +				 plane->blend.alpha << 24);
> +			switch (plane->blend.blend_mode) {
> +			case BLEND_PREMULTI:
> +				dc_write(hw, reg->blend_config + offset, 0x3450);
> +				break;
> +			case BLEND_COVERAGE:
> +				dc_write(hw, reg->blend_config + offset, 0x3950);
> +				break;
> +			case BLEND_PIXEL_NONE:
> +				dc_write(hw, reg->blend_config + offset, 0x3548);
> +				break;
> +			default:
> +				break;
> +			}
> +			plane->blend.dirty = false;
> +		}
> +
> +		if (plane->colorkey.dirty) {
> +			dc_write(hw, reg->color_key + offset, plane->colorkey.colorkey);
> +			dc_write(hw, reg->color_key_high + offset,
> +				 plane->colorkey.colorkey_high);
> +
> +			if (primary)
> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
> +					     plane->colorkey.transparency << 9, 0x03 << 9);
> +			else
> +				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> +					     plane->colorkey.transparency, 0x03);
> +
> +			plane->colorkey.dirty = false;
> +		}
> +
> +		if (plane->roi.dirty) {
> +			if (plane->roi.enable) {
> +				dc_write(hw, reg->roi_origin + offset,
> +					 plane->roi.x | (plane->roi.y << 16));
> +				dc_write(hw, reg->roi_size + offset,
> +					 plane->roi.width | (plane->roi.height << 16));
> +				if (primary)
> +					dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> +						     BIT(0), 0);
> +				else
> +					dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> +						     BIT(22), 0);
> +			} else {
> +				if (primary)
> +					dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> +						     0, BIT(0));
> +				else
> +					dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> +						     0, BIT(22));
> +			}
> +			plane->roi.dirty = false;
> +		}
> +	}
> +}
> +
> +static void plane_ex_commit(struct dc_hw *hw)
> +{
> +	struct dc_hw_plane *plane;
> +	const struct dc_hw_plane_reg *reg;
> +	bool primary = false;
> +	u8 id, layer_num = hw->info->layer_num;
> +	u32 i, offset;
> +
> +	for (i = 0; i < layer_num; i++) {
> +		plane = &hw->plane[i];
> +		id = hw->info->planes[i].id;
> +		offset = get_addr_offset(id);
> +		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
> +			reg = &dc_plane_reg[0];
> +			primary = true;
> +		} else {
> +			reg = &dc_plane_reg[1];
> +			primary = false;
> +		}
> +
> +		if (plane->fb.dirty) {
> +			if (is_rgb(plane->fb.format)) {
> +				if (primary)
> +					dc_set_clear(hw,
> +						     DC_FRAMEBUFFER_CONFIG_EX + offset,
> +						     BIT(6), BIT(8));
> +				else
> +					dc_set_clear(hw,
> +						     DC_OVERLAY_CONFIG + offset,
> +						     BIT(29), BIT(30));
> +			} else {
> +				if (primary)
> +					dc_set_clear(hw,
> +						     DC_FRAMEBUFFER_CONFIG_EX + offset,
> +						     BIT(8), BIT(6));
> +				else
> +					dc_set_clear(hw,
> +						     DC_OVERLAY_CONFIG + offset,
> +						     BIT(30), BIT(29));
> +				switch (plane->fb.yuv_color_space) {
> +				case COLOR_SPACE_601:
> +					load_yuv_to_rgb(hw, reg, offset, YUV601_2RGB);
> +					break;
> +				case COLOR_SPACE_709:
> +					load_yuv_to_rgb(hw, reg, offset, YUV709_2RGB);
> +					break;
> +				case COLOR_SPACE_2020:
> +					load_yuv_to_rgb(hw, reg, offset, YUV2020_2RGB);
> +					break;
> +				default:
> +					break;
> +				}
> +			}
> +		}
> +		if (plane->degamma.dirty) {
> +			switch (plane->degamma.mode) {
> +			case VS_DEGAMMA_DISABLE:
> +				if (primary)
> +					dc_set_clear(hw,
> +						     DC_FRAMEBUFFER_CONFIG_EX + offset,
> +						     0, BIT(5));
> +				else
> +					dc_set_clear(hw,
> +						     DC_OVERLAY_CONFIG + offset,
> +						     0, BIT(28));
> +				break;
> +			case VS_DEGAMMA_BT709:
> +				load_degamma_table(hw, reg, offset, DEGAMMA_709);
> +				if (primary)
> +					dc_set_clear(hw,
> +						     DC_FRAMEBUFFER_CONFIG_EX + offset,
> +						     BIT(5), 0);
> +				else
> +					dc_set_clear(hw,
> +						     DC_OVERLAY_CONFIG + offset,
> +						     BIT(28), 0);
> +				break;
> +			case VS_DEGAMMA_BT2020:
> +				load_degamma_table(hw, reg, offset, DEGAMMA_2020);
> +				if (primary)
> +					dc_set_clear(hw,
> +						     DC_FRAMEBUFFER_CONFIG_EX + offset,
> +						     BIT(5), 0);
> +				else
> +					dc_set_clear(hw,
> +						     DC_OVERLAY_CONFIG + offset,
> +						     BIT(28), 0);
> +				break;
> +			default:
> +				break;
> +			}
> +			plane->degamma.dirty = false;
> +		}
> +	}
> +	plane_commit(hw);
> +}
> +
> +static void setup_display(struct dc_hw *hw, struct dc_hw_display *display)
> +{
> +	u8 id = display->id;
> +	u32 dpi_cfg, offset = id << 2;
> +
> +	if (hw->display[id].enable) {
> +		switch (display->bus_format) {
> +		case MEDIA_BUS_FMT_RGB565_1X16:
> +			dpi_cfg = 0;
> +			break;
> +		case MEDIA_BUS_FMT_RGB666_1X18:
> +			dpi_cfg = 3;
> +			break;
> +		case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
> +			dpi_cfg = 4;
> +			break;
> +		case MEDIA_BUS_FMT_RGB888_1X24:
> +			dpi_cfg = 5;
> +			break;
> +		case MEDIA_BUS_FMT_RGB101010_1X30:
> +			dpi_cfg = 6;
> +			break;
> +		default:
> +			dpi_cfg = 5;
> +			break;
> +		}
> +		dc_write(hw, DC_DISPLAY_DPI_CONFIG + offset, dpi_cfg);
> +
> +		if (id == 0)
> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
> +		else
> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
> +
> +		dc_write(hw, DC_DISPLAY_H + offset, hw->display[id].h_active |
> +			 (hw->display[id].h_total << 16));
> +		dc_write(hw, DC_DISPLAY_H_SYNC + offset,
> +			 hw->display[id].h_sync_start |
> +			 (hw->display[id].h_sync_end << 15) |
> +			 (hw->display[id].h_sync_polarity ? 0 : BIT(31)) |
> +			 BIT(30));
> +		dc_write(hw, DC_DISPLAY_V + offset, hw->display[id].v_active |
> +				(hw->display[id].v_total << 16));
> +		dc_write(hw, DC_DISPLAY_V_SYNC + offset,
> +			 hw->display[id].v_sync_start |
> +			 (hw->display[id].v_sync_end << 15) |
> +			 (hw->display[id].v_sync_polarity ? 0 : BIT(31)) |
> +			 BIT(30));
> +
> +		if (hw->info->pipe_sync) {
> +			switch (display->sync_mode) {
> +			case VS_SINGLE_DC:
> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX,
> +					     0, BIT(3) | BIT(4));
> +				break;
> +			case VS_MULTI_DC_PRIMARY:
> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX,
> +					     BIT(3) | BIT(4), 0);
> +				break;
> +			case VS_MULTI_DC_SECONDARY:
> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX,
> +					     BIT(3), BIT(4));
> +				break;
> +			default:
> +				break;
> +			}
> +		}
> +
> +		if (hw->info->background)
> +			dc_write(hw, DC_FRAMEBUFFER_BG_COLOR + offset,
> +				 hw->display[id].bg_color);
> +
> +		if (hw->display[id].dither_enable) {
> +			dc_write(hw, DC_DISPLAY_DITHER_TABLE_LOW + offset,
> +				 DC_DISPLAY_DITHERTABLE_LOW);
> +			dc_write(hw, DC_DISPLAY_DITHER_TABLE_HIGH + offset,
> +				 DC_DISPLAY_DITHERTABLE_HIGH);
> +			dc_write(hw, DC_DISPLAY_DITHER_CONFIG + offset, BIT(31));
> +		} else {
> +			dc_write(hw, DC_DISPLAY_DITHER_CONFIG + offset, 0);
> +		}
> +
> +		dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(12), 0);
> +		if (hw->display[id].sync_enable)
> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(2) | BIT(3), 0);
> +		else if (id == 0)
> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(0), BIT(3));
> +		else
> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(1), BIT(3));
> +	} else {
> +		dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(12));
> +		if (id == 0)
> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
> +		else
> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
> +	}
> +}
> +
> +static void setup_display_ex(struct dc_hw *hw, struct dc_hw_display *display)
> +{
> +	u8 id = display->id;
> +	u32 dp_cfg, offset = id << 2;
> +	bool is_yuv = false;
> +
> +	if (hw->display[id].enable && hw->out[id] == OUT_DP) {
> +		switch (display->bus_format) {
> +		case MEDIA_BUS_FMT_RGB565_1X16:
> +			dp_cfg = 0;
> +			break;
> +		case MEDIA_BUS_FMT_RGB666_1X18:
> +			dp_cfg = 1;
> +			break;
> +		case MEDIA_BUS_FMT_RGB888_1X24:
> +			dp_cfg = 2;
> +			break;
> +		case MEDIA_BUS_FMT_RGB101010_1X30:
> +			dp_cfg = 3;
> +			break;
> +		case MEDIA_BUS_FMT_UYVY8_1X16:
> +			dp_cfg = 2 << 4;
> +			is_yuv = true;
> +			break;
> +		case MEDIA_BUS_FMT_YUV8_1X24:
> +			dp_cfg = 4 << 4;
> +			is_yuv = true;
> +			break;
> +		case MEDIA_BUS_FMT_UYVY10_1X20:
> +			dp_cfg = 8 << 4;
> +			is_yuv = true;
> +			break;
> +		case MEDIA_BUS_FMT_YUV10_1X30:
> +			dp_cfg = 10 << 4;
> +			is_yuv = true;
> +			break;
> +		case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> +			dp_cfg = 12 << 4;
> +			is_yuv = true;
> +			break;
> +		case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> +			dp_cfg = 13 << 4;
> +			is_yuv = true;
> +			break;
> +		default:
> +			dp_cfg = 2;
> +			break;
> +		}
> +		if (is_yuv)
> +			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(16), 0);
> +		else
> +			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(16));
> +		dc_write(hw, DC_DISPLAY_DP_CONFIG + offset, dp_cfg | BIT(3));
> +	}
> +
> +	if (hw->out[id] == OUT_DPI)
> +		dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, BIT(3));
> +
> +	setup_display(hw, display);
> +}
> +
> +static const struct dc_hw_funcs hw_func = {
> +	.gamma = &gamma_ex_commit,
> +	.plane = &plane_ex_commit,
> +	.display = setup_display_ex,
> +};
> +
> +void dc_hw_commit(struct dc_hw *hw)
> +{
> +	u32 i, offset = 0;
> +	u8 plane_num = hw->info->plane_num;
> +	u8 layer_num = hw->info->layer_num;
> +	u8 cursor_num = plane_num - layer_num;
> +
> +	hw->func->gamma(hw);
> +	hw->func->plane(hw);
> +
> +	for (i = 0; i < cursor_num; i++) {
> +		if (hw->cursor[i].dirty) {
> +			offset = hw->cursor[i].display_id ? DC_CURSOR_OFFSET : 0;
> +			if (hw->cursor[i].enable) {
> +				dc_write(hw, DC_CURSOR_ADDRESS + offset,
> +					 hw->cursor[i].address);
> +				dc_write(hw, DC_CURSOR_LOCATION + offset, hw->cursor[i].x |
> +					 (hw->cursor[i].y << 16));
> +				dc_set_clear(hw, DC_CURSOR_CONFIG + offset,
> +					     (hw->cursor[i].hot_x << 16) |
> +					     (hw->cursor[i].hot_y << 8) |
> +					     (hw->cursor[i].size << 5) |
> +					     BIT(3) | BIT(2) | 0x02,
> +					     (0xFF << 16) |
> +					     (0xFF << 8) |
> +					     (0x07 << 5) | 0x1F);
> +			} else {
> +				dc_set_clear(hw, DC_CURSOR_CONFIG + offset, BIT(3), 0x03);
> +			}
> +			hw->cursor[i].dirty = false;
> +		}
> +	}
> +
> +	if (hw->qos.dirty) {
> +		dc_set_clear(hw, DC_QOS_CONFIG, (hw->qos.high_value << 4) |
> +					 hw->qos.low_value, 0xFF);
> +		hw->qos.dirty = false;
> +	}
> +}
> +
> diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.h b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
> new file mode 100644
> index 000000000000..cd037718ecd5
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
> @@ -0,0 +1,496 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_DC_HW_H__
> +#define __VS_DC_HW_H__
> +
> +#include <linux/version.h>
> +
> +#define AQ_INTR_ACKNOWLEDGE				0x0010
> +#define AQ_INTR_ENBL					0x0014
> +#define DC_HW_REVISION					0x0024
> +#define DC_HW_CHIP_CID					0x0030
> +
> +#define DC_REG_BASE					0x0800
> +#define DC_REG_RANGE					0x2000
> +#define DC_SEC_REG_OFFSET				0x100000
> +
> +#define DC_FRAMEBUFFER_CONFIG				0x1518
> +#define DC_FRAMEBUFFER_CONFIG_EX			0x1cc0
> +#define DC_FRAMEBUFFER_SCALE_CONFIG			0x1520
> +#define DC_FRAMEBUFFER_TOP_LEFT				0x24d8
> +#define DC_FRAMEBUFFER_BOTTOM_RIGHT			0x24e0
> +#define DC_FRAMEBUFFER_ADDRESS				0x1400
> +#define DC_FRAMEBUFFER_U_ADDRESS			0x1530
> +#define DC_FRAMEBUFFER_V_ADDRESS			0x1538
> +#define DC_FRAMEBUFFER_STRIDE				0x1408
> +#define DC_FRAMEBUFFER_U_STRIDE				0x1800
> +#define DC_FRAMEBUFFER_V_STRIDE				0x1808
> +#define DC_FRAMEBUFFER_SIZE				0x1810
> +#define DC_FRAMEBUFFER_SCALE_FACTOR_X			0x1828
> +#define DC_FRAMEBUFFER_SCALE_FACTOR_Y			0x1830
> +#define DC_FRAMEBUFFER_H_FILTER_COEF_INDEX		0x1838
> +#define DC_FRAMEBUFFER_H_FILTER_COEF_DATA		0x1a00
> +#define DC_FRAMEBUFFER_V_FILTER_COEF_INDEX		0x1a08
> +#define DC_FRAMEBUFFER_V_FILTER_COEF_DATA		0x1a10
> +#define DC_FRAMEBUFFER_INIT_OFFSET			0x1a20
> +#define DC_FRAMEBUFFER_COLOR_KEY			0x1508
> +#define DC_FRAMEBUFFER_COLOR_KEY_HIGH			0x1510
> +#define DC_FRAMEBUFFER_CLEAR_VALUE			0x1a18
> +#define DC_FRAMEBUFFER_COLOR_TABLE_INDEX		0x1818
> +#define DC_FRAMEBUFFER_COLOR_TABLE_DATA			0x1820
> +#define DC_FRAMEBUFFER_BG_COLOR				0x1528
> +#define DC_FRAMEBUFFER_ROI_ORIGIN			0x1cb0
> +#define DC_FRAMEBUFFER_ROI_SIZE				0x1cb8
> +#define DC_FRAMEBUFFER_WATER_MARK			0x1ce8
> +#define DC_FRAMEBUFFER_DEGAMMA_INDEX			0x1d88
> +#define DC_FRAMEBUFFER_DEGAMMA_DATA			0x1d90
> +#define DC_FRAMEBUFFER_DEGAMMA_EX_DATA			0x1d98
> +#define DC_FRAMEBUFFER_YUVTORGB_COEF0			0x1da0
> +#define DC_FRAMEBUFFER_YUVTORGB_COEF1			0x1da8
> +#define DC_FRAMEBUFFER_YUVTORGB_COEF2			0x1db0
> +#define DC_FRAMEBUFFER_YUVTORGB_COEF3			0x1db8
> +#define DC_FRAMEBUFFER_YUVTORGB_COEF4			0x1e00
> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD0			0x1e08
> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD1			0x1e10
> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD2			0x1e18
> +#define DC_FRAMEBUFFER_Y_CLAMP_BOUND			0x1e88
> +#define DC_FRAMEBUFFER_UV_CLAMP_BOUND			0x1e90
> +#define DC_FRAMEBUFFER_RGBTORGB_COEF0			0x1e20
> +#define DC_FRAMEBUFFER_RGBTORGB_COEF1			0x1e28
> +#define DC_FRAMEBUFFER_RGBTORGB_COEF2			0x1e30
> +#define DC_FRAMEBUFFER_RGBTORGB_COEF3			0x1e38
> +#define DC_FRAMEBUFFER_RGBTORGB_COEF4			0x1e40
> +#define DC_FRAMEBUFFER_BLEND_CONFIG			0x2510
> +#define DC_FRAMEBUFFER_SRC_GLOBAL_COLOR			0x2500
> +#define DC_FRAMEBUFFER_DST_GLOBAL_COLOR			0x2508
> +
> +#define DC_OVERLAY_CONFIG				0x1540
> +#define DC_OVERLAY_CONFIG_EX				0x2540
> +#define DC_OVERLAY_SCALE_CONFIG				0x1c00
> +#define DC_OVERLAY_BLEND_CONFIG				0x1580
> +#define DC_OVERLAY_TOP_LEFT				0x1640
> +#define DC_OVERLAY_BOTTOM_RIGHT				0x1680
> +#define DC_OVERLAY_ADDRESS				0x15c0
> +#define DC_OVERLAY_U_ADDRESS				0x1840
> +#define DC_OVERLAY_V_ADDRESS				0x1880
> +#define DC_OVERLAY_STRIDE				0x1600
> +#define DC_OVERLAY_U_STRIDE				0x18c0
> +#define DC_OVERLAY_V_STRIDE				0x1900
> +#define DC_OVERLAY_SIZE					0x17c0
> +#define DC_OVERLAY_SCALE_FACTOR_X			0x1a40
> +#define DC_OVERLAY_SCALE_FACTOR_Y			0x1a80
> +#define DC_OVERLAY_H_FILTER_COEF_INDEX			0x1aC0
> +#define DC_OVERLAY_H_FILTER_COEF_DATA			0x1b00
> +#define DC_OVERLAY_V_FILTER_COEF_INDEX			0x1b40
> +#define DC_OVERLAY_V_FILTER_COEF_DATA			0x1b80
> +#define DC_OVERLAY_INIT_OFFSET				0x1bC0
> +#define DC_OVERLAY_COLOR_KEY				0x1740
> +#define DC_OVERLAY_COLOR_KEY_HIGH			0x1780
> +#define DC_OVERLAY_CLEAR_VALUE				0x1940
> +#define DC_OVERLAY_COLOR_TABLE_INDEX			0x1980
> +#define DC_OVERLAY_COLOR_TABLE_DATA			0x19c0
> +#define DC_OVERLAY_SRC_GLOBAL_COLOR			0x16c0
> +#define DC_OVERLAY_DST_GLOBAL_COLOR			0x1700
> +#define DC_OVERLAY_ROI_ORIGIN				0x1d00
> +#define DC_OVERLAY_ROI_SIZE				0x1d40
> +#define DC_OVERLAY_WATER_MARK				0x1dc0
> +#define DC_OVERLAY_DEGAMMA_INDEX			0x2200
> +#define DC_OVERLAY_DEGAMMA_DATA				0x2240
> +#define DC_OVERLAY_DEGAMMA_EX_DATA			0x2280
> +#define DC_OVERLAY_YUVTORGB_COEF0			0x1ec0
> +#define DC_OVERLAY_YUVTORGB_COEF1			0x1f00
> +#define DC_OVERLAY_YUVTORGB_COEF2			0x1f40
> +#define DC_OVERLAY_YUVTORGB_COEF3			0x1f80
> +#define DC_OVERLAY_YUVTORGB_COEF4			0x1fc0
> +#define DC_OVERLAY_YUVTORGB_COEFD0			0x2000
> +#define DC_OVERLAY_YUVTORGB_COEFD1			0x2040
> +#define DC_OVERLAY_YUVTORGB_COEFD2			0x2080
> +#define DC_OVERLAY_Y_CLAMP_BOUND			0x22c0
> +#define DC_OVERLAY_UV_CLAMP_BOUND			0x2300
> +#define DC_OVERLAY_RGBTORGB_COEF0			0x20c0
> +#define DC_OVERLAY_RGBTORGB_COEF1			0x2100
> +#define DC_OVERLAY_RGBTORGB_COEF2			0x2140
> +#define DC_OVERLAY_RGBTORGB_COEF3			0x2180
> +#define DC_OVERLAY_RGBTORGB_COEF4			0x21c0
> +
> +#define DC_CURSOR_CONFIG				0x1468
> +#define DC_CURSOR_ADDRESS				0x146c
> +#define DC_CURSOR_LOCATION				0x1470
> +#define DC_CURSOR_BACKGROUND				0x1474
> +#define DC_CURSOR_FOREGROUND				0x1478
> +#define DC_CURSOR_CLK_GATING				0x1484
> +#define DC_CURSOR_CONFIG_EX				0x24e8
> +#define DC_CURSOR_OFFSET				0x1080
> +
> +#define DC_DISPLAY_DITHER_CONFIG			0x1410
> +#define DC_DISPLAY_PANEL_CONFIG				0x1418
> +#define DC_DISPLAY_PANEL_CONFIG_EX			0x2518
> +#define DC_DISPLAY_DITHER_TABLE_LOW			0x1420
> +#define DC_DISPLAY_DITHER_TABLE_HIGH			0x1428
> +#define DC_DISPLAY_H					0x1430
> +#define DC_DISPLAY_H_SYNC				0x1438
> +#define DC_DISPLAY_V					0x1440
> +#define DC_DISPLAY_V_SYNC				0x1448
> +#define DC_DISPLAY_CURRENT_LOCATION			0x1450
> +#define DC_DISPLAY_GAMMA_INDEX				0x1458
> +#define DC_DISPLAY_GAMMA_DATA				0x1460
> +#define DC_DISPLAY_INT					0x147c
> +#define DC_DISPLAY_INT_ENABLE				0x1480
> +#define DC_DISPLAY_DBI_CONFIG				0x1488
> +#define DC_DISPLAY_GENERAL_CONFIG			0x14b0
> +#define DC_DISPLAY_DPI_CONFIG				0x14b8
> +#define DC_DISPLAY_PANEL_START				0x1ccc
> +#define DC_DISPLAY_DEBUG_COUNTER_SELECT			0x14d0
> +#define DC_DISPLAY_DEBUG_COUNTER_VALUE			0x14d8
> +#define DC_DISPLAY_DP_CONFIG				0x1cd0
> +#define DC_DISPLAY_GAMMA_EX_INDEX			0x1cf0
> +#define DC_DISPLAY_GAMMA_EX_DATA			0x1cf8
> +#define DC_DISPLAY_GAMMA_EX_ONE_DATA			0x1d80
> +#define DC_DISPLAY_RGBTOYUV_COEF0			0x1e48
> +#define DC_DISPLAY_RGBTOYUV_COEF1			0x1e50
> +#define DC_DISPLAY_RGBTOYUV_COEF2			0x1e58
> +#define DC_DISPLAY_RGBTOYUV_COEF3			0x1e60
> +#define DC_DISPLAY_RGBTOYUV_COEF4			0x1e68
> +#define DC_DISPLAY_RGBTOYUV_COEFD0			0x1e70
> +#define DC_DISPLAY_RGBTOYUV_COEFD1			0x1e78
> +#define DC_DISPLAY_RGBTOYUV_COEFD2			0x1e80
> +
> +#define DC_CLK_GATTING					0x1a28
> +#define DC_QOS_CONFIG					0x1a38
> +
> +#define DC_TRANSPARENCY_OPAQUE				0x00
> +#define DC_TRANSPARENCY_KEY				0x02
> +#define DC_DISPLAY_DITHERTABLE_LOW			0x7b48f3c0
> +#define DC_DISPLAY_DITHERTABLE_HIGH			0x596ad1e2
> +
> +#define GAMMA_SIZE					256
> +#define GAMMA_EX_SIZE					300
> +#define DEGAMMA_SIZE					260
> +
> +#define RGB_TO_RGB_TABLE_SIZE				9
> +#define YUV_TO_RGB_TABLE_SIZE				16
> +#define RGB_TO_YUV_TABLE_SIZE				12
> +
> +#define DC_LAYER_NUM					6
> +#define DC_DISPLAY_NUM					2
> +#define DC_CURSOR_NUM					2
> +
> +enum dc_chip_rev {
> +	DC_REV_0,/* For HW_REV_5720,HW_REV_5721_311 */
> +	DC_REV_1,/* For HW_REV_5721_30B */
> +	DC_REV_2,/* For HW_REV_5721_310 */
> +};
> +
> +enum dc_hw_plane_id {
> +	PRIMARY_PLANE_0,
> +	OVERLAY_PLANE_0,
> +	OVERLAY_PLANE_1,
> +	PRIMARY_PLANE_1,
> +	OVERLAY_PLANE_2,
> +	OVERLAY_PLANE_3,
> +	CURSOR_PLANE_0,
> +	CURSOR_PLANE_1,
> +	PLANE_NUM
> +};
> +
> +enum dc_hw_color_format {
> +	FORMAT_X4R4G4B4,//0
> +	FORMAT_A4R4G4B4,//1
> +	FORMAT_X1R5G5B5,//2
> +	FORMAT_A1R5G5B5,//3
> +	FORMAT_R5G6B5,//4
> +	FORMAT_X8R8G8B8,//5
> +	FORMAT_A8R8G8B8,//6
> +	FORMAT_YUY2,//7
> +	FORMAT_UYVY,//8
> +	FORMAT_INDEX8,//9
> +	FORMAT_MONOCHROME,//10
> +	FORMAT_YV12 = 0xf,
> +	FORMAT_A8,//16
> +	FORMAT_NV12,//17
> +	FORMAT_NV16,//18
> +	FORMAT_RG16,//19
> +	FORMAT_R8,//20
> +	FORMAT_NV12_10BIT,//21
> +	FORMAT_A2R10G10B10,//22
> +	FORMAT_NV16_10BIT,//23
> +	FORMAT_INDEX1,//24
> +	FORMAT_INDEX2,//25
> +	FORMAT_INDEX4,//26
> +	FORMAT_P010,//27
> +	FORMAT_YUV444,//28
> +	FORMAT_YUV444_10BIT,//29
> +};
> +
> +enum dc_hw_yuv_color_space {
> +	COLOR_SPACE_601 = 0,
> +	COLOR_SPACE_709 = 1,
> +	COLOR_SPACE_2020 = 3,
> +};
> +
> +enum dc_hw_rotation {
> +	ROT_0 = 0,
> +	ROT_90 = 4,
> +	ROT_180 = 5,
> +	ROT_270 = 6,
> +	FLIP_X = 1,
> +	FLIP_Y = 2,
> +	FLIP_XY = 3,
> +};
> +
> +enum dc_hw_swizzle {
> +	SWIZZLE_ARGB = 0,
> +	SWIZZLE_RGBA,
> +	SWIZZLE_ABGR,
> +	SWIZZLE_BGRA,
> +};
> +
> +enum dc_hw_out {
> +	OUT_DPI,
> +	OUT_DP,
> +};
> +
> +enum dc_hw_cursor_size {
> +	CURSOR_SIZE_32X32 = 0,
> +	CURSOR_SIZE_64X64,
> +};
> +
> +enum dc_hw_blend_mode {
> +	/* out.rgb = plane_alpha * fg.rgb +
> +	 *		(1 - (plane_alpha * fg.alpha)) * bg.rgb
> +	 */
> +	BLEND_PREMULTI,
> +	/* out.rgb = plane_alpha * fg.alpha * fg.rgb +
> +	 *		(1 - (plane_alpha * fg.alpha)) * bg.rgb
> +	 */
> +	BLEND_COVERAGE,
> +	/* out.rgb = plane_alpha * fg.rgb +
> +	 *		(1 - plane_alpha) * bg.rgb
> +	 */
> +	BLEND_PIXEL_NONE,
> +};
> +
> +struct dc_hw_plane_reg {
> +	u32 y_address;
> +	u32 u_address;
> +	u32 v_address;
> +	u32 y_stride;
> +	u32 u_stride;
> +	u32 v_stride;
> +	u32 size;
> +	u32 top_left;
> +	u32 bottom_right;
> +	u32 scale_factor_x;
> +	u32 scale_factor_y;
> +	u32 h_filter_coef_index;
> +	u32 h_filter_coef_data;
> +	u32 v_filter_coef_index;
> +	u32 v_filter_coef_data;
> +	u32 init_offset;
> +	u32 color_key;
> +	u32 color_key_high;
> +	u32 clear_value;
> +	u32 color_table_index;
> +	u32 color_table_data;
> +	u32 scale_config;
> +	u32 water_mark;
> +	u32 degamma_index;
> +	u32 degamma_data;
> +	u32 degamma_ex_data;
> +	u32 src_global_color;
> +	u32 dst_global_color;
> +	u32 blend_config;
> +	u32 roi_origin;
> +	u32 roi_size;
> +	u32 yuv_to_rgb_coef0;
> +	u32 yuv_to_rgb_coef1;
> +	u32 yuv_to_rgb_coef2;
> +	u32 yuv_to_rgb_coef3;
> +	u32 yuv_to_rgb_coef4;
> +	u32 yuv_to_rgb_coefd0;
> +	u32 yuv_to_rgb_coefd1;
> +	u32 yuv_to_rgb_coefd2;
> +	u32 y_clamp_bound;
> +	u32 uv_clamp_bound;
> +	u32 rgb_to_rgb_coef0;
> +	u32 rgb_to_rgb_coef1;
> +	u32 rgb_to_rgb_coef2;
> +	u32 rgb_to_rgb_coef3;
> +	u32 rgb_to_rgb_coef4;
> +};
> +
> +struct dc_hw_fb {
> +	u32 y_address;
> +	u32 u_address;
> +	u32 v_address;
> +	u32 clear_value;
> +	u32 water_mark;
> +	u16 y_stride;
> +	u16 u_stride;
> +	u16 v_stride;
> +	u16 width;
> +	u16 height;
> +	u8	format;
> +	u8	tile_mode;
> +	u8	rotation;
> +	u8	yuv_color_space;
> +	u8	swizzle;
> +	u8	uv_swizzle;
> +	u8	zpos;
> +	u8	display_id;
> +	bool	clear_enable;
> +	bool	dec_enable;
> +	bool	enable;
> +	bool	dirty;
> +};
> +
> +struct dc_hw_scale {
> +	u32 scale_factor_x;
> +	u32 scale_factor_y;
> +	bool	enable;
> +	bool	dirty;
> +};
> +
> +struct dc_hw_position {
> +	u16 start_x;
> +	u16 start_y;
> +	u16 end_x;
> +	u16 end_y;
> +	bool	dirty;
> +};
> +
> +struct dc_hw_blend {
> +	u8	alpha;
> +	u8	blend_mode;
> +	bool	dirty;
> +};
> +
> +struct dc_hw_colorkey {
> +	u32 colorkey;
> +	u32 colorkey_high;
> +	u8	transparency;
> +	bool dirty;
> +};
> +
> +struct dc_hw_roi {
> +	u16 x;
> +	u16 y;
> +	u16 width;
> +	u16 height;
> +	bool enable;
> +	bool dirty;
> +};
> +
> +struct dc_hw_cursor {
> +	u32 address;
> +	u16 x;
> +	u16 y;
> +	u16 hot_x;
> +	u16 hot_y;
> +	u8	size;
> +	u8	display_id;
> +	bool	enable;
> +	bool	dirty;
> +};
> +
> +struct dc_hw_display {
> +	u32 bus_format;
> +	u16 h_active;
> +	u16 h_total;
> +	u16 h_sync_start;
> +	u16 h_sync_end;
> +	u16 v_active;
> +	u16 v_total;
> +	u16 v_sync_start;
> +	u16 v_sync_end;
> +	u16 sync_mode;
> +	u32 bg_color;
> +	u8	id;
> +	bool	h_sync_polarity;
> +	bool	v_sync_polarity;
> +	bool	enable;
> +	bool	sync_enable;
> +	bool	dither_enable;
> +};
> +
> +struct dc_hw_gamma {
> +	u16 gamma[GAMMA_EX_SIZE][3];
> +	bool	enable;
> +	bool	dirty;
> +};
> +
> +struct dc_hw_degamma {
> +	u16 degamma[DEGAMMA_SIZE][3];
> +	u32 mode;
> +	bool	dirty;
> +};
> +
> +struct dc_hw_plane {
> +	struct dc_hw_fb			fb;
> +	struct dc_hw_position	pos;
> +	struct dc_hw_scale		scale;
> +	struct dc_hw_blend		blend;
> +	struct dc_hw_roi		roi;
> +	struct dc_hw_colorkey	colorkey;
> +	struct dc_hw_degamma	degamma;
> +};
> +
> +struct dc_hw_qos {
> +	u8	  low_value;
> +	u8	  high_value;
> +	bool  dirty;
> +};
> +
> +struct dc_hw_read {
> +	u32			reg;
> +	u32			value;
> +};
> +
> +struct dc_hw;
> +struct dc_hw_funcs {
> +	void (*gamma)(struct dc_hw *hw);
> +	void (*plane)(struct dc_hw *hw);
> +	void (*display)(struct dc_hw *hw, struct dc_hw_display *display);
> +};
> +
> +struct dc_hw {
> +	enum dc_chip_rev rev;
> +	enum dc_hw_out		out[DC_DISPLAY_NUM];
> +	void			*hi_base;
> +	void			*reg_base;
> +
> +	struct dc_hw_display display[DC_DISPLAY_NUM];
> +	struct dc_hw_gamma	 gamma[DC_DISPLAY_NUM];
> +	struct dc_hw_plane	 plane[DC_LAYER_NUM];
> +	struct dc_hw_cursor  cursor[DC_CURSOR_NUM];
> +	struct dc_hw_qos	 qos;
> +	struct dc_hw_funcs	 *func;
> +	struct vs_dc_info	 *info;
> +};
> +
> +int dc_hw_init(struct dc_hw *hw);
> +void dc_hw_deinit(struct dc_hw *hw);
> +void dc_hw_update_plane(struct dc_hw *hw, u8 id,
> +			struct dc_hw_fb *fb, struct dc_hw_scale *scale,
> +			struct dc_hw_position *pos, struct dc_hw_blend *blend);
> +void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode);
> +void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi);
> +void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
> +			   struct dc_hw_colorkey *colorkey);
> +void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos);
> +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor);
> +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
> +			u16 r, u16 g, u16 b);
> +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable);
> +void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display);
> +void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable);
> +u32 dc_hw_get_interrupt(struct dc_hw *hw);
> +bool dc_hw_check_underflow(struct dc_hw *hw);
> +void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable);
> +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id);
> +void dc_hw_commit(struct dc_hw *hw);
> +
> +#endif /* __VS_DC_HW_H__ */
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
> index d84aacd751bc..c28bfd74ffc9 100644
> --- a/drivers/gpu/drm/verisilicon/vs_drv.c
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> @@ -32,6 +32,7 @@
>   #include "vs_drv.h"
>   #include "vs_fb.h"
>   #include "vs_gem.h"
> +#include "vs_dc.h"
>   
>   #define DRV_NAME	"starfive"
>   #define DRV_DESC	"Starfive DRM driver"
> @@ -181,6 +182,7 @@ static const struct component_master_ops vs_drm_ops = {
>   };
>   
>   static struct platform_driver *drm_sub_drivers[] = {
> +	&dc_platform_driver,
>   };
>   
>   #define NUM_DRM_DRIVERS \

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH 3/9] drm/verisilicon: Add basic drm driver
  2023-06-02  7:40 ` [PATCH 3/9] drm/verisilicon: Add basic drm driver Keith Zhao
  2023-06-07  8:53   ` Lucas Stach
  2023-06-19 12:59   ` Thomas Zimmermann
@ 2023-07-03 18:42   ` Shengyu Qu
  2023-07-04  6:09     ` Keith Zhao
  2 siblings, 1 reply; 46+ messages in thread
From: Shengyu Qu @ 2023-07-03 18:42 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: wiagn233, David Airlie, Daniel Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Emil Renner Berthing,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Philipp Zabel, Sumit Semwal,
	christian.koenig, Bjorn Andersson, Heiko Stuebner, Shawn Guo,
	Jagan Teki, Chris Morgan, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Hello Keith,

While compiling this driver as a module, a error happens:

drivers/gpu/drm/verisilicon/vs_drm: struct of_device_id is 200 bytes.  
The last of 1 is:
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x76 0x65 0x72 0x69 0x73 0x69 
0x6c 0x69 0x63 0x6f 0x6e 0x2c 0x64 0x69 0x73 0x70 0x6c 0x61 0x79 0x2d 
0x73 0x75 0x62 0x73 0x79 0x73 0x74 0x65 0x6d 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00
FATAL: modpost: drivers/gpu/drm/verisilicon/vs_drm: struct of_device_id 
is not terminated with a NULL entry!

> +
> +static const struct of_device_id vs_drm_dt_ids[] = {
> +	{ .compatible = "verisilicon,display-subsystem", },
> +};
> +

So, this should be:

static const struct of_device_id vs_drm_dt_ids[] = {
	{ .compatible = "verisilicon,display-subsystem", },
	{ },
};

After fixing this problem, another error happens:

ERROR: modpost: module vs_drm uses symbol dma_buf_mmap from namespace 
DMA_BUF, but does not import it.

Please fix.

Best regards,
Shengyu


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

* Re: [PATCH 3/9] drm/verisilicon: Add basic drm driver
  2023-07-03 18:42   ` Shengyu Qu
@ 2023-07-04  6:09     ` Keith Zhao
  0 siblings, 0 replies; 46+ messages in thread
From: Keith Zhao @ 2023-07-04  6:09 UTC (permalink / raw)
  To: Shengyu Qu, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Jack Zhu, Shengyang Chen, Changhuang Liang



On 2023/7/4 2:42, Shengyu Qu wrote:
> Hello Keith,
> 
> While compiling this driver as a module, a error happens:
> 
> drivers/gpu/drm/verisilicon/vs_drm: struct of_device_id is 200 bytes.  The last of 1 is:
> 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x76 0x65 0x72 0x69 0x73 0x69 0x6c 0x69 0x63 0x6f 0x6e 0x2c 0x64 0x69 0x73 0x70 0x6c 0x61 0x79 0x2d 0x73 0x75 0x62 0x73 0x79 0x73 0x74 0x65 0x6d 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
> 0x00 0x00
> FATAL: modpost: drivers/gpu/drm/verisilicon/vs_drm: struct of_device_id is not terminated with a NULL entry!
> 
>> +
>> +static const struct of_device_id vs_drm_dt_ids[] = {
>> +    { .compatible = "verisilicon,display-subsystem", },
>> +};
>> +
> 
> So, this should be:
> 
> static const struct of_device_id vs_drm_dt_ids[] = {
>     { .compatible = "verisilicon,display-subsystem", },
>     { },
> };
> 
> After fixing this problem, another error happens:
> 
> ERROR: modpost: module vs_drm uses symbol dma_buf_mmap from namespace DMA_BUF, but does not import it.
> 
> Please fix.
> 
> Best regards,
> Shengyu

hello Shengyu , 

I can reproduce the error generated by compiling ko , and add MODULE_IMPORT_NS(DMA_BUF) at the beginning of vs_gem.c ,
it can fix the error message, 
I will add this in my next patch , thanks

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

* Re: [PATCH 3/9] drm/verisilicon: Add basic drm driver
  2023-06-19 12:59   ` Thomas Zimmermann
@ 2023-07-07 18:09     ` Nicolas Dufresne
  2023-07-08 19:11       ` Thomas Zimmermann
  0 siblings, 1 reply; 46+ messages in thread
From: Nicolas Dufresne @ 2023-07-07 18:09 UTC (permalink / raw)
  To: Thomas Zimmermann, Keith Zhao, dri-devel, devicetree,
	linux-kernel, linux-riscv, linux-media, linaro-mm-sig
  Cc: Krzysztof Kozlowski, Sumit Semwal, Emil Renner Berthing,
	Shengyang Chen, Conor Dooley, Albert Ou, Jagan Teki, Rob Herring,
	Chris Morgan, Paul Walmsley, Bjorn Andersson, Changhuang Liang,
	Jack Zhu, Palmer Dabbelt, Shawn Guo, christian.koenig

Hi Thomas,

Le lundi 19 juin 2023 à 14:59 +0200, Thomas Zimmermann a écrit :
> Hi,
> 
> I appreciate that you split the driver into small patches. Please find 
> some comments below.
> 
> Am 02.06.23 um 09:40 schrieb Keith Zhao:
> > Add a basic platform driver of the DRM driver for JH7110 SoC.
> > 
> > Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> > ---
> >   MAINTAINERS                          |   2 +
> >   drivers/gpu/drm/Kconfig              |   2 +
> >   drivers/gpu/drm/Makefile             |   1 +
> >   drivers/gpu/drm/verisilicon/Kconfig  |  13 ++
> >   drivers/gpu/drm/verisilicon/Makefile |   6 +
> >   drivers/gpu/drm/verisilicon/vs_drv.c | 284 +++++++++++++++++++++++++++
> >   drivers/gpu/drm/verisilicon/vs_drv.h |  48 +++++
> >   include/uapi/drm/drm_fourcc.h        |  83 ++++++++
> >   include/uapi/drm/vs_drm.h            |  50 +++++
> >   9 files changed, 489 insertions(+)
> >   create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
> >   create mode 100644 drivers/gpu/drm/verisilicon/Makefile
> >   create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
> >   create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
> >   create mode 100644 include/uapi/drm/vs_drm.h
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 293aa13d484c..da5b6766a7bb 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -7055,6 +7055,8 @@ L:	dri-devel@lists.freedesktop.org
> >   S:	Maintained
> >   T:	git git://anongit.freedesktop.org/drm/drm-misc
> >   F:	Documentation/devicetree/bindings/display/verisilicon/
> > +F:	drivers/gpu/drm/verisilicon/
> > +F:	include/uapi/drm/vs_drm.h
> >   
> >   DRM DRIVERS FOR VIVANTE GPU IP
> >   M:	Lucas Stach <l.stach@pengutronix.de>
> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > index ba3fb04bb691..f7e461fa4656 100644
> > --- a/drivers/gpu/drm/Kconfig
> > +++ b/drivers/gpu/drm/Kconfig
> > @@ -371,6 +371,8 @@ source "drivers/gpu/drm/solomon/Kconfig"
> >   
> >   source "drivers/gpu/drm/sprd/Kconfig"
> >   
> > +source "drivers/gpu/drm/verisilicon/Kconfig"
> > +
> >   config DRM_HYPERV
> >   	tristate "DRM Support for Hyper-V synthetic video device"
> >   	depends on DRM && PCI && MMU && HYPERV
> > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> > index a33257d2bc7f..e50622ee4e46 100644
> > --- a/drivers/gpu/drm/Makefile
> > +++ b/drivers/gpu/drm/Makefile
> > @@ -194,3 +194,4 @@ obj-y			+= gud/
> >   obj-$(CONFIG_DRM_HYPERV) += hyperv/
> >   obj-y			+= solomon/
> >   obj-$(CONFIG_DRM_SPRD) += sprd/
> > +obj-$(CONFIG_DRM_VERISILICON) += verisilicon/
> > diff --git a/drivers/gpu/drm/verisilicon/Kconfig b/drivers/gpu/drm/verisilicon/Kconfig
> > new file mode 100644
> > index 000000000000..89d12185f73b
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/Kconfig
> > @@ -0,0 +1,13 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +config DRM_VERISILICON
> > +	tristate "DRM Support for VeriSilicon"
> 
> Can you rename the driver and files? 'VeriSilicon' seems 
> unpronounceable. Simply 'StarFive' and starfive/ would be fine.

Are you sure you want to request this ? If the display controller is a
Verisilicon design, it will be super odd to use on other SoC that aren't from
StarFive. Think about STM network driver, which is DesignWare.

Nicolas

> 
> > +	depends on DRM
> > +	select DRM_KMS_HELPER
> > +	select CMA
> > +	select DMA_CMA
> > +	help
> > +	  Choose this option if you have a VeriSilicon soc chipset.
> > +	  This driver provides VeriSilicon kernel mode
> > +	  setting and buffer management. It does not
> > +	  provide 2D or 3D acceleration.
> > diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> > new file mode 100644
> > index 000000000000..64ce1b26546c
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/Makefile
> > @@ -0,0 +1,6 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +vs_drm-objs := vs_drv.o
> > +
> > +obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
> > +
> > diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
> > new file mode 100644
> > index 000000000000..24d333598477
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> > @@ -0,0 +1,284 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/component.h>
> > +#include <linux/delay.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/iommu.h>
> > +#include <linux/of_graph.h>
> > +#include <linux/of_reserved_mem.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/reset.h>
> > +#include <linux/version.h>
> > +
> > +#include <drm/drm_aperture.h>
> > +#include <drm/drm_crtc.h>
> > +#include <drm/drm_crtc_helper.h>
> > +#include <drm/drm_debugfs.h>
> > +#include <drm/drm_drv.h>
> > +#include <drm/drm_fb_helper.h>
> > +#include <drm/drm_fbdev_generic.h>
> > +#include <drm/drm_file.h>
> > +#include <drm/drm_fourcc.h>
> > +#include <drm/drm_ioctl.h>
> > +#include <drm/drm_of.h>
> > +#include <drm/drm_prime.h>
> > +#include <drm/drm_probe_helper.h>
> > +#include <drm/drm_vblank.h>
> > +
> > +#include "vs_drv.h"
> > +
> > +#define DRV_NAME	"starfive"
> > +#define DRV_DESC	"Starfive DRM driver"
> > +#define DRV_DATE	"202305161"
> > +#define DRV_MAJOR	1
> > +#define DRV_MINOR	0
> > +
> > +static struct platform_driver vs_drm_platform_driver;
> > +
> > +static const struct file_operations fops = {
> > +	.owner			= THIS_MODULE,
> > +	.open			= drm_open,
> > +	.release		= drm_release,
> > +	.unlocked_ioctl	= drm_ioctl,
> > +	.compat_ioctl	= drm_compat_ioctl,
> > +	.poll			= drm_poll,
> > +	.read			= drm_read,
> > +};
> > +
> > +static struct drm_driver vs_drm_driver = {
> > +	.driver_features	= DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
> > +	.lastclose		= drm_fb_helper_lastclose,
> > +	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> > +	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> > +	.fops			= &fops,
> > +	.name			= DRV_NAME,
> > +	.desc			= DRV_DESC,
> > +	.date			= DRV_DATE,
> > +	.major			= DRV_MAJOR,
> > +	.minor			= DRV_MINOR,
> > +};
> > +
> > +void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
> > +				   unsigned int alignment)
> > +{
> > +	struct vs_drm_private *priv = drm_dev->dev_private;
> > +
> > +	if (alignment > priv->pitch_alignment)
> > +		priv->pitch_alignment = alignment;
> > +}
> > +
> > +static int vs_drm_bind(struct device *dev)
> > +{
> > +	struct drm_device *drm_dev;
> > +	struct vs_drm_private *priv;
> > +	int ret;
> > +	static u64 dma_mask = DMA_BIT_MASK(40);
> > +
> > +	/* Remove existing drivers that may own the framebuffer memory. */
> > +	ret = drm_aperture_remove_framebuffers(false, &vs_drm_driver);
> > +	if (ret) {
> > +		DRM_DEV_ERROR(dev,
> 
> drm_err(), drm_info(), drm_warn(), etc.  Here and everwhere else. The 
> DRM_DEV_*() print macros are obsolete.
> 
> > +			      "Failed to remove existing framebuffers - %d.\n",
> > +			      ret);
> > +		return ret;
> > +	}
> > +
> > +	drm_dev = drm_dev_alloc(&vs_drm_driver, dev);
> > +	if (IS_ERR(drm_dev))
> > +		return PTR_ERR(drm_dev);
> > +
> > +	dev_set_drvdata(dev, drm_dev);
> > +
> > +	priv = devm_kzalloc(drm_dev->dev, sizeof(struct vs_drm_private),
> > +			    GFP_KERNEL);
> > +	if (!priv) {
> > +		ret = -ENOMEM;
> > +		goto err_put_dev;
> > +	}
> > +
> > +	priv->pitch_alignment = 64;
> > +	priv->dma_dev = drm_dev->dev;
> > +	priv->dma_dev->coherent_dma_mask = dma_mask;
> > +	drm_dev->dev_private = priv;
> 
> dev_private is obsolete and about to go away at some point.
> 
> Please embed drm_device in vs_drm_private and allocate the memory with 
> devm_drm_dev_alloc().
> 
> > +
> > +	drm_mode_config_init(drm_dev);
> 
> drmm_mode_config_init() please.
> 
> > +
> > +	/* Now try and bind all our sub-components */
> > +	ret = component_bind_all(dev, drm_dev);
> > +	if (ret)
> > +		goto err_mode;
> > +
> > +	ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
> > +	if (ret)
> > +		goto err_bind;
> > +
> > +	drm_mode_config_reset(drm_dev);
> > +
> > +	drm_kms_helper_poll_init(drm_dev);
> > +
> > +	ret = drm_dev_register(drm_dev, 0);
> > +	if (ret)
> > +		goto err_helper;
> > +
> > +	drm_fbdev_generic_setup(drm_dev, 32);
> > +
> > +	return 0;
> > +
> > +err_helper:
> > +	drm_kms_helper_poll_fini(drm_dev);
> > +err_bind:
> > +	component_unbind_all(drm_dev->dev, drm_dev);
> > +err_mode:
> > +	drm_mode_config_cleanup(drm_dev);
> > +	if (priv->domain)
> > +		iommu_domain_free(priv->domain);
> > +err_put_dev:
> > +	drm_dev->dev_private = NULL;
> > +	dev_set_drvdata(dev, NULL);
> > +	drm_dev_put(drm_dev);
> > +	return ret;
> > +}
> > +
> > +static void vs_drm_unbind(struct device *dev)
> > +{
> > +	struct drm_device *drm_dev = dev_get_drvdata(dev);
> > +	struct vs_drm_private *priv = drm_dev->dev_private;
> > +
> > +	drm_dev_unregister(drm_dev);
> > +
> > +	drm_kms_helper_poll_fini(drm_dev);
> > +
> > +	component_unbind_all(drm_dev->dev, drm_dev);
> > +
> > +	drm_mode_config_cleanup(drm_dev);
> > +
> > +	if (priv->domain) {
> > +		iommu_domain_free(priv->domain);
> > +		priv->domain = NULL;
> > +	}
> > +
> > +	drm_dev->dev_private = NULL;
> > +	dev_set_drvdata(dev, NULL);
> > +	drm_dev_put(drm_dev);
> 
> You rather want to convert the individual steps of this cleanup to 
> managed functions (drmm_ and devm_) to automate the cleanup when as part 
> of drm_dev_put().
> 
> > +}
> > +
> > +static const struct component_master_ops vs_drm_ops = {
> > +	.bind = vs_drm_bind,
> > +	.unbind = vs_drm_unbind,
> > +};
> > +
> > +static struct platform_driver *drm_sub_drivers[] = {
> > +};
> > +
> > +#define NUM_DRM_DRIVERS \
> > +	(sizeof(drm_sub_drivers) / sizeof(struct platform_driver *))
> 
> Does this really work? sizeof(drm_sub_drivers) isn't know at compile 
> time. It is always assumed to be 0 AFAICT. Or do you fill this array in 
> later patches?
> 
> 
> > +
> > +static int compare_dev(struct device *dev, void *data)
> > +{
> > +	return dev == (struct device *)data;
> > +}
> > +
> > +static struct component_match *vs_drm_match_add(struct device *dev)
> > +{
> > +	struct component_match *match = NULL;
> > +	int i;
> > +
> > +	for (i = 0; i < NUM_DRM_DRIVERS; ++i) {
> > +		struct platform_driver *drv = drm_sub_drivers[i];
> > +		struct device *p = NULL, *d;
> > +
> > +		while ((d = platform_find_device_by_driver(p, &drv->driver))) {
> > +			put_device(p);
> > +
> > +			component_match_add(dev, &match, compare_dev, d);
> > +			p = d;
> > +		}
> > +		put_device(p);
> > +	}
> > +
> > +	return match ?: ERR_PTR(-ENODEV);
> > +}
> > +
> > +static int vs_drm_platform_probe(struct platform_device *pdev)
> > +{
> > +	struct device *dev = &pdev->dev;
> > +	struct component_match *match;
> > +
> > +	match = vs_drm_match_add(dev);
> > +	if (IS_ERR(match))
> > +		return PTR_ERR(match);
> > +
> > +	return component_master_add_with_match(dev, &vs_drm_ops, match);
> > +}
> > +
> > +static int vs_drm_platform_remove(struct platform_device *pdev)
> > +{
> > +	component_master_del(&pdev->dev, &vs_drm_ops);
> > +	return 0;
> > +}
> > +
> > +#ifdef CONFIG_PM_SLEEP
> > +static int vs_drm_suspend(struct device *dev)
> > +{
> > +	struct drm_device *drm = dev_get_drvdata(dev);
> > +
> > +	return drm_mode_config_helper_suspend(drm);
> > +}
> > +
> > +static int vs_drm_resume(struct device *dev)
> > +{
> > +	struct drm_device *drm = dev_get_drvdata(dev);
> > +
> > +	return drm_mode_config_helper_resume(drm);
> > +}
> > +#endif
> > +
> > +static SIMPLE_DEV_PM_OPS(vs_drm_pm_ops, vs_drm_suspend, vs_drm_resume);
> > +
> > +static const struct of_device_id vs_drm_dt_ids[] = {
> > +	{ .compatible = "verisilicon,display-subsystem", },
> > +};
> > +
> > +MODULE_DEVICE_TABLE(of, vs_drm_dt_ids);
> > +
> > +static struct platform_driver vs_drm_platform_driver = {
> > +	.probe = vs_drm_platform_probe,
> > +	.remove = vs_drm_platform_remove,
> > +
> > +	.driver = {
> > +		.name = DRV_NAME,
> > +		.of_match_table = vs_drm_dt_ids,
> > +		.pm = &vs_drm_pm_ops,
> > +	},
> > +};
> > +
> > +static int __init vs_drm_init(void)
> > +{
> > +	int ret;
> > +
> > +	ret = platform_register_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = platform_driver_register(&vs_drm_platform_driver);
> > +	if (ret)
> > +		platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
> > +
> > +	return ret;
> > +}
> > +
> > +static void __exit vs_drm_fini(void)
> > +{
> > +	platform_driver_unregister(&vs_drm_platform_driver);
> > +	platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
> > +}
> > +
> > +module_init(vs_drm_init);
> > +module_exit(vs_drm_fini);
> > +
> > +MODULE_DESCRIPTION("VeriSilicon DRM Driver");
> > +MODULE_LICENSE("GPL");
> > diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
> > new file mode 100644
> > index 000000000000..0382b44e3bf0
> > --- /dev/null
> > +++ b/drivers/gpu/drm/verisilicon/vs_drv.h
> > @@ -0,0 +1,48 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > + */
> > +
> > +#ifndef __VS_DRV_H__
> > +#define __VS_DRV_H__
> > +
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/version.h>
> > +#include <drm/drm_drv.h>
> > +#include <drm/drm_gem.h>
> > +
> > +/*
> > + *
> > + * @dma_dev: device for DMA API.
> > + *	- use the first attached device if support iommu
> > +	else use drm device (only contiguous buffer support)
> > + * @domain: iommu domain for DRM.
> > + *	- all DC IOMMU share same domain to reduce mapping
> > + * @pitch_alignment: buffer pitch alignment required by sub-devices.
> > + *
> > + */
> > +struct vs_drm_private {
> > +	struct device *dma_dev;
> > +	struct iommu_domain *domain;
> > +	unsigned int pitch_alignment;
> > +};
> 
> As mentioned, this struct needs to embed struct drm_device.
> 
> > +
> > +void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
> > +				   unsigned int alignment);
> > +
> > +static inline struct device *to_dma_dev(struct drm_device *dev)
> > +{
> > +	struct vs_drm_private *priv = dev->dev_private;
> > +
> > +	return priv->dma_dev;
> 
> And this needs to be an upcast via container_of().
> 
> > +}
> > +
> > +static inline bool is_iommu_enabled(struct drm_device *dev)
> > +{
> > +	struct vs_drm_private *priv = dev->dev_private;
> > +
> > +	return priv->domain ? true : false;
> > +}
> > +
> > +#endif /* __VS_DRV_H__ */
> > diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
> > index de703c6be969..af4fb50f9207 100644
> > --- a/include/uapi/drm/drm_fourcc.h
> > +++ b/include/uapi/drm/drm_fourcc.h
> 
> The UAPI changes shouldn't be needed in this patch?
> 
> > @@ -419,6 +419,7 @@ extern "C" {
> >   #define DRM_FORMAT_MOD_VENDOR_ARM     0x08
> >   #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09
> >   #define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a
> > +#define DRM_FORMAT_MOD_VENDOR_VS      0x0b
> >   
> >   /* add more to the end as needed */
> >   
> > @@ -1519,6 +1520,88 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
> >   #define AMD_FMT_MOD_CLEAR(field) \
> >   	(~((__u64)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT))
> >   
> > +#define DRM_FORMAT_MOD_VS_TYPE_NORMAL        0x00
> > +#define DRM_FORMAT_MOD_VS_TYPE_COMPRESSED    0x01
> > +#define DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT  0x02
> > +#define DRM_FORMAT_MOD_VS_TYPE_MASK     ((__u64)0x3 << 54)
> > +
> > +#define fourcc_mod_vs_code(type, val) \
> > +	fourcc_mod_code(VS, ((((__u64)type) << 54) | (val)))
> > +
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_MODE_MASK    0x3F
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_XMAJOR   0x00
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_YMAJOR   0x01
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4     0x02
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4      0x03
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_4X8      0x04
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X4   0x06
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X4     0x07
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4     0x08
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X1  0x09
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X1  0x0A
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X4   0x0B
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X2  0x0C
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X2  0x0D
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X4  0x0E
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X1   0x0F
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X8     0x10
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X16     0x11
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_512X1  0x12
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X4   0x13
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X2   0x14
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X2   0x15
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X1   0x16
> > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X1   0x17
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X4    0x18
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_256X4    0x19
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_512X4    0x1A
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X16    0x1B
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X16    0x1C
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X16    0x1D
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X8    0x1E
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4_S    0x1F
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_S   0x20
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_S   0x21
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_LSB 0x22
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_LSB 0x23
> > +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X8     0x24
> > +
> > +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_32      (0x01 << 6)
> > +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_64      (0x01 << 7)
> > +
> > +#define fourcc_mod_vs_dec_code(tile, align) \
> > +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_COMPRESSED, \
> > +				((tile) | (align)))
> > +
> > +#define DRM_FORMAT_MOD_VS_NORM_MODE_MASK        0x1F
> > +#define DRM_FORMAT_MOD_VS_LINEAR                0x00
> > +#define DRM_FORMAT_MOD_VS_TILED4x4              0x01
> > +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR    0x02
> > +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR    0x03
> > +#define DRM_FORMAT_MOD_VS_TILE_8X8              0x04
> > +#define DRM_FORMAT_MOD_VS_TILE_MODE1            0x05
> > +#define DRM_FORMAT_MOD_VS_TILE_MODE2            0x06
> > +#define DRM_FORMAT_MOD_VS_TILE_8X4              0x07
> > +#define DRM_FORMAT_MOD_VS_TILE_MODE4            0x08
> > +#define DRM_FORMAT_MOD_VS_TILE_MODE5            0x09
> > +#define DRM_FORMAT_MOD_VS_TILE_MODE6            0x0A
> > +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4    0x0B
> > +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8    0x0C
> > +#define DRM_FORMAT_MOD_VS_TILE_Y                0x0D
> > +#define DRM_FORMAT_MOD_VS_TILE_128X1            0x0F
> > +#define DRM_FORMAT_MOD_VS_TILE_256X1            0x10
> > +#define DRM_FORMAT_MOD_VS_TILE_32X1             0x11
> > +#define DRM_FORMAT_MOD_VS_TILE_64X1             0x12
> > +#define DRM_FORMAT_MOD_VS_TILE_MODE4X4          0x15
> > +
> > +#define fourcc_mod_vs_norm_code(tile) \
> > +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_NORMAL, \
> > +				(tile))
> > +
> > +#define fourcc_mod_vs_custom_code(tile) \
> > +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT, \
> > +				(tile))
> > +
> >   #if defined(__cplusplus)
> >   }
> >   #endif
> > diff --git a/include/uapi/drm/vs_drm.h b/include/uapi/drm/vs_drm.h
> > new file mode 100644
> > index 000000000000..96b7fc95d658
> > --- /dev/null
> > +++ b/include/uapi/drm/vs_drm.h
> 
> Another UAPI addition that appears to be unused. Please only add things 
> that you're using.
> 
> Best regards
> Thomas
> 
> > @@ -0,0 +1,50 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
> > +/*
> > + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
> > + */
> > +
> > +#ifndef __VS_DRM_H__
> > +#define __VS_DRM_H__
> > +
> > +#include "drm.h"
> > +
> > +enum drm_vs_degamma_mode {
> > +	VS_DEGAMMA_DISABLE = 0,
> > +	VS_DEGAMMA_BT709 = 1,
> > +	VS_DEGAMMA_BT2020 = 2,
> > +};
> > +
> > +enum drm_vs_sync_dc_mode {
> > +	VS_SINGLE_DC = 0,
> > +	VS_MULTI_DC_PRIMARY = 1,
> > +	VS_MULTI_DC_SECONDARY = 2,
> > +};
> > +
> > +enum drm_vs_mmu_prefetch_mode {
> > +	VS_MMU_PREFETCH_DISABLE = 0,
> > +	VS_MMU_PREFETCH_ENABLE = 1,
> > +};
> > +
> > +struct drm_vs_watermark {
> > +	__u32 watermark;
> > +	__u8 qos_low;
> > +	__u8 qos_high;
> > +};
> > +
> > +struct drm_vs_color_mgmt {
> > +	__u32 colorkey;
> > +	__u32 colorkey_high;
> > +	__u32 clear_value;
> > +	bool  clear_enable;
> > +	bool  transparency;
> > +};
> > +
> > +struct drm_vs_roi {
> > +	bool enable;
> > +	__u16 roi_x;
> > +	__u16 roi_y;
> > +	__u16 roi_w;
> > +	__u16 roi_h;
> > +};
> > +
> > +#endif /* __VS_DRM_H__ */
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Frankenstrasse 146, 90461 Nuernberg, Germany
> GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
> HRB 36809 (AG Nuernberg)


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

* Re: [PATCH 3/9] drm/verisilicon: Add basic drm driver
  2023-07-07 18:09     ` Nicolas Dufresne
@ 2023-07-08 19:11       ` Thomas Zimmermann
  2023-07-13 15:14         ` Nicolas Dufresne
  0 siblings, 1 reply; 46+ messages in thread
From: Thomas Zimmermann @ 2023-07-08 19:11 UTC (permalink / raw)
  To: Nicolas Dufresne, Keith Zhao, dri-devel, devicetree,
	linux-kernel, linux-riscv, linux-media, linaro-mm-sig
  Cc: Conor Dooley, Albert Ou, Emil Renner Berthing, christian.koenig,
	Bjorn Andersson, Chris Morgan, Changhuang Liang, Jagan Teki,
	Jack Zhu, Rob Herring, Palmer Dabbelt, Krzysztof Kozlowski,
	Paul Walmsley, Shengyang Chen, Shawn Guo, Sumit Semwal


[-- Attachment #1.1: Type: text/plain, Size: 19134 bytes --]

Hi

Am 07.07.23 um 20:09 schrieb Nicolas Dufresne:
[...]
>>> +config DRM_VERISILICON
>>> +	tristate "DRM Support for VeriSilicon"
>>
>> Can you rename the driver and files? 'VeriSilicon' seems
>> unpronounceable. Simply 'StarFive' and starfive/ would be fine.
> 
> Are you sure you want to request this ? If the display controller is a
> Verisilicon design, it will be super odd to use on other SoC that aren't from
> StarFive. Think about STM network driver, which is DesignWare.

It's not a hard requirement. If that's the name, so be it.

Best regards
Thomas

> 
> Nicolas
> 
>>
>>> +	depends on DRM
>>> +	select DRM_KMS_HELPER
>>> +	select CMA
>>> +	select DMA_CMA
>>> +	help
>>> +	  Choose this option if you have a VeriSilicon soc chipset.
>>> +	  This driver provides VeriSilicon kernel mode
>>> +	  setting and buffer management. It does not
>>> +	  provide 2D or 3D acceleration.
>>> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
>>> new file mode 100644
>>> index 000000000000..64ce1b26546c
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/verisilicon/Makefile
>>> @@ -0,0 +1,6 @@
>>> +# SPDX-License-Identifier: GPL-2.0
>>> +
>>> +vs_drm-objs := vs_drv.o
>>> +
>>> +obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
>>> +
>>> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
>>> new file mode 100644
>>> index 000000000000..24d333598477
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
>>> @@ -0,0 +1,284 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>>> + */
>>> +
>>> +#include <linux/clk.h>
>>> +#include <linux/component.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/dma-mapping.h>
>>> +#include <linux/iommu.h>
>>> +#include <linux/of_graph.h>
>>> +#include <linux/of_reserved_mem.h>
>>> +#include <linux/pm_runtime.h>
>>> +#include <linux/reset.h>
>>> +#include <linux/version.h>
>>> +
>>> +#include <drm/drm_aperture.h>
>>> +#include <drm/drm_crtc.h>
>>> +#include <drm/drm_crtc_helper.h>
>>> +#include <drm/drm_debugfs.h>
>>> +#include <drm/drm_drv.h>
>>> +#include <drm/drm_fb_helper.h>
>>> +#include <drm/drm_fbdev_generic.h>
>>> +#include <drm/drm_file.h>
>>> +#include <drm/drm_fourcc.h>
>>> +#include <drm/drm_ioctl.h>
>>> +#include <drm/drm_of.h>
>>> +#include <drm/drm_prime.h>
>>> +#include <drm/drm_probe_helper.h>
>>> +#include <drm/drm_vblank.h>
>>> +
>>> +#include "vs_drv.h"
>>> +
>>> +#define DRV_NAME	"starfive"
>>> +#define DRV_DESC	"Starfive DRM driver"
>>> +#define DRV_DATE	"202305161"
>>> +#define DRV_MAJOR	1
>>> +#define DRV_MINOR	0
>>> +
>>> +static struct platform_driver vs_drm_platform_driver;
>>> +
>>> +static const struct file_operations fops = {
>>> +	.owner			= THIS_MODULE,
>>> +	.open			= drm_open,
>>> +	.release		= drm_release,
>>> +	.unlocked_ioctl	= drm_ioctl,
>>> +	.compat_ioctl	= drm_compat_ioctl,
>>> +	.poll			= drm_poll,
>>> +	.read			= drm_read,
>>> +};
>>> +
>>> +static struct drm_driver vs_drm_driver = {
>>> +	.driver_features	= DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
>>> +	.lastclose		= drm_fb_helper_lastclose,
>>> +	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
>>> +	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
>>> +	.fops			= &fops,
>>> +	.name			= DRV_NAME,
>>> +	.desc			= DRV_DESC,
>>> +	.date			= DRV_DATE,
>>> +	.major			= DRV_MAJOR,
>>> +	.minor			= DRV_MINOR,
>>> +};
>>> +
>>> +void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
>>> +				   unsigned int alignment)
>>> +{
>>> +	struct vs_drm_private *priv = drm_dev->dev_private;
>>> +
>>> +	if (alignment > priv->pitch_alignment)
>>> +		priv->pitch_alignment = alignment;
>>> +}
>>> +
>>> +static int vs_drm_bind(struct device *dev)
>>> +{
>>> +	struct drm_device *drm_dev;
>>> +	struct vs_drm_private *priv;
>>> +	int ret;
>>> +	static u64 dma_mask = DMA_BIT_MASK(40);
>>> +
>>> +	/* Remove existing drivers that may own the framebuffer memory. */
>>> +	ret = drm_aperture_remove_framebuffers(false, &vs_drm_driver);
>>> +	if (ret) {
>>> +		DRM_DEV_ERROR(dev,
>>
>> drm_err(), drm_info(), drm_warn(), etc.  Here and everwhere else. The
>> DRM_DEV_*() print macros are obsolete.
>>
>>> +			      "Failed to remove existing framebuffers - %d.\n",
>>> +			      ret);
>>> +		return ret;
>>> +	}
>>> +
>>> +	drm_dev = drm_dev_alloc(&vs_drm_driver, dev);
>>> +	if (IS_ERR(drm_dev))
>>> +		return PTR_ERR(drm_dev);
>>> +
>>> +	dev_set_drvdata(dev, drm_dev);
>>> +
>>> +	priv = devm_kzalloc(drm_dev->dev, sizeof(struct vs_drm_private),
>>> +			    GFP_KERNEL);
>>> +	if (!priv) {
>>> +		ret = -ENOMEM;
>>> +		goto err_put_dev;
>>> +	}
>>> +
>>> +	priv->pitch_alignment = 64;
>>> +	priv->dma_dev = drm_dev->dev;
>>> +	priv->dma_dev->coherent_dma_mask = dma_mask;
>>> +	drm_dev->dev_private = priv;
>>
>> dev_private is obsolete and about to go away at some point.
>>
>> Please embed drm_device in vs_drm_private and allocate the memory with
>> devm_drm_dev_alloc().
>>
>>> +
>>> +	drm_mode_config_init(drm_dev);
>>
>> drmm_mode_config_init() please.
>>
>>> +
>>> +	/* Now try and bind all our sub-components */
>>> +	ret = component_bind_all(dev, drm_dev);
>>> +	if (ret)
>>> +		goto err_mode;
>>> +
>>> +	ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
>>> +	if (ret)
>>> +		goto err_bind;
>>> +
>>> +	drm_mode_config_reset(drm_dev);
>>> +
>>> +	drm_kms_helper_poll_init(drm_dev);
>>> +
>>> +	ret = drm_dev_register(drm_dev, 0);
>>> +	if (ret)
>>> +		goto err_helper;
>>> +
>>> +	drm_fbdev_generic_setup(drm_dev, 32);
>>> +
>>> +	return 0;
>>> +
>>> +err_helper:
>>> +	drm_kms_helper_poll_fini(drm_dev);
>>> +err_bind:
>>> +	component_unbind_all(drm_dev->dev, drm_dev);
>>> +err_mode:
>>> +	drm_mode_config_cleanup(drm_dev);
>>> +	if (priv->domain)
>>> +		iommu_domain_free(priv->domain);
>>> +err_put_dev:
>>> +	drm_dev->dev_private = NULL;
>>> +	dev_set_drvdata(dev, NULL);
>>> +	drm_dev_put(drm_dev);
>>> +	return ret;
>>> +}
>>> +
>>> +static void vs_drm_unbind(struct device *dev)
>>> +{
>>> +	struct drm_device *drm_dev = dev_get_drvdata(dev);
>>> +	struct vs_drm_private *priv = drm_dev->dev_private;
>>> +
>>> +	drm_dev_unregister(drm_dev);
>>> +
>>> +	drm_kms_helper_poll_fini(drm_dev);
>>> +
>>> +	component_unbind_all(drm_dev->dev, drm_dev);
>>> +
>>> +	drm_mode_config_cleanup(drm_dev);
>>> +
>>> +	if (priv->domain) {
>>> +		iommu_domain_free(priv->domain);
>>> +		priv->domain = NULL;
>>> +	}
>>> +
>>> +	drm_dev->dev_private = NULL;
>>> +	dev_set_drvdata(dev, NULL);
>>> +	drm_dev_put(drm_dev);
>>
>> You rather want to convert the individual steps of this cleanup to
>> managed functions (drmm_ and devm_) to automate the cleanup when as part
>> of drm_dev_put().
>>
>>> +}
>>> +
>>> +static const struct component_master_ops vs_drm_ops = {
>>> +	.bind = vs_drm_bind,
>>> +	.unbind = vs_drm_unbind,
>>> +};
>>> +
>>> +static struct platform_driver *drm_sub_drivers[] = {
>>> +};
>>> +
>>> +#define NUM_DRM_DRIVERS \
>>> +	(sizeof(drm_sub_drivers) / sizeof(struct platform_driver *))
>>
>> Does this really work? sizeof(drm_sub_drivers) isn't know at compile
>> time. It is always assumed to be 0 AFAICT. Or do you fill this array in
>> later patches?
>>
>>
>>> +
>>> +static int compare_dev(struct device *dev, void *data)
>>> +{
>>> +	return dev == (struct device *)data;
>>> +}
>>> +
>>> +static struct component_match *vs_drm_match_add(struct device *dev)
>>> +{
>>> +	struct component_match *match = NULL;
>>> +	int i;
>>> +
>>> +	for (i = 0; i < NUM_DRM_DRIVERS; ++i) {
>>> +		struct platform_driver *drv = drm_sub_drivers[i];
>>> +		struct device *p = NULL, *d;
>>> +
>>> +		while ((d = platform_find_device_by_driver(p, &drv->driver))) {
>>> +			put_device(p);
>>> +
>>> +			component_match_add(dev, &match, compare_dev, d);
>>> +			p = d;
>>> +		}
>>> +		put_device(p);
>>> +	}
>>> +
>>> +	return match ?: ERR_PTR(-ENODEV);
>>> +}
>>> +
>>> +static int vs_drm_platform_probe(struct platform_device *pdev)
>>> +{
>>> +	struct device *dev = &pdev->dev;
>>> +	struct component_match *match;
>>> +
>>> +	match = vs_drm_match_add(dev);
>>> +	if (IS_ERR(match))
>>> +		return PTR_ERR(match);
>>> +
>>> +	return component_master_add_with_match(dev, &vs_drm_ops, match);
>>> +}
>>> +
>>> +static int vs_drm_platform_remove(struct platform_device *pdev)
>>> +{
>>> +	component_master_del(&pdev->dev, &vs_drm_ops);
>>> +	return 0;
>>> +}
>>> +
>>> +#ifdef CONFIG_PM_SLEEP
>>> +static int vs_drm_suspend(struct device *dev)
>>> +{
>>> +	struct drm_device *drm = dev_get_drvdata(dev);
>>> +
>>> +	return drm_mode_config_helper_suspend(drm);
>>> +}
>>> +
>>> +static int vs_drm_resume(struct device *dev)
>>> +{
>>> +	struct drm_device *drm = dev_get_drvdata(dev);
>>> +
>>> +	return drm_mode_config_helper_resume(drm);
>>> +}
>>> +#endif
>>> +
>>> +static SIMPLE_DEV_PM_OPS(vs_drm_pm_ops, vs_drm_suspend, vs_drm_resume);
>>> +
>>> +static const struct of_device_id vs_drm_dt_ids[] = {
>>> +	{ .compatible = "verisilicon,display-subsystem", },
>>> +};
>>> +
>>> +MODULE_DEVICE_TABLE(of, vs_drm_dt_ids);
>>> +
>>> +static struct platform_driver vs_drm_platform_driver = {
>>> +	.probe = vs_drm_platform_probe,
>>> +	.remove = vs_drm_platform_remove,
>>> +
>>> +	.driver = {
>>> +		.name = DRV_NAME,
>>> +		.of_match_table = vs_drm_dt_ids,
>>> +		.pm = &vs_drm_pm_ops,
>>> +	},
>>> +};
>>> +
>>> +static int __init vs_drm_init(void)
>>> +{
>>> +	int ret;
>>> +
>>> +	ret = platform_register_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	ret = platform_driver_register(&vs_drm_platform_driver);
>>> +	if (ret)
>>> +		platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
>>> +
>>> +	return ret;
>>> +}
>>> +
>>> +static void __exit vs_drm_fini(void)
>>> +{
>>> +	platform_driver_unregister(&vs_drm_platform_driver);
>>> +	platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
>>> +}
>>> +
>>> +module_init(vs_drm_init);
>>> +module_exit(vs_drm_fini);
>>> +
>>> +MODULE_DESCRIPTION("VeriSilicon DRM Driver");
>>> +MODULE_LICENSE("GPL");
>>> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
>>> new file mode 100644
>>> index 000000000000..0382b44e3bf0
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/verisilicon/vs_drv.h
>>> @@ -0,0 +1,48 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +/*
>>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>>> + */
>>> +
>>> +#ifndef __VS_DRV_H__
>>> +#define __VS_DRV_H__
>>> +
>>> +#include <linux/module.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/version.h>
>>> +#include <drm/drm_drv.h>
>>> +#include <drm/drm_gem.h>
>>> +
>>> +/*
>>> + *
>>> + * @dma_dev: device for DMA API.
>>> + *	- use the first attached device if support iommu
>>> +	else use drm device (only contiguous buffer support)
>>> + * @domain: iommu domain for DRM.
>>> + *	- all DC IOMMU share same domain to reduce mapping
>>> + * @pitch_alignment: buffer pitch alignment required by sub-devices.
>>> + *
>>> + */
>>> +struct vs_drm_private {
>>> +	struct device *dma_dev;
>>> +	struct iommu_domain *domain;
>>> +	unsigned int pitch_alignment;
>>> +};
>>
>> As mentioned, this struct needs to embed struct drm_device.
>>
>>> +
>>> +void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
>>> +				   unsigned int alignment);
>>> +
>>> +static inline struct device *to_dma_dev(struct drm_device *dev)
>>> +{
>>> +	struct vs_drm_private *priv = dev->dev_private;
>>> +
>>> +	return priv->dma_dev;
>>
>> And this needs to be an upcast via container_of().
>>
>>> +}
>>> +
>>> +static inline bool is_iommu_enabled(struct drm_device *dev)
>>> +{
>>> +	struct vs_drm_private *priv = dev->dev_private;
>>> +
>>> +	return priv->domain ? true : false;
>>> +}
>>> +
>>> +#endif /* __VS_DRV_H__ */
>>> diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
>>> index de703c6be969..af4fb50f9207 100644
>>> --- a/include/uapi/drm/drm_fourcc.h
>>> +++ b/include/uapi/drm/drm_fourcc.h
>>
>> The UAPI changes shouldn't be needed in this patch?
>>
>>> @@ -419,6 +419,7 @@ extern "C" {
>>>    #define DRM_FORMAT_MOD_VENDOR_ARM     0x08
>>>    #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09
>>>    #define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a
>>> +#define DRM_FORMAT_MOD_VENDOR_VS      0x0b
>>>    
>>>    /* add more to the end as needed */
>>>    
>>> @@ -1519,6 +1520,88 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
>>>    #define AMD_FMT_MOD_CLEAR(field) \
>>>    	(~((__u64)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT))
>>>    
>>> +#define DRM_FORMAT_MOD_VS_TYPE_NORMAL        0x00
>>> +#define DRM_FORMAT_MOD_VS_TYPE_COMPRESSED    0x01
>>> +#define DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT  0x02
>>> +#define DRM_FORMAT_MOD_VS_TYPE_MASK     ((__u64)0x3 << 54)
>>> +
>>> +#define fourcc_mod_vs_code(type, val) \
>>> +	fourcc_mod_code(VS, ((((__u64)type) << 54) | (val)))
>>> +
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_MODE_MASK    0x3F
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_XMAJOR   0x00
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_YMAJOR   0x01
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4     0x02
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4      0x03
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_4X8      0x04
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X4   0x06
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X4     0x07
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4     0x08
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X1  0x09
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X1  0x0A
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X4   0x0B
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X2  0x0C
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X2  0x0D
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X4  0x0E
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X1   0x0F
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X8     0x10
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X16     0x11
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_512X1  0x12
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X4   0x13
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X2   0x14
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X2   0x15
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X1   0x16
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X1   0x17
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X4    0x18
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_256X4    0x19
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_512X4    0x1A
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X16    0x1B
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X16    0x1C
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X16    0x1D
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X8    0x1E
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4_S    0x1F
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_S   0x20
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_S   0x21
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_LSB 0x22
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_LSB 0x23
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X8     0x24
>>> +
>>> +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_32      (0x01 << 6)
>>> +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_64      (0x01 << 7)
>>> +
>>> +#define fourcc_mod_vs_dec_code(tile, align) \
>>> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_COMPRESSED, \
>>> +				((tile) | (align)))
>>> +
>>> +#define DRM_FORMAT_MOD_VS_NORM_MODE_MASK        0x1F
>>> +#define DRM_FORMAT_MOD_VS_LINEAR                0x00
>>> +#define DRM_FORMAT_MOD_VS_TILED4x4              0x01
>>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR    0x02
>>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR    0x03
>>> +#define DRM_FORMAT_MOD_VS_TILE_8X8              0x04
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE1            0x05
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE2            0x06
>>> +#define DRM_FORMAT_MOD_VS_TILE_8X4              0x07
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE4            0x08
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE5            0x09
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE6            0x0A
>>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4    0x0B
>>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8    0x0C
>>> +#define DRM_FORMAT_MOD_VS_TILE_Y                0x0D
>>> +#define DRM_FORMAT_MOD_VS_TILE_128X1            0x0F
>>> +#define DRM_FORMAT_MOD_VS_TILE_256X1            0x10
>>> +#define DRM_FORMAT_MOD_VS_TILE_32X1             0x11
>>> +#define DRM_FORMAT_MOD_VS_TILE_64X1             0x12
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE4X4          0x15
>>> +
>>> +#define fourcc_mod_vs_norm_code(tile) \
>>> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_NORMAL, \
>>> +				(tile))
>>> +
>>> +#define fourcc_mod_vs_custom_code(tile) \
>>> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT, \
>>> +				(tile))
>>> +
>>>    #if defined(__cplusplus)
>>>    }
>>>    #endif
>>> diff --git a/include/uapi/drm/vs_drm.h b/include/uapi/drm/vs_drm.h
>>> new file mode 100644
>>> index 000000000000..96b7fc95d658
>>> --- /dev/null
>>> +++ b/include/uapi/drm/vs_drm.h
>>
>> Another UAPI addition that appears to be unused. Please only add things
>> that you're using.
>>
>> Best regards
>> Thomas
>>
>>> @@ -0,0 +1,50 @@
>>> +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
>>> +/*
>>> + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
>>> + */
>>> +
>>> +#ifndef __VS_DRM_H__
>>> +#define __VS_DRM_H__
>>> +
>>> +#include "drm.h"
>>> +
>>> +enum drm_vs_degamma_mode {
>>> +	VS_DEGAMMA_DISABLE = 0,
>>> +	VS_DEGAMMA_BT709 = 1,
>>> +	VS_DEGAMMA_BT2020 = 2,
>>> +};
>>> +
>>> +enum drm_vs_sync_dc_mode {
>>> +	VS_SINGLE_DC = 0,
>>> +	VS_MULTI_DC_PRIMARY = 1,
>>> +	VS_MULTI_DC_SECONDARY = 2,
>>> +};
>>> +
>>> +enum drm_vs_mmu_prefetch_mode {
>>> +	VS_MMU_PREFETCH_DISABLE = 0,
>>> +	VS_MMU_PREFETCH_ENABLE = 1,
>>> +};
>>> +
>>> +struct drm_vs_watermark {
>>> +	__u32 watermark;
>>> +	__u8 qos_low;
>>> +	__u8 qos_high;
>>> +};
>>> +
>>> +struct drm_vs_color_mgmt {
>>> +	__u32 colorkey;
>>> +	__u32 colorkey_high;
>>> +	__u32 clear_value;
>>> +	bool  clear_enable;
>>> +	bool  transparency;
>>> +};
>>> +
>>> +struct drm_vs_roi {
>>> +	bool enable;
>>> +	__u16 roi_x;
>>> +	__u16 roi_y;
>>> +	__u16 roi_w;
>>> +	__u16 roi_h;
>>> +};
>>> +
>>> +#endif /* __VS_DRM_H__ */
>>
>> -- 
>> Thomas Zimmermann
>> Graphics Driver Developer
>> SUSE Software Solutions Germany GmbH
>> Frankenstrasse 146, 90461 Nuernberg, Germany
>> GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
>> HRB 36809 (AG Nuernberg)
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH 7/9] drm/verisilicon: Add drm plane funcs
  2023-06-02  7:40 ` [PATCH 7/9] drm/verisilicon: Add drm plane funcs Keith Zhao
  2023-06-30 12:14   ` Thomas Zimmermann
@ 2023-07-10 16:46   ` Shengyu Qu
  2023-07-11  1:44     ` Keith Zhao
  1 sibling, 1 reply; 46+ messages in thread
From: Shengyu Qu @ 2023-07-10 16:46 UTC (permalink / raw)
  To: Keith Zhao, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: wiagn233, David Airlie, Daniel Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Emil Renner Berthing,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Philipp Zabel, Sumit Semwal,
	christian.koenig, Bjorn Andersson, Heiko Stuebner, Shawn Guo,
	Jagan Teki, Chris Morgan, Jack Zhu, Shengyang Chen,
	Changhuang Liang

Hello Keith,
> +
> +static void vs_plane_atomic_update(struct drm_plane *plane,
> +				   struct drm_atomic_state *state)
> +{
> +	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
> +									   plane);
> +	unsigned char i, num_planes;
> +	struct drm_framebuffer *fb;
> +	struct vs_plane *vs_plane = to_vs_plane(plane);
> +	//struct drm_plane_state *state = plane->state;
> +	struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
> +	struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
> +	//struct drm_format_name_buf *name = &plane_state->status.format_name;
> +
> +	if (!new_state->fb || !new_state->crtc)
> +		return;
> +
> +	fb = new_state->fb;
> +
> +	num_planes = vs_get_plane_number(fb);
> +
> +	for (i = 0; i < num_planes; i++) {
> +		struct vs_gem_object *vs_obj;
> +
> +		vs_obj = vs_fb_get_gem_obj(fb, i);
> +		vs_plane->dma_addr[i] = vs_obj->iova + fb->offsets[i];

There is a dcache flush operation here in downstream driver. Is that a 
cache coherence problem?

Best regards,

Shengyu

> +	}
> +
> +	plane_state->status.src = drm_plane_state_src(new_state);
> +	plane_state->status.dest = drm_plane_state_dest(new_state);
> +
> +	vs_plane->funcs->update(vs_crtc->dev, vs_plane, plane, state);
> +}
>

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

* Re: [PATCH 7/9] drm/verisilicon: Add drm plane funcs
  2023-07-10 16:46   ` Shengyu Qu
@ 2023-07-11  1:44     ` Keith Zhao
  0 siblings, 0 replies; 46+ messages in thread
From: Keith Zhao @ 2023-07-11  1:44 UTC (permalink / raw)
  To: Shengyu Qu, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Philipp Zabel, Sumit Semwal, christian.koenig,
	Bjorn Andersson, Heiko Stuebner, Shawn Guo, Jagan Teki,
	Chris Morgan, Jack Zhu, Shengyang Chen, Changhuang Liang



On 2023/7/11 0:46, Shengyu Qu wrote:
> Hello Keith,
>> +
>> +static void vs_plane_atomic_update(struct drm_plane *plane,
>> +                   struct drm_atomic_state *state)
>> +{
>> +    struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
>> +                                       plane);
>> +    unsigned char i, num_planes;
>> +    struct drm_framebuffer *fb;
>> +    struct vs_plane *vs_plane = to_vs_plane(plane);
>> +    //struct drm_plane_state *state = plane->state;
>> +    struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
>> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
>> +    //struct drm_format_name_buf *name = &plane_state->status.format_name;
>> +
>> +    if (!new_state->fb || !new_state->crtc)
>> +        return;
>> +
>> +    fb = new_state->fb;
>> +
>> +    num_planes = vs_get_plane_number(fb);
>> +
>> +    for (i = 0; i < num_planes; i++) {
>> +        struct vs_gem_object *vs_obj;
>> +
>> +        vs_obj = vs_fb_get_gem_obj(fb, i);
>> +        vs_plane->dma_addr[i] = vs_obj->iova + fb->offsets[i];
> 
> There is a dcache flush operation here in downstream driver. Is that a cache coherence problem?
> 
> Best regards,
> 
> Shengyu
> 
>> +    }
>> +
>> +    plane_state->status.src = drm_plane_state_src(new_state);
>> +    plane_state->status.dest = drm_plane_state_dest(new_state);
>> +
>> +    vs_plane->funcs->update(vs_crtc->dev, vs_plane, plane, state);
>> +}
>>yes , You can find that the current situation is very professional. 
This problem exists at present, but the dma interface is not perfect at now, 
and the dma_sync_single_for_device interface needs to be implemented later. 
I will consider repairing this problem in the form of patch

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

* Re: [PATCH 3/9] drm/verisilicon: Add basic drm driver
  2023-07-08 19:11       ` Thomas Zimmermann
@ 2023-07-13 15:14         ` Nicolas Dufresne
  0 siblings, 0 replies; 46+ messages in thread
From: Nicolas Dufresne @ 2023-07-13 15:14 UTC (permalink / raw)
  To: Thomas Zimmermann, Keith Zhao, dri-devel, devicetree,
	linux-kernel, linux-riscv, linux-media, linaro-mm-sig
  Cc: Conor Dooley, Albert Ou, Emil Renner Berthing, christian.koenig,
	Bjorn Andersson, Chris Morgan, Changhuang Liang, Jagan Teki,
	Jack Zhu, Rob Herring, Palmer Dabbelt, Krzysztof Kozlowski,
	Paul Walmsley, Shengyang Chen, Shawn Guo, Sumit Semwal

Le samedi 08 juillet 2023 à 21:11 +0200, Thomas Zimmermann a écrit :
> Hi
> 
> Am 07.07.23 um 20:09 schrieb Nicolas Dufresne:
> [...]
> > > > +config DRM_VERISILICON
> > > > +	tristate "DRM Support for VeriSilicon"
> > > 
> > > Can you rename the driver and files? 'VeriSilicon' seems
> > > unpronounceable. Simply 'StarFive' and starfive/ would be fine.
> > 
> > Are you sure you want to request this ? If the display controller is a
> > Verisilicon design, it will be super odd to use on other SoC that aren't from
> > StarFive. Think about STM network driver, which is DesignWare.
> 
> It's not a hard requirement. If that's the name, so be it.

If that helps you pronouncing this, it is commonly pronounced has:

  very-silicon

Or just a caulking mess if you really hate it :-D

Nicolas

> 
> Best regards
> Thomas
> 
> > 
> > Nicolas
> > 
> > > 
> > > > +	depends on DRM
> > > > +	select DRM_KMS_HELPER
> > > > +	select CMA
> > > > +	select DMA_CMA
> > > > +	help
> > > > +	  Choose this option if you have a VeriSilicon soc chipset.
> > > > +	  This driver provides VeriSilicon kernel mode
> > > > +	  setting and buffer management. It does not
> > > > +	  provide 2D or 3D acceleration.
> > > > diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> > > > new file mode 100644
> > > > index 000000000000..64ce1b26546c
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/verisilicon/Makefile
> > > > @@ -0,0 +1,6 @@
> > > > +# SPDX-License-Identifier: GPL-2.0
> > > > +
> > > > +vs_drm-objs := vs_drv.o
> > > > +
> > > > +obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
> > > > +
> > > > diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
> > > > new file mode 100644
> > > > index 000000000000..24d333598477
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> > > > @@ -0,0 +1,284 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +/*
> > > > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > > > + */
> > > > +
> > > > +#include <linux/clk.h>
> > > > +#include <linux/component.h>
> > > > +#include <linux/delay.h>
> > > > +#include <linux/dma-mapping.h>
> > > > +#include <linux/iommu.h>
> > > > +#include <linux/of_graph.h>
> > > > +#include <linux/of_reserved_mem.h>
> > > > +#include <linux/pm_runtime.h>
> > > > +#include <linux/reset.h>
> > > > +#include <linux/version.h>
> > > > +
> > > > +#include <drm/drm_aperture.h>
> > > > +#include <drm/drm_crtc.h>
> > > > +#include <drm/drm_crtc_helper.h>
> > > > +#include <drm/drm_debugfs.h>
> > > > +#include <drm/drm_drv.h>
> > > > +#include <drm/drm_fb_helper.h>
> > > > +#include <drm/drm_fbdev_generic.h>
> > > > +#include <drm/drm_file.h>
> > > > +#include <drm/drm_fourcc.h>
> > > > +#include <drm/drm_ioctl.h>
> > > > +#include <drm/drm_of.h>
> > > > +#include <drm/drm_prime.h>
> > > > +#include <drm/drm_probe_helper.h>
> > > > +#include <drm/drm_vblank.h>
> > > > +
> > > > +#include "vs_drv.h"
> > > > +
> > > > +#define DRV_NAME	"starfive"
> > > > +#define DRV_DESC	"Starfive DRM driver"
> > > > +#define DRV_DATE	"202305161"
> > > > +#define DRV_MAJOR	1
> > > > +#define DRV_MINOR	0
> > > > +
> > > > +static struct platform_driver vs_drm_platform_driver;
> > > > +
> > > > +static const struct file_operations fops = {
> > > > +	.owner			= THIS_MODULE,
> > > > +	.open			= drm_open,
> > > > +	.release		= drm_release,
> > > > +	.unlocked_ioctl	= drm_ioctl,
> > > > +	.compat_ioctl	= drm_compat_ioctl,
> > > > +	.poll			= drm_poll,
> > > > +	.read			= drm_read,
> > > > +};
> > > > +
> > > > +static struct drm_driver vs_drm_driver = {
> > > > +	.driver_features	= DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
> > > > +	.lastclose		= drm_fb_helper_lastclose,
> > > > +	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> > > > +	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> > > > +	.fops			= &fops,
> > > > +	.name			= DRV_NAME,
> > > > +	.desc			= DRV_DESC,
> > > > +	.date			= DRV_DATE,
> > > > +	.major			= DRV_MAJOR,
> > > > +	.minor			= DRV_MINOR,
> > > > +};
> > > > +
> > > > +void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
> > > > +				   unsigned int alignment)
> > > > +{
> > > > +	struct vs_drm_private *priv = drm_dev->dev_private;
> > > > +
> > > > +	if (alignment > priv->pitch_alignment)
> > > > +		priv->pitch_alignment = alignment;
> > > > +}
> > > > +
> > > > +static int vs_drm_bind(struct device *dev)
> > > > +{
> > > > +	struct drm_device *drm_dev;
> > > > +	struct vs_drm_private *priv;
> > > > +	int ret;
> > > > +	static u64 dma_mask = DMA_BIT_MASK(40);
> > > > +
> > > > +	/* Remove existing drivers that may own the framebuffer memory. */
> > > > +	ret = drm_aperture_remove_framebuffers(false, &vs_drm_driver);
> > > > +	if (ret) {
> > > > +		DRM_DEV_ERROR(dev,
> > > 
> > > drm_err(), drm_info(), drm_warn(), etc.  Here and everwhere else. The
> > > DRM_DEV_*() print macros are obsolete.
> > > 
> > > > +			      "Failed to remove existing framebuffers - %d.\n",
> > > > +			      ret);
> > > > +		return ret;
> > > > +	}
> > > > +
> > > > +	drm_dev = drm_dev_alloc(&vs_drm_driver, dev);
> > > > +	if (IS_ERR(drm_dev))
> > > > +		return PTR_ERR(drm_dev);
> > > > +
> > > > +	dev_set_drvdata(dev, drm_dev);
> > > > +
> > > > +	priv = devm_kzalloc(drm_dev->dev, sizeof(struct vs_drm_private),
> > > > +			    GFP_KERNEL);
> > > > +	if (!priv) {
> > > > +		ret = -ENOMEM;
> > > > +		goto err_put_dev;
> > > > +	}
> > > > +
> > > > +	priv->pitch_alignment = 64;
> > > > +	priv->dma_dev = drm_dev->dev;
> > > > +	priv->dma_dev->coherent_dma_mask = dma_mask;
> > > > +	drm_dev->dev_private = priv;
> > > 
> > > dev_private is obsolete and about to go away at some point.
> > > 
> > > Please embed drm_device in vs_drm_private and allocate the memory with
> > > devm_drm_dev_alloc().
> > > 
> > > > +
> > > > +	drm_mode_config_init(drm_dev);
> > > 
> > > drmm_mode_config_init() please.
> > > 
> > > > +
> > > > +	/* Now try and bind all our sub-components */
> > > > +	ret = component_bind_all(dev, drm_dev);
> > > > +	if (ret)
> > > > +		goto err_mode;
> > > > +
> > > > +	ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
> > > > +	if (ret)
> > > > +		goto err_bind;
> > > > +
> > > > +	drm_mode_config_reset(drm_dev);
> > > > +
> > > > +	drm_kms_helper_poll_init(drm_dev);
> > > > +
> > > > +	ret = drm_dev_register(drm_dev, 0);
> > > > +	if (ret)
> > > > +		goto err_helper;
> > > > +
> > > > +	drm_fbdev_generic_setup(drm_dev, 32);
> > > > +
> > > > +	return 0;
> > > > +
> > > > +err_helper:
> > > > +	drm_kms_helper_poll_fini(drm_dev);
> > > > +err_bind:
> > > > +	component_unbind_all(drm_dev->dev, drm_dev);
> > > > +err_mode:
> > > > +	drm_mode_config_cleanup(drm_dev);
> > > > +	if (priv->domain)
> > > > +		iommu_domain_free(priv->domain);
> > > > +err_put_dev:
> > > > +	drm_dev->dev_private = NULL;
> > > > +	dev_set_drvdata(dev, NULL);
> > > > +	drm_dev_put(drm_dev);
> > > > +	return ret;
> > > > +}
> > > > +
> > > > +static void vs_drm_unbind(struct device *dev)
> > > > +{
> > > > +	struct drm_device *drm_dev = dev_get_drvdata(dev);
> > > > +	struct vs_drm_private *priv = drm_dev->dev_private;
> > > > +
> > > > +	drm_dev_unregister(drm_dev);
> > > > +
> > > > +	drm_kms_helper_poll_fini(drm_dev);
> > > > +
> > > > +	component_unbind_all(drm_dev->dev, drm_dev);
> > > > +
> > > > +	drm_mode_config_cleanup(drm_dev);
> > > > +
> > > > +	if (priv->domain) {
> > > > +		iommu_domain_free(priv->domain);
> > > > +		priv->domain = NULL;
> > > > +	}
> > > > +
> > > > +	drm_dev->dev_private = NULL;
> > > > +	dev_set_drvdata(dev, NULL);
> > > > +	drm_dev_put(drm_dev);
> > > 
> > > You rather want to convert the individual steps of this cleanup to
> > > managed functions (drmm_ and devm_) to automate the cleanup when as part
> > > of drm_dev_put().
> > > 
> > > > +}
> > > > +
> > > > +static const struct component_master_ops vs_drm_ops = {
> > > > +	.bind = vs_drm_bind,
> > > > +	.unbind = vs_drm_unbind,
> > > > +};
> > > > +
> > > > +static struct platform_driver *drm_sub_drivers[] = {
> > > > +};
> > > > +
> > > > +#define NUM_DRM_DRIVERS \
> > > > +	(sizeof(drm_sub_drivers) / sizeof(struct platform_driver *))
> > > 
> > > Does this really work? sizeof(drm_sub_drivers) isn't know at compile
> > > time. It is always assumed to be 0 AFAICT. Or do you fill this array in
> > > later patches?
> > > 
> > > 
> > > > +
> > > > +static int compare_dev(struct device *dev, void *data)
> > > > +{
> > > > +	return dev == (struct device *)data;
> > > > +}
> > > > +
> > > > +static struct component_match *vs_drm_match_add(struct device *dev)
> > > > +{
> > > > +	struct component_match *match = NULL;
> > > > +	int i;
> > > > +
> > > > +	for (i = 0; i < NUM_DRM_DRIVERS; ++i) {
> > > > +		struct platform_driver *drv = drm_sub_drivers[i];
> > > > +		struct device *p = NULL, *d;
> > > > +
> > > > +		while ((d = platform_find_device_by_driver(p, &drv->driver))) {
> > > > +			put_device(p);
> > > > +
> > > > +			component_match_add(dev, &match, compare_dev, d);
> > > > +			p = d;
> > > > +		}
> > > > +		put_device(p);
> > > > +	}
> > > > +
> > > > +	return match ?: ERR_PTR(-ENODEV);
> > > > +}
> > > > +
> > > > +static int vs_drm_platform_probe(struct platform_device *pdev)
> > > > +{
> > > > +	struct device *dev = &pdev->dev;
> > > > +	struct component_match *match;
> > > > +
> > > > +	match = vs_drm_match_add(dev);
> > > > +	if (IS_ERR(match))
> > > > +		return PTR_ERR(match);
> > > > +
> > > > +	return component_master_add_with_match(dev, &vs_drm_ops, match);
> > > > +}
> > > > +
> > > > +static int vs_drm_platform_remove(struct platform_device *pdev)
> > > > +{
> > > > +	component_master_del(&pdev->dev, &vs_drm_ops);
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +#ifdef CONFIG_PM_SLEEP
> > > > +static int vs_drm_suspend(struct device *dev)
> > > > +{
> > > > +	struct drm_device *drm = dev_get_drvdata(dev);
> > > > +
> > > > +	return drm_mode_config_helper_suspend(drm);
> > > > +}
> > > > +
> > > > +static int vs_drm_resume(struct device *dev)
> > > > +{
> > > > +	struct drm_device *drm = dev_get_drvdata(dev);
> > > > +
> > > > +	return drm_mode_config_helper_resume(drm);
> > > > +}
> > > > +#endif
> > > > +
> > > > +static SIMPLE_DEV_PM_OPS(vs_drm_pm_ops, vs_drm_suspend, vs_drm_resume);
> > > > +
> > > > +static const struct of_device_id vs_drm_dt_ids[] = {
> > > > +	{ .compatible = "verisilicon,display-subsystem", },
> > > > +};
> > > > +
> > > > +MODULE_DEVICE_TABLE(of, vs_drm_dt_ids);
> > > > +
> > > > +static struct platform_driver vs_drm_platform_driver = {
> > > > +	.probe = vs_drm_platform_probe,
> > > > +	.remove = vs_drm_platform_remove,
> > > > +
> > > > +	.driver = {
> > > > +		.name = DRV_NAME,
> > > > +		.of_match_table = vs_drm_dt_ids,
> > > > +		.pm = &vs_drm_pm_ops,
> > > > +	},
> > > > +};
> > > > +
> > > > +static int __init vs_drm_init(void)
> > > > +{
> > > > +	int ret;
> > > > +
> > > > +	ret = platform_register_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > > +	ret = platform_driver_register(&vs_drm_platform_driver);
> > > > +	if (ret)
> > > > +		platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
> > > > +
> > > > +	return ret;
> > > > +}
> > > > +
> > > > +static void __exit vs_drm_fini(void)
> > > > +{
> > > > +	platform_driver_unregister(&vs_drm_platform_driver);
> > > > +	platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS);
> > > > +}
> > > > +
> > > > +module_init(vs_drm_init);
> > > > +module_exit(vs_drm_fini);
> > > > +
> > > > +MODULE_DESCRIPTION("VeriSilicon DRM Driver");
> > > > +MODULE_LICENSE("GPL");
> > > > diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h
> > > > new file mode 100644
> > > > index 000000000000..0382b44e3bf0
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/verisilicon/vs_drv.h
> > > > @@ -0,0 +1,48 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > > +/*
> > > > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> > > > + */
> > > > +
> > > > +#ifndef __VS_DRV_H__
> > > > +#define __VS_DRV_H__
> > > > +
> > > > +#include <linux/module.h>
> > > > +#include <linux/platform_device.h>
> > > > +#include <linux/version.h>
> > > > +#include <drm/drm_drv.h>
> > > > +#include <drm/drm_gem.h>
> > > > +
> > > > +/*
> > > > + *
> > > > + * @dma_dev: device for DMA API.
> > > > + *	- use the first attached device if support iommu
> > > > +	else use drm device (only contiguous buffer support)
> > > > + * @domain: iommu domain for DRM.
> > > > + *	- all DC IOMMU share same domain to reduce mapping
> > > > + * @pitch_alignment: buffer pitch alignment required by sub-devices.
> > > > + *
> > > > + */
> > > > +struct vs_drm_private {
> > > > +	struct device *dma_dev;
> > > > +	struct iommu_domain *domain;
> > > > +	unsigned int pitch_alignment;
> > > > +};
> > > 
> > > As mentioned, this struct needs to embed struct drm_device.
> > > 
> > > > +
> > > > +void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
> > > > +				   unsigned int alignment);
> > > > +
> > > > +static inline struct device *to_dma_dev(struct drm_device *dev)
> > > > +{
> > > > +	struct vs_drm_private *priv = dev->dev_private;
> > > > +
> > > > +	return priv->dma_dev;
> > > 
> > > And this needs to be an upcast via container_of().
> > > 
> > > > +}
> > > > +
> > > > +static inline bool is_iommu_enabled(struct drm_device *dev)
> > > > +{
> > > > +	struct vs_drm_private *priv = dev->dev_private;
> > > > +
> > > > +	return priv->domain ? true : false;
> > > > +}
> > > > +
> > > > +#endif /* __VS_DRV_H__ */
> > > > diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
> > > > index de703c6be969..af4fb50f9207 100644
> > > > --- a/include/uapi/drm/drm_fourcc.h
> > > > +++ b/include/uapi/drm/drm_fourcc.h
> > > 
> > > The UAPI changes shouldn't be needed in this patch?
> > > 
> > > > @@ -419,6 +419,7 @@ extern "C" {
> > > >    #define DRM_FORMAT_MOD_VENDOR_ARM     0x08
> > > >    #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09
> > > >    #define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a
> > > > +#define DRM_FORMAT_MOD_VENDOR_VS      0x0b
> > > >    
> > > >    /* add more to the end as needed */
> > > >    
> > > > @@ -1519,6 +1520,88 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
> > > >    #define AMD_FMT_MOD_CLEAR(field) \
> > > >    	(~((__u64)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT))
> > > >    
> > > > +#define DRM_FORMAT_MOD_VS_TYPE_NORMAL        0x00
> > > > +#define DRM_FORMAT_MOD_VS_TYPE_COMPRESSED    0x01
> > > > +#define DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT  0x02
> > > > +#define DRM_FORMAT_MOD_VS_TYPE_MASK     ((__u64)0x3 << 54)
> > > > +
> > > > +#define fourcc_mod_vs_code(type, val) \
> > > > +	fourcc_mod_code(VS, ((((__u64)type) << 54) | (val)))
> > > > +
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_MODE_MASK    0x3F
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_XMAJOR   0x00
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_YMAJOR   0x01
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4     0x02
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4      0x03
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_4X8      0x04
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X4   0x06
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X4     0x07
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4     0x08
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X1  0x09
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X1  0x0A
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X4   0x0B
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X2  0x0C
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X2  0x0D
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X4  0x0E
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X1   0x0F
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X8     0x10
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X16     0x11
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_512X1  0x12
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X4   0x13
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X2   0x14
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X2   0x15
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X1   0x16
> > > > +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X1   0x17
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X4    0x18
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_256X4    0x19
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_512X4    0x1A
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X16    0x1B
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X16    0x1C
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X16    0x1D
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X8    0x1E
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4_S    0x1F
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_S   0x20
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_S   0x21
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_LSB 0x22
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_LSB 0x23
> > > > +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X8     0x24
> > > > +
> > > > +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_32      (0x01 << 6)
> > > > +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_64      (0x01 << 7)
> > > > +
> > > > +#define fourcc_mod_vs_dec_code(tile, align) \
> > > > +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_COMPRESSED, \
> > > > +				((tile) | (align)))
> > > > +
> > > > +#define DRM_FORMAT_MOD_VS_NORM_MODE_MASK        0x1F
> > > > +#define DRM_FORMAT_MOD_VS_LINEAR                0x00
> > > > +#define DRM_FORMAT_MOD_VS_TILED4x4              0x01
> > > > +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR    0x02
> > > > +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR    0x03
> > > > +#define DRM_FORMAT_MOD_VS_TILE_8X8              0x04
> > > > +#define DRM_FORMAT_MOD_VS_TILE_MODE1            0x05
> > > > +#define DRM_FORMAT_MOD_VS_TILE_MODE2            0x06
> > > > +#define DRM_FORMAT_MOD_VS_TILE_8X4              0x07
> > > > +#define DRM_FORMAT_MOD_VS_TILE_MODE4            0x08
> > > > +#define DRM_FORMAT_MOD_VS_TILE_MODE5            0x09
> > > > +#define DRM_FORMAT_MOD_VS_TILE_MODE6            0x0A
> > > > +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4    0x0B
> > > > +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8    0x0C
> > > > +#define DRM_FORMAT_MOD_VS_TILE_Y                0x0D
> > > > +#define DRM_FORMAT_MOD_VS_TILE_128X1            0x0F
> > > > +#define DRM_FORMAT_MOD_VS_TILE_256X1            0x10
> > > > +#define DRM_FORMAT_MOD_VS_TILE_32X1             0x11
> > > > +#define DRM_FORMAT_MOD_VS_TILE_64X1             0x12
> > > > +#define DRM_FORMAT_MOD_VS_TILE_MODE4X4          0x15
> > > > +
> > > > +#define fourcc_mod_vs_norm_code(tile) \
> > > > +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_NORMAL, \
> > > > +				(tile))
> > > > +
> > > > +#define fourcc_mod_vs_custom_code(tile) \
> > > > +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT, \
> > > > +				(tile))
> > > > +
> > > >    #if defined(__cplusplus)
> > > >    }
> > > >    #endif
> > > > diff --git a/include/uapi/drm/vs_drm.h b/include/uapi/drm/vs_drm.h
> > > > new file mode 100644
> > > > index 000000000000..96b7fc95d658
> > > > --- /dev/null
> > > > +++ b/include/uapi/drm/vs_drm.h
> > > 
> > > Another UAPI addition that appears to be unused. Please only add things
> > > that you're using.
> > > 
> > > Best regards
> > > Thomas
> > > 
> > > > @@ -0,0 +1,50 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
> > > > +/*
> > > > + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
> > > > + */
> > > > +
> > > > +#ifndef __VS_DRM_H__
> > > > +#define __VS_DRM_H__
> > > > +
> > > > +#include "drm.h"
> > > > +
> > > > +enum drm_vs_degamma_mode {
> > > > +	VS_DEGAMMA_DISABLE = 0,
> > > > +	VS_DEGAMMA_BT709 = 1,
> > > > +	VS_DEGAMMA_BT2020 = 2,
> > > > +};
> > > > +
> > > > +enum drm_vs_sync_dc_mode {
> > > > +	VS_SINGLE_DC = 0,
> > > > +	VS_MULTI_DC_PRIMARY = 1,
> > > > +	VS_MULTI_DC_SECONDARY = 2,
> > > > +};
> > > > +
> > > > +enum drm_vs_mmu_prefetch_mode {
> > > > +	VS_MMU_PREFETCH_DISABLE = 0,
> > > > +	VS_MMU_PREFETCH_ENABLE = 1,
> > > > +};
> > > > +
> > > > +struct drm_vs_watermark {
> > > > +	__u32 watermark;
> > > > +	__u8 qos_low;
> > > > +	__u8 qos_high;
> > > > +};
> > > > +
> > > > +struct drm_vs_color_mgmt {
> > > > +	__u32 colorkey;
> > > > +	__u32 colorkey_high;
> > > > +	__u32 clear_value;
> > > > +	bool  clear_enable;
> > > > +	bool  transparency;
> > > > +};
> > > > +
> > > > +struct drm_vs_roi {
> > > > +	bool enable;
> > > > +	__u16 roi_x;
> > > > +	__u16 roi_y;
> > > > +	__u16 roi_w;
> > > > +	__u16 roi_h;
> > > > +};
> > > > +
> > > > +#endif /* __VS_DRM_H__ */
> > > 
> > > -- 
> > > Thomas Zimmermann
> > > Graphics Driver Developer
> > > SUSE Software Solutions Germany GmbH
> > > Frankenstrasse 146, 90461 Nuernberg, Germany
> > > GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
> > > HRB 36809 (AG Nuernberg)
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Frankenstrasse 146, 90461 Nuernberg, Germany
> GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
> HRB 36809 (AG Nuernberg)


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

* Re: [PATCH 4/9] drm/verisilicon: Add gem driver for JH7110 SoC
  2023-06-19 13:18   ` Thomas Zimmermann
@ 2023-07-20 10:00     ` Keith Zhao
  0 siblings, 0 replies; 46+ messages in thread
From: Keith Zhao @ 2023-07-20 10:00 UTC (permalink / raw)
  To: Thomas Zimmermann, dri-devel, devicetree, linux-kernel,
	linux-riscv, linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Heiko Stuebner, Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu,
	Shengyang Chen, Changhuang Liang



On 2023/6/19 21:18, Thomas Zimmermann wrote:
> 
> 
> Am 02.06.23 um 09:40 schrieb Keith Zhao:
>> This patch implements gem related APIs for JH7100 SoC.
>>
>> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
>> ---
>>   drivers/gpu/drm/verisilicon/Makefile |   3 +-
>>   drivers/gpu/drm/verisilicon/vs_drv.c |   6 +
>>   drivers/gpu/drm/verisilicon/vs_gem.c | 372 +++++++++++++++++++++++++++
>>   drivers/gpu/drm/verisilicon/vs_gem.h |  72 ++++++
>>   4 files changed, 452 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_gem.c
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_gem.h
>>
>> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
>> index 64ce1b26546c..30360e370e47 100644
>> --- a/drivers/gpu/drm/verisilicon/Makefile
>> +++ b/drivers/gpu/drm/verisilicon/Makefile
>> @@ -1,6 +1,7 @@
>>   # SPDX-License-Identifier: GPL-2.0
>>   -vs_drm-objs := vs_drv.o
>> +vs_drm-objs := vs_drv.o \
>> +        vs_gem.o
>>     obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
>>   diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
>> index 24d333598477..e0a2fc43b55f 100644
>> --- a/drivers/gpu/drm/verisilicon/vs_drv.c
>> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
>> @@ -30,6 +30,7 @@
>>   #include <drm/drm_vblank.h>
>>     #include "vs_drv.h"
>> +#include "vs_gem.h"
>>     #define DRV_NAME    "starfive"
>>   #define DRV_DESC    "Starfive DRM driver"
>> @@ -47,6 +48,7 @@ static const struct file_operations fops = {
>>       .compat_ioctl    = drm_compat_ioctl,
>>       .poll            = drm_poll,
>>       .read            = drm_read,
>> +    .mmap            = vs_gem_mmap,
>>   };
>>     static struct drm_driver vs_drm_driver = {
>> @@ -54,6 +56,10 @@ static struct drm_driver vs_drm_driver = {
>>       .lastclose        = drm_fb_helper_lastclose,
>>       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
>>       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
>> +    .gem_prime_import    = vs_gem_prime_import,
>> +    .gem_prime_import_sg_table = vs_gem_prime_import_sg_table,
>> +    .gem_prime_mmap        = vs_gem_prime_mmap,
>> +    .dumb_create        = vs_gem_dumb_create,
>>       .fops            = &fops,
>>       .name            = DRV_NAME,
>>       .desc            = DRV_DESC,
>> diff --git a/drivers/gpu/drm/verisilicon/vs_gem.c b/drivers/gpu/drm/verisilicon/vs_gem.c
>> new file mode 100644
>> index 000000000000..3f963471c1ab
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_gem.c
>> @@ -0,0 +1,372 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#include <linux/dma-buf.h>
>> +#include <linux/of_reserved_mem.h>
>> +#include <drm/drm_gem_dma_helper.h>
>> +
>> +#include "vs_drv.h"
>> +#include "vs_gem.h"
>> +
>> +static const struct drm_gem_object_funcs vs_gem_default_funcs;
>> +
>> +static int vs_gem_alloc_buf(struct vs_gem_object *vs_obj)
>> +{
>> +    struct drm_device *dev = vs_obj->base.dev;
>> +    unsigned int nr_pages;
>> +    struct sg_table sgt;
>> +    int ret = -ENOMEM;
>> +
>> +    if (vs_obj->dma_addr) {
>> +        DRM_DEV_DEBUG_KMS(dev->dev, "already allocated.\n");
>> +        return 0;
>> +    }
>> +
>> +    vs_obj->dma_attrs = DMA_ATTR_WRITE_COMBINE | DMA_ATTR_FORCE_CONTIGUOUS
>> +               | DMA_ATTR_NO_KERNEL_MAPPING;
>> +
>> +    nr_pages = vs_obj->size >> PAGE_SHIFT;
>> +
>> +    vs_obj->pages = kvmalloc_array(nr_pages, sizeof(struct page *),
>> +                       GFP_KERNEL | __GFP_ZERO);
>> +    if (!vs_obj->pages) {
>> +        DRM_DEV_ERROR(dev->dev, "failed to allocate pages.\n");
>> +        return -ENOMEM;
>> +    }
>> +
>> +    vs_obj->cookie = dma_alloc_attrs(to_dma_dev(dev), vs_obj->size,
>> +                     &vs_obj->dma_addr, GFP_KERNEL,
>> +                     vs_obj->dma_attrs);
>> +
>> +    if (!vs_obj->cookie) {
>> +        DRM_DEV_ERROR(dev->dev, "failed to allocate buffer.\n");
>> +        goto err_free;
>> +    }
>> +
>> +    vs_obj->iova = vs_obj->dma_addr;
>> +
>> +    ret = dma_get_sgtable_attrs(to_dma_dev(dev), &sgt,
>> +                    vs_obj->cookie, vs_obj->dma_addr,
>> +                    vs_obj->size, vs_obj->dma_attrs);
>> +    if (ret < 0) {
>> +        DRM_DEV_ERROR(dev->dev, "failed to get sgtable.\n");
>> +        goto err_mem_free;
>> +    }
>> +
>> +    if (drm_prime_sg_to_page_array(&sgt, vs_obj->pages, nr_pages)) {
>> +        DRM_DEV_ERROR(dev->dev, "invalid sgtable.\n");
>> +        ret = -EINVAL;
>> +        goto err_sgt_free;
>> +    }
>> +
>> +    sg_free_table(&sgt);
>> +
>> +    return 0;
>> +
>> +err_sgt_free:
>> +    sg_free_table(&sgt);
>> +err_mem_free:
>> +        dma_free_attrs(to_dma_dev(dev), vs_obj->size, vs_obj->cookie,
>> +                   vs_obj->dma_addr, vs_obj->dma_attrs);
>> +err_free:
>> +    kvfree(vs_obj->pages);
>> +
>> +    return ret;
>> +}
>> +
>> +static void vs_gem_free_buf(struct vs_gem_object *vs_obj)
>> +{
>> +    struct drm_device *dev = vs_obj->base.dev;
>> +
>> +    if (!vs_obj->dma_addr) {
>> +        DRM_DEV_DEBUG_KMS(dev->dev, "dma_addr is invalid.\n");
>> +        return;
>> +    }
>> +
>> +    dma_free_attrs(to_dma_dev(dev), vs_obj->size, vs_obj->cookie,
>> +               (dma_addr_t)vs_obj->dma_addr,
>> +               vs_obj->dma_attrs);
>> +
>> +    kvfree(vs_obj->pages);
>> +}
>> +
>> +static void vs_gem_free_object(struct drm_gem_object *obj)
>> +{
>> +    struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
>> +
>> +    if (obj->import_attach)
>> +        drm_prime_gem_destroy(obj, vs_obj->sgt);
>> +    else
>> +        vs_gem_free_buf(vs_obj);
>> +
>> +    drm_gem_object_release(obj);
>> +
>> +    kfree(vs_obj);
>> +}
>> +
>> +static struct vs_gem_object *vs_gem_alloc_object(struct drm_device *dev,
>> +                         size_t size)
>> +{
>> +    struct vs_gem_object *vs_obj;
>> +    struct drm_gem_object *obj;
>> +    int ret;
>> +
>> +    vs_obj = kzalloc(sizeof(*vs_obj), GFP_KERNEL);
>> +    if (!vs_obj)
>> +        return ERR_PTR(-ENOMEM);
>> +
>> +    vs_obj->size = size;
>> +    obj = &vs_obj->base;
>> +
>> +    ret = drm_gem_object_init(dev, obj, size);
>> +    if (ret)
>> +        goto err_free;
>> +
>> +    vs_obj->base.funcs = &vs_gem_default_funcs;
>> +
>> +    ret = drm_gem_create_mmap_offset(obj);
>> +    if (ret) {
>> +        drm_gem_object_release(obj);
>> +        goto err_free;
>> +    }
>> +
>> +    return vs_obj;
>> +
>> +err_free:
>> +    kfree(vs_obj);
>> +    return ERR_PTR(ret);
>> +}
>> +
>> +struct vs_gem_object *vs_gem_create_object(struct drm_device *dev,
>> +                       size_t size)
>> +{
>> +    struct vs_gem_object *vs_obj;
>> +    int ret;
>> +
>> +    size = PAGE_ALIGN(size);
>> +
>> +    vs_obj = vs_gem_alloc_object(dev, size);
>> +    if (IS_ERR(vs_obj))
>> +        return vs_obj;
>> +
>> +    ret = vs_gem_alloc_buf(vs_obj);
>> +    if (ret) {
>> +        drm_gem_object_release(&vs_obj->base);
>> +        kfree(vs_obj);
>> +        return ERR_PTR(ret);
>> +    }
>> +
>> +    return vs_obj;
>> +}
>> +
>> +static struct vs_gem_object *vs_gem_create_with_handle(struct drm_device *dev,
>> +                               struct drm_file *file,
>> +                               size_t size,
>> +                               unsigned int *handle)
>> +{
>> +    struct vs_gem_object *vs_obj;
>> +    struct drm_gem_object *obj;
>> +    int ret;
>> +
>> +    vs_obj = vs_gem_create_object(dev, size);
>> +    if (IS_ERR(vs_obj))
>> +        return vs_obj;
>> +
>> +    obj = &vs_obj->base;
>> +
>> +    ret = drm_gem_handle_create(file, obj, handle);
>> +
>> +    drm_gem_object_put(obj);
>> +
>> +    if (ret)
>> +        return ERR_PTR(ret);
>> +
>> +    return vs_obj;
>> +}
>> +
>> +static int vs_gem_mmap_obj(struct drm_gem_object *obj,
>> +               struct vm_area_struct *vma)
>> +{
>> +    struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
>> +    struct drm_device *drm_dev = vs_obj->base.dev;
>> +    unsigned long vm_size;
>> +    int ret = 0;
>> +
>> +    vm_size = vma->vm_end - vma->vm_start;
>> +    if (vm_size > vs_obj->size)
>> +        return -EINVAL;
>> +
>> +    vma->vm_pgoff = 0;
>> +
>> +    /*
>> +     * We allocated a struct page table for starfive_obj, so clear
>> +     * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
>> +     */
>> +    vm_flags_mod(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP, VM_PFNMAP);
>> +
>> +    vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
>> +    vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
>> +
>> +    ret = dma_mmap_attrs(to_dma_dev(drm_dev), vma, vs_obj->cookie,
>> +                 vs_obj->dma_addr, vs_obj->size,
>> +                 vs_obj->dma_attrs);
>> +
>> +    if (ret)
>> +        drm_gem_vm_close(vma);
>> +
>> +    return ret;
>> +}
>> +
>> +struct sg_table *vs_gem_prime_get_sg_table(struct drm_gem_object *obj)
>> +{
>> +    struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
>> +
>> +    return drm_prime_pages_to_sg(obj->dev, vs_obj->pages,
>> +                     vs_obj->size >> PAGE_SHIFT);
>> +}
>> +
>> +int vs_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
>> +{
>> +    struct vs_gem_object *vs_obj = to_vs_gem_object(obj);
>> +
>> +    void *vaddr = vs_obj->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING ?
>> +               page_address(vs_obj->cookie) : vs_obj->cookie;
>> +
>> +    iosys_map_set_vaddr(map, vaddr);
>> +
>> +    return 0;
>> +}
>> +
>> +void vs_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
>> +{
>> +    /* Nothing to do */
>> +}
>> +
>> +static const struct vm_operations_struct vs_vm_ops = {
>> +    .open  = drm_gem_vm_open,
>> +    .close = drm_gem_vm_close,
>> +};
>> +
>> +static const struct drm_gem_object_funcs vs_gem_default_funcs = {
>> +    .free = vs_gem_free_object,
>> +    .get_sg_table = vs_gem_prime_get_sg_table,
>> +    .vmap = vs_gem_prime_vmap,
>> +    .vunmap = vs_gem_prime_vunmap,
>> +    .vm_ops = &vs_vm_ops,
>> +};
>> +
>> +int vs_gem_dumb_create(struct drm_file *file,
>> +               struct drm_device *dev,
>> +               struct drm_mode_create_dumb *args)
>> +{
>> +    struct vs_drm_private *priv = dev->dev_private;
>> +    struct vs_gem_object *vs_obj;
>> +    unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
>> +
>> +    if (args->bpp % 10)
>> +        args->pitch = ALIGN(pitch, priv->pitch_alignment);
>> +    else
>> +        /* for costum 10bit format with no bit gaps */
>> +        args->pitch = pitch;
>> +    args->size = PAGE_ALIGN(args->pitch * args->height);
>> +    vs_obj = vs_gem_create_with_handle(dev, file, args->size,
>> +                       &args->handle);
>> +    return PTR_ERR_OR_ZERO(vs_obj);
>> +}
>> +
>> +struct drm_gem_object *vs_gem_prime_import(struct drm_device *dev,
>> +                       struct dma_buf *dma_buf)
>> +{
>> +    return drm_gem_prime_import_dev(dev, dma_buf, to_dma_dev(dev));
>> +}
>> +
>> +struct drm_gem_object *
>> +vs_gem_prime_import_sg_table(struct drm_device *dev,
>> +                 struct dma_buf_attachment *attach,
>> +                 struct sg_table *sgt)
>> +{
>> +    struct vs_gem_object *vs_obj;
>> +    int npages;
>> +    int ret;
>> +    struct scatterlist *s;
>> +    u32 i;
>> +    dma_addr_t expected;
>> +    size_t size = attach->dmabuf->size;
>> +
>> +    size = PAGE_ALIGN(size);
>> +
>> +    vs_obj = vs_gem_alloc_object(dev, size);
>> +    if (IS_ERR(vs_obj))
>> +        return ERR_CAST(vs_obj);
>> +
>> +    expected = sg_dma_address(sgt->sgl);
>> +    for_each_sg(sgt->sgl, s, sgt->nents, i) {
>> +        if (sg_dma_address(s) != expected) {
>> +            DRM_ERROR("sg_table is not contiguous");
>> +            ret = -EINVAL;
>> +            goto err;
>> +        }
>> +        if (sg_dma_len(s) & (PAGE_SIZE - 1)) {
>> +            ret = -EINVAL;
>> +            goto err;
>> +        }
>> +        if (i == 0)
>> +            vs_obj->iova = sg_dma_address(s);
>> +        expected = sg_dma_address(s) + sg_dma_len(s);
>> +    }
>> +
>> +    vs_obj->dma_addr = sg_dma_address(sgt->sgl);
>> +
>> +    npages = vs_obj->size >> PAGE_SHIFT;
>> +    vs_obj->pages = kvmalloc_array(npages, sizeof(struct page *),
>> +                       GFP_KERNEL);
>> +    if (!vs_obj->pages) {
>> +        ret = -ENOMEM;
>> +        goto err;
>> +    }
>> +
>> +    ret = drm_prime_sg_to_page_array(sgt, vs_obj->pages, npages);
>> +    if (ret)
>> +        goto err_free_page;
>> +
>> +    vs_obj->sgt = sgt;
>> +
>> +    return &vs_obj->base;
>> +
>> +err_free_page:
>> +    kvfree(vs_obj->pages);
>> +err:
>> +    vs_gem_free_object(&vs_obj->base);
>> +
>> +    return ERR_PTR(ret);
>> +}
>> +
>> +int vs_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
>> +{
>> +    int ret = 0;
>> +
>> +    ret = drm_gem_mmap_obj(obj, obj->size, vma);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    return vs_gem_mmap_obj(obj, vma);
>> +}
>> +
>> +int vs_gem_mmap(struct file *filp, struct vm_area_struct *vma)
> 
> This function needs to go away.
> 
>> +{
>> +    struct drm_gem_object *obj;
>> +    int ret;
>> +
>> +    ret = drm_gem_mmap(filp, vma);
> 
> Set drm_gem_mmap() as your fops.mmap callback.
> 
>> +    if (ret)
>> +        return ret;
>> +
>> +    obj = vma->vm_private_data;
>> +
>> +    if (obj->import_attach)
>> +        return dma_buf_mmap(obj->dma_buf, vma, 0);
>> +
>> +    return vs_gem_mmap_obj(obj, vma);
> 
> Both, dma_buf and regular objects, should be handled in struct drm_gem_object_funcs.mmap. drm_gem_mmap() will call it for you. vs_gem_mmap_obj() can then be removed.
> 
> you can find example code in drm_gem_shmem_helper.c and drm_gem_dma_helper.c on how to write GEM object's mmap function.
> 

hi Thomas : 
yes , it is a good idea , 
It can largely reuse drm helper interfaces rather than defining its own set of interfaces.

I added 
.mmap = drm_gem_dma_object_mmap,
in my own defineed drm_gem_object_funcs

also use "struct drm_gem_dma_object base;" to replace  "struct drm_gem_object base;"
this makes my code more consice!
> 
>> +}
>> diff --git a/drivers/gpu/drm/verisilicon/vs_gem.h b/drivers/gpu/drm/verisilicon/vs_gem.h
>> new file mode 100644
>> index 000000000000..3a6d7452cb06
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_gem.h
>> @@ -0,0 +1,72 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#ifndef __VS_GEM_H__
>> +#define __VS_GEM_H__
>> +
>> +#include <linux/dma-buf.h>
>> +
>> +#include <drm/drm_gem.h>
>> +#include <drm/drm_prime.h>
>> +
>> +#include "vs_drv.h"
>> +/*
>> + *
>> + * @base: drm gem object.
>> + * @size: size requested from user
>> + * @cookie: cookie returned by dma_alloc_attrs
>> + *    - not kernel virtual address with DMA_ATTR_NO_KERNEL_MAPPING
>> + * @dma_addr: bus address(accessed by dma) to allocated memory region.
>> + *    - this address could be physical address without IOMMU and
>> + *    device address with IOMMU.
>> + * @dma_attrs: attribute for DMA API
>> + * @get_pages: flag for manually applying for non-contiguous memory.
>> + * @pages: Array of backing pages.
>> + * @sgt: Imported sg_table.
>> + *
>> + */
>> +struct vs_gem_object {
>> +    struct drm_gem_object    base;
>> +    size_t            size;
>> +    void            *cookie;
>> +    dma_addr_t        dma_addr;
>> +    u32                iova;
>> +    unsigned long    dma_attrs;
>> +    bool            get_pages;
>> +    struct page        **pages;
>> +    struct sg_table *sgt;
>> +};
>> +
>> +static inline
>> +struct vs_gem_object *to_vs_gem_object(struct drm_gem_object *obj)
>> +{
>> +    return container_of(obj, struct vs_gem_object, base);
>> +}
>> +
>> +struct vs_gem_object *vs_gem_create_object(struct drm_device *dev,
>> +                       size_t size);
>> +
>> +int vs_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map);
>> +void vs_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map);
> 
> 
> 
>> +
>> +int vs_gem_prime_mmap(struct drm_gem_object *obj,
>> +              struct vm_area_struct *vma);
>> +
>> +int vs_gem_dumb_create(struct drm_file *file_priv,
>> +               struct drm_device *drm,
>> +               struct drm_mode_create_dumb *args);
>> +
>> +int vs_gem_mmap(struct file *filp, struct vm_area_struct *vma);
>> +
>> +struct sg_table *vs_gem_prime_get_sg_table(struct drm_gem_object *obj);
>> +
>> +struct drm_gem_object *vs_gem_prime_import(struct drm_device *dev,
>> +                       struct dma_buf *dma_buf);
>> +struct drm_gem_object *
>> +vs_gem_prime_import_sg_table(struct drm_device *dev,
>> +                 struct dma_buf_attachment *attach,
>> +                 struct sg_table *sgt);
>> +
>> +#endif /* __VS_GEM_H__ */
> 

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

* Re: [PATCH 5/9] drm/verisilicon: Add mode config funcs
  2023-06-21 11:04   ` Thomas Zimmermann
@ 2023-07-21  9:06     ` Keith Zhao
  0 siblings, 0 replies; 46+ messages in thread
From: Keith Zhao @ 2023-07-21  9:06 UTC (permalink / raw)
  To: Thomas Zimmermann, dri-devel, devicetree, linux-kernel,
	linux-riscv, linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Heiko Stuebner, Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu,
	Shengyang Chen, Changhuang Liang



On 2023/6/21 19:04, Thomas Zimmermann wrote:
> Hi Keith
> 
> Am 02.06.23 um 09:40 schrieb Keith Zhao:
>> Add mode setting functions for JH7110 SoC.
>>
>> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
>> ---
>>   drivers/gpu/drm/verisilicon/Makefile |   1 +
>>   drivers/gpu/drm/verisilicon/vs_drv.c |   3 +
> 
>>   drivers/gpu/drm/verisilicon/vs_fb.c  | 181 +++++++++++++++++++++++++++
>>   drivers/gpu/drm/verisilicon/vs_fb.h  |  15 +++
> 
> I'd call these files vs_modeset.{c,h} to be consistent with the rest of the drivers.
> 
>>   4 files changed, 200 insertions(+)
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_fb.c
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_fb.h
>>
>> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
>> index 30360e370e47..38254dc5d98d 100644
>> --- a/drivers/gpu/drm/verisilicon/Makefile
>> +++ b/drivers/gpu/drm/verisilicon/Makefile
>> @@ -1,6 +1,7 @@
>>   # SPDX-License-Identifier: GPL-2.0
>>     vs_drm-objs := vs_drv.o \
>> +        vs_fb.o \
>>           vs_gem.o
>>     obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
>> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
>> index e0a2fc43b55f..d84aacd751bc 100644
>> --- a/drivers/gpu/drm/verisilicon/vs_drv.c
>> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
>> @@ -30,6 +30,7 @@
>>   #include <drm/drm_vblank.h>
>>     #include "vs_drv.h"
>> +#include "vs_fb.h"
>>   #include "vs_gem.h"
>>     #define DRV_NAME    "starfive"
>> @@ -118,6 +119,8 @@ static int vs_drm_bind(struct device *dev)
>>       if (ret)
>>           goto err_mode;
>>   +    vs_mode_config_init(drm_dev);
>> +
>>       ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
>>       if (ret)
>>           goto err_bind;
>> diff --git a/drivers/gpu/drm/verisilicon/vs_fb.c b/drivers/gpu/drm/verisilicon/vs_fb.c
>> new file mode 100644
>> index 000000000000..3e85f7365084
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_fb.c
>> @@ -0,0 +1,181 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/version.h>
>> +
>> +#include <drm/drm_damage_helper.h>
>> +#include <drm/drm_fb_helper.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_crtc_helper.h>
>> +#include <drm/drm_fourcc.h>
>> +#include <drm/drm_framebuffer.h>
>> +#include <drm/drm_gem.h>
>> +#include <drm/drm_gem_framebuffer_helper.h>
>> +
>> +#include "vs_fb.h"
>> +#include "vs_gem.h"
>> +
>> +#define fourcc_mod_vs_get_type(val) \
>> +    (((val) & DRM_FORMAT_MOD_VS_TYPE_MASK) >> 54)
>> +
>> +static struct drm_framebuffer_funcs vs_fb_funcs = {
>> +    .create_handle    = drm_gem_fb_create_handle,
>> +    .destroy    = drm_gem_fb_destroy,
>> +    .dirty        = drm_atomic_helper_dirtyfb,
>> +};
>> +
>> +static struct drm_framebuffer *
>> +vs_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd,
>> +        struct vs_gem_object **obj, unsigned int num_planes)
>> +{
>> +    struct drm_framebuffer *fb;
>> +    int ret, i;
>> +
>> +    fb = kzalloc(sizeof(*fb), GFP_KERNEL);
>> +    if (!fb)
>> +        return ERR_PTR(-ENOMEM);
>> +
>> +    drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
>> +
>> +    for (i = 0; i < num_planes; i++)
>> +        fb->obj[i] = &obj[i]->base;
>> +
>> +    ret = drm_framebuffer_init(dev, fb, &vs_fb_funcs);
>> +    if (ret) {
>> +        dev_err(dev->dev, "Failed to initialize framebuffer: %d\n",
>> +            ret);
>> +        kfree(fb);
>> +        return ERR_PTR(ret);
>> +    }
>> +
>> +    return fb;
>> +}
>> +
>> +static struct drm_framebuffer *vs_fb_create(struct drm_device *dev,
>> +                        struct drm_file *file_priv,
>> +                        const struct drm_mode_fb_cmd2 *mode_cmd)
>> +{
>> +    struct drm_framebuffer *fb;
>> +    const struct drm_format_info *info;
>> +    struct vs_gem_object *objs[MAX_NUM_PLANES];
>> +    struct drm_gem_object *obj;
>> +    unsigned int height, size;
>> +    unsigned char i, num_planes;
>> +    int ret = 0;
>> +
>> +    info = drm_get_format_info(dev, mode_cmd);
>> +    if (!info)
>> +        return ERR_PTR(-EINVAL);
>> +
>> +    num_planes = info->num_planes;
>> +    if (num_planes > MAX_NUM_PLANES)
>> +        return ERR_PTR(-EINVAL);
>> +
>> +    for (i = 0; i < num_planes; i++) {
>> +        obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
>> +        if (!obj) {
>> +            dev_err(dev->dev, "Failed to lookup GEM object.\n");
>> +            ret = -ENXIO;
>> +            goto err;
>> +        }
>> +
>> +        height = drm_format_info_plane_height(info,
>> +                              mode_cmd->height, i);
>> +
>> +        size = height * mode_cmd->pitches[i] + mode_cmd->offsets[i];
>> +
>> +        if (obj->size < size) {
>> +            drm_gem_object_put(obj);
>> +
>> +            ret = -EINVAL;
>> +            goto err;
>> +        }
>> +
>> +        objs[i] = to_vs_gem_object(obj);
>> +    }
>> +
>> +    fb = vs_fb_alloc(dev, mode_cmd, objs, i);
>> +    if (IS_ERR(fb)) {
>> +        ret = PTR_ERR(fb);
>> +        goto err;
>> +    }
>> +
>> +    return fb;
>> +
>> +err:
>> +    for (; i > 0; i--)
>> +        drm_gem_object_put(&objs[i - 1]->base);
>> +
>> +    return ERR_PTR(ret);
>> +}
>> +
>> +struct vs_gem_object *vs_fb_get_gem_obj(struct drm_framebuffer *fb,
>> +                    unsigned char plane)
>> +{
>> +    if (plane > MAX_NUM_PLANES)
>> +        return NULL;
>> +
>> +    return to_vs_gem_object(fb->obj[plane]);
>> +}
>> +
>> +static const struct drm_format_info vs_formats[] = {
>> +    {.format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .char_per_block = { 20, 40, 0 },
>> +     .block_w = { 4, 4, 0 }, .block_h = { 4, 4, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true},
>> +    {.format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .char_per_block = { 20, 20, 20 },
>> +     .block_w = { 4, 4, 4 }, .block_h = { 4, 4, 4 }, .hsub = 1, .vsub = 1, .is_yuv = true},
>> +};
>> +
>> +static const struct drm_format_info *
>> +vs_lookup_format_info(const struct drm_format_info formats[],
>> +              int num_formats, u32 format)
>> +{
>> +    int i;
>> +
>> +    for (i = 0; i < num_formats; i++) {
>> +        if (formats[i].format == format)
>> +            return &formats[i];
>> +    }
>> +
>> +    return NULL;
>> +}
>> +
>> +static const struct drm_format_info *
>> +vs_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
>> +{
>> +    if (fourcc_mod_vs_get_type(cmd->modifier[0]) ==
>> +        DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT)
>> +        return vs_lookup_format_info(vs_formats, ARRAY_SIZE(vs_formats),
>> +                                     cmd->pixel_format);
>> +    else
>> +        return NULL;
>> +}
>> +
>> +static const struct drm_mode_config_funcs vs_mode_config_funcs = {
>> +    .fb_create             = vs_fb_create,
> 
> Maybe I'm missing something here, but it looks like you can call
> drm_gem_fb_create_with_funcs() to create the framebuffer.
> 
That's a brilliant suggestion!!! 


>> +    .get_format_info     = vs_get_format_info,
>> +    .output_poll_changed = drm_fb_helper_output_poll_changed,
>> +    .atomic_check         = drm_atomic_helper_check,
>> +    .atomic_commit         = drm_atomic_helper_commit,
>> +};
>> +
>> +static struct drm_mode_config_helper_funcs vs_mode_config_helpers = {
>> +    .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
>> +};
>> +
>> +void vs_mode_config_init(struct drm_device *dev)
>> +{
> 
> If possible, move the call to drm_mode_config_init() into this function.
> 
move drm_mode_config_init() into vs_mode_config_init. 
and vs_mode_config_init must be called ahead component_bind_all

like this:
static int vs_drm_bind(struct device *dev)
{
	......

	vs_mode_config_init(drm_dev);

	/* Now try and bind all our sub-components */
	ret = component_bind_all(dev, drm_dev);
	if (ret)
		goto err_mode;
	......
}

>> +    dev->mode_config.fb_modifiers_not_supported = false;
>> +
>> +    if (dev->mode_config.max_width == 0 ||
>> +        dev->mode_config.max_height == 0) {
>> +        dev->mode_config.min_width  = 0;
>> +        dev->mode_config.min_height = 0;
>> +        dev->mode_config.max_width  = 4096;
>> +        dev->mode_config.max_height = 4096;
>> +    }
>> +    dev->mode_config.funcs = &vs_mode_config_funcs;
>> +    dev->mode_config.helper_private = &vs_mode_config_helpers;
>> +}
>> diff --git a/drivers/gpu/drm/verisilicon/vs_fb.h b/drivers/gpu/drm/verisilicon/vs_fb.h
>> new file mode 100644
>> index 000000000000..78dda8e42894
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_fb.h
>> @@ -0,0 +1,15 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#ifndef __VS_FB_H__
>> +#define __VS_FB_H__
>> +
>> +#define MAX_NUM_PLANES        3 /* colour format plane */
> 
> There's DRM_FORMAT_MAX_PLANES already. Please don't introduce a constant with the same purpose.
> 
ok good idea! 
> Best regards
> Thomas
> 
>> +
>> +struct vs_gem_object *vs_fb_get_gem_obj(struct drm_framebuffer *fb,
>> +                    unsigned char plane);
>> +
>> +void vs_mode_config_init(struct drm_device *dev);
>> +#endif /* __VS_FB_H__ */
> 

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

* Re: [PATCH 6/9] drm/verisilicon: Add drm crtc funcs
  2023-06-30 11:55   ` Thomas Zimmermann
@ 2023-07-21 11:57     ` Keith Zhao
  2023-07-21 12:32       ` Sam Ravnborg
  0 siblings, 1 reply; 46+ messages in thread
From: Keith Zhao @ 2023-07-21 11:57 UTC (permalink / raw)
  To: Thomas Zimmermann, dri-devel, devicetree, linux-kernel,
	linux-riscv, linux-media, linaro-mm-sig
  Cc: David Airlie, Daniel Vetter, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Emil Renner Berthing, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Maarten Lankhorst, Maxime Ripard,
	Philipp Zabel, Sumit Semwal, christian.koenig, Bjorn Andersson,
	Heiko Stuebner, Shawn Guo, Jagan Teki, Chris Morgan, Jack Zhu,
	Shengyang Chen, Changhuang Liang



On 2023/6/30 19:55, Thomas Zimmermann wrote:
> Hi
> 
> Am 02.06.23 um 09:40 schrieb Keith Zhao:
>> Add crtc driver which implements crtc related operation functions.
>>
>> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
>> ---
>>   drivers/gpu/drm/verisilicon/Makefile  |   1 +
>>   drivers/gpu/drm/verisilicon/vs_crtc.c | 388 ++++++++++++++++++++++++++
>>   drivers/gpu/drm/verisilicon/vs_crtc.h |  74 +++++
>>   drivers/gpu/drm/verisilicon/vs_type.h |  72 +++++
>>   4 files changed, 535 insertions(+)
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
>>
>> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
>> index 38254dc5d98d..bae5fbab9bbb 100644
>> --- a/drivers/gpu/drm/verisilicon/Makefile
>> +++ b/drivers/gpu/drm/verisilicon/Makefile
>> @@ -1,6 +1,7 @@
>>   # SPDX-License-Identifier: GPL-2.0
>>     vs_drm-objs := vs_drv.o \
>> +        vs_crtc.o \
>>           vs_fb.o \
>>           vs_gem.o
>>   diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c
>> new file mode 100644
>> index 000000000000..a9e742d7bd1a
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.c
>> @@ -0,0 +1,388 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + *
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/debugfs.h>
>> +#include <linux/media-bus-format.h>
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_atomic.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_gem_atomic_helper.h>
>> +#include <drm/drm_vblank.h>
>> +#include <drm/vs_drm.h>
>> +
>> +#include "vs_crtc.h"
>> +
>> +void vs_crtc_destroy(struct drm_crtc *crtc)
>> +{
>> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +
>> +    drm_crtc_cleanup(crtc);
>> +    kfree(vs_crtc);
>> +}
>> +
>> +static void vs_crtc_reset(struct drm_crtc *crtc)
>> +{
>> +    struct vs_crtc_state *state;
>> +
>> +    if (crtc->state) {
>> +        __drm_atomic_helper_crtc_destroy_state(crtc->state);
>> +
>> +        state = to_vs_crtc_state(crtc->state);
>> +        kfree(state);
>> +        crtc->state = NULL;
>> +    }
>> +
>> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
>> +    if (!state)
>> +        return;
>> +
>> +    __drm_atomic_helper_crtc_reset(crtc, &state->base);
>> +
>> +    state->sync_mode = VS_SINGLE_DC;
>> +    state->output_fmt = MEDIA_BUS_FMT_RBG888_1X24;
>> +    state->encoder_type = DRM_MODE_ENCODER_NONE;
>> +}
>> +
>> +static struct drm_crtc_state *
>> +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
>> +{
>> +    struct vs_crtc_state *ori_state;
>> +    struct vs_crtc_state *state;
>> +
>> +    if (WARN_ON(!crtc->state))
>> +        return NULL;
> 
> I'd leave this check out. IIRC, crtc->state not supposed to be NULL here. Rather let it crash.
> 
>> +
>> +    ori_state = to_vs_crtc_state(crtc->state);
>> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
>> +    if (!state)
>> +        return NULL;
>> +
>> +    __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
>> +
>> +    state->sync_mode = ori_state->sync_mode;
>> +    state->output_fmt = ori_state->output_fmt;
>> +    state->encoder_type = ori_state->encoder_type;
>> +    state->bg_color = ori_state->bg_color;
>> +    state->bpp = ori_state->bpp;
>> +    state->sync_enable = ori_state->sync_enable;
>> +    state->dither_enable = ori_state->dither_enable;
>> +    state->underflow = ori_state->underflow;
>> +
>> +    return &state->base;
>> +}
>> +
>> +static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
>> +                     struct drm_crtc_state *state)
>> +{
>> +    __drm_atomic_helper_crtc_destroy_state(state);
>> +    kfree(to_vs_crtc_state(state));
>> +}
>> +
>> +static int vs_crtc_atomic_set_property(struct drm_crtc *crtc,
>> +                       struct drm_crtc_state *state,
>> +                       struct drm_property *property,
>> +                       uint64_t val)
>> +{
>> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +    struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(state);
>> +
>> +    if (property == vs_crtc->sync_mode)
>> +        vs_crtc_state->sync_mode = val;
>> +    else if (property == vs_crtc->mmu_prefetch)
>> +        vs_crtc_state->mmu_prefetch = val;
>> +    else if (property == vs_crtc->bg_color)
>> +        vs_crtc_state->bg_color = val;
>> +    else if (property == vs_crtc->panel_sync)
>> +        vs_crtc_state->sync_enable = val;
>> +    else if (property == vs_crtc->dither)
>> +        vs_crtc_state->dither_enable = val;
>> +    else
>> +        return -EINVAL;
>> +
>> +    return 0;
>> +}
>> +
>> +static int vs_crtc_atomic_get_property(struct drm_crtc *crtc,
>> +                       const struct drm_crtc_state *state,
>> +                       struct drm_property *property,
>> +                       uint64_t *val)
>> +{
>> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +    const struct vs_crtc_state *vs_crtc_state =
>> +        container_of(state, const struct vs_crtc_state, base);
>> +
>> +    if (property == vs_crtc->sync_mode)
>> +        *val = vs_crtc_state->sync_mode;
>> +    else if (property == vs_crtc->mmu_prefetch)
>> +        *val = vs_crtc_state->mmu_prefetch;
>> +    else if (property == vs_crtc->bg_color)
>> +        *val = vs_crtc_state->bg_color;
>> +    else if (property == vs_crtc->panel_sync)
>> +        *val = vs_crtc_state->sync_enable;
>> +    else if (property == vs_crtc->dither)
>> +        *val = vs_crtc_state->dither_enable;
>> +    else
>> +        return -EINVAL;
>> +
>> +    return 0;
>> +}
>> +
>> +static int vs_crtc_late_register(struct drm_crtc *crtc)
>> +{
>> +    return 0;
>> +}
>> +
>> +static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
>> +{
>> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +
>> +    vs_crtc->funcs->enable_vblank(vs_crtc->dev, true);
>> +
>> +    return 0;
>> +}
>> +
>> +static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
>> +{
>> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +
>> +    vs_crtc->funcs->enable_vblank(vs_crtc->dev, false);
>> +}
>> +
>> +static const struct drm_crtc_funcs vs_crtc_funcs = {
>> +    .set_config        = drm_atomic_helper_set_config,
>> +    .destroy        = vs_crtc_destroy,
>> +    .page_flip        = drm_atomic_helper_page_flip,
>> +    .reset            = vs_crtc_reset,
>> +    .atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
>> +    .atomic_destroy_state    = vs_crtc_atomic_destroy_state,
>> +    .atomic_set_property    = vs_crtc_atomic_set_property,
>> +    .atomic_get_property    = vs_crtc_atomic_get_property,
>> +    .late_register        = vs_crtc_late_register,
>> +    .enable_vblank        = vs_crtc_enable_vblank,
>> +    .disable_vblank        = vs_crtc_disable_vblank,
>> +};
>> +
>> +static u8 cal_pixel_bits(u32 bus_format)
>> +{
>> +    u8 bpp;
>> +
>> +    switch (bus_format) {
>> +    case MEDIA_BUS_FMT_RGB565_1X16:
>> +    case MEDIA_BUS_FMT_UYVY8_1X16:
>> +        bpp = 16;
>> +        break;
>> +    case MEDIA_BUS_FMT_RGB666_1X18:
>> +    case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
>> +        bpp = 18;
>> +        break;
>> +    case MEDIA_BUS_FMT_UYVY10_1X20:
>> +        bpp = 20;
>> +        break;
>> +    case MEDIA_BUS_FMT_BGR888_1X24:
>> +    case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
>> +    case MEDIA_BUS_FMT_YUV8_1X24:
>> +        bpp = 24;
>> +        break;
>> +    case MEDIA_BUS_FMT_RGB101010_1X30:
>> +    case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
>> +    case MEDIA_BUS_FMT_YUV10_1X30:
>> +        bpp = 30;
>> +        break;
>> +    default:
>> +        bpp = 24;
>> +        break;
>> +    }
>> +
>> +    return bpp;
>> +}
>> +
>> +static bool vs_crtc_mode_fixup(struct drm_crtc *crtc,
>> +                   const struct drm_display_mode *mode,
>> +                   struct drm_display_mode *adjusted_mode)
>> +{
>> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +
>> +    return vs_crtc->funcs->mode_fixup(vs_crtc->dev, mode, adjusted_mode);
>> +}
>> +
>> +static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
>> +                  struct drm_atomic_state *state)
>> +{
>> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +    struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
>> +
>> +    vs_crtc_state->bpp = cal_pixel_bits(vs_crtc_state->output_fmt);
>> +
>> +    vs_crtc->funcs->enable(vs_crtc->dev, crtc);
>> +    drm_crtc_vblank_on(crtc);
>> +}
>> +
>> +static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
>> +                   struct drm_atomic_state *state)
>> +{
>> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +
>> +    drm_crtc_vblank_off(crtc);
>> +
>> +    vs_crtc->funcs->disable(vs_crtc->dev, crtc);
>> +
>> +    if (crtc->state->event && !crtc->state->active) {
>> +        spin_lock_irq(&crtc->dev->event_lock);
>> +        drm_crtc_send_vblank_event(crtc, crtc->state->event);
>> +        spin_unlock_irq(&crtc->dev->event_lock);
>> +
>> +        crtc->state->event = NULL;
>> +    }
>> +}
>> +
>> +static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
>> +                 struct drm_atomic_state *state)
>> +{
>> +    struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
>> +                                      crtc);
>> +
>> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +    struct device *dev = vs_crtc->dev;
>> +    struct drm_property_blob *blob = crtc->state->gamma_lut;
>> +    struct drm_color_lut *lut;
>> +
>> +    if (crtc_state->color_mgmt_changed) {
>> +        if (blob && blob->length) {
>> +            lut = blob->data;
>> +            vs_crtc->funcs->set_gamma(dev, crtc, lut,
>> +                          blob->length / sizeof(*lut));
>> +            vs_crtc->funcs->enable_gamma(dev, crtc, true);
>> +        } else {
>> +            vs_crtc->funcs->enable_gamma(dev, crtc, false);
>> +        }
>> +    }
>> +}
>> +
>> +static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
>> +                 struct drm_atomic_state *state)
>> +{
>> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +    struct drm_pending_vblank_event *event = crtc->state->event;
>> +
>> +    vs_crtc->funcs->commit(vs_crtc->dev);
>> +
>> +    if (event) {
>> +        WARN_ON(drm_crtc_vblank_get(crtc) != 0);
>> +
>> +        spin_lock_irq(&crtc->dev->event_lock);
>> +        drm_crtc_arm_vblank_event(crtc, event);
>> +        spin_unlock_irq(&crtc->dev->event_lock);
>> +        crtc->state->event = NULL;
>> +    }
>> +}
>> +
>> +static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
>> +    .mode_fixup = vs_crtc_mode_fixup,
>> +    .atomic_enable    = vs_crtc_atomic_enable,
>> +    .atomic_disable = vs_crtc_atomic_disable,
>> +    .atomic_begin    = vs_crtc_atomic_begin,
>> +    .atomic_flush    = vs_crtc_atomic_flush,
>> +};
>> +
>> +static const struct drm_prop_enum_list vs_sync_mode_enum_list[] = {
>> +    { VS_SINGLE_DC,            "single dc mode" },
>> +    { VS_MULTI_DC_PRIMARY,        "primary dc for multi dc mode" },
>> +    { VS_MULTI_DC_SECONDARY,    "secondary dc for multi dc mode" },
>> +};
>> +
>> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
>> +                   struct vs_dc_info *info)
>> +{
>> +    struct vs_crtc *crtc;
>> +    int ret;
>> +
>> +    if (!info)
>> +        return NULL;
>> +
>> +    crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
>> +    if (!crtc)
>> +        return NULL;
>> +
>> +    ret = drm_crtc_init_with_planes(drm_dev, &crtc->base,
>> +                    NULL, NULL, &vs_crtc_funcs,
>> +                    info->name ? info->name : NULL);
>> +    if (ret)
>> +        goto err_free_crtc;
>> +
>> +    drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
>> +
>> +    /* Set up the crtc properties */
>> +    if (info->pipe_sync) {
>> +        crtc->sync_mode = drm_property_create_enum(drm_dev, 0,
>> +                               "SYNC_MODE",
>> +                                vs_sync_mode_enum_list,
>> +                                ARRAY_SIZE(vs_sync_mode_enum_list));
>> +
>> +        if (!crtc->sync_mode)
>> +            goto err_cleanup_crts;
>> +
>> +        drm_object_attach_property(&crtc->base.base,
>> +                       crtc->sync_mode,
>> +                       VS_SINGLE_DC);
>> +    }
>> +
>> +    if (info->gamma_size) {
>> +        ret = drm_mode_crtc_set_gamma_size(&crtc->base,
>> +                           info->gamma_size);
>> +        if (ret)
>> +            goto err_cleanup_crts;
>> +
>> +        drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
>> +                       info->gamma_size);
>> +    }
>> +
>> +    if (info->background) {
>> +        crtc->bg_color = drm_property_create_range(drm_dev, 0,
>> +                               "BG_COLOR", 0, 0xffffffff);
>> +
>> +        if (!crtc->bg_color)
>> +            goto err_cleanup_crts;
>> +
>> +        drm_object_attach_property(&crtc->base.base, crtc->bg_color, 0);
>> +    }
>> +
>> +    if (info->panel_sync) {
>> +        crtc->panel_sync = drm_property_create_bool(drm_dev, 0, "SYNC_ENABLED");
>> +
>> +        if (!crtc->panel_sync)
>> +            goto err_cleanup_crts;
>> +
>> +        drm_object_attach_property(&crtc->base.base, crtc->panel_sync, 0);
>> +    }
>> +
>> +    crtc->dither = drm_property_create_bool(drm_dev, 0, "DITHER_ENABLED");
>> +    if (!crtc->dither)
>> +        goto err_cleanup_crts;
>> +
>> +    drm_object_attach_property(&crtc->base.base, crtc->dither, 0);
>> +
>> +    crtc->max_bpc = info->max_bpc;
>> +    crtc->color_formats = info->color_formats;
>> +    return crtc;
>> +
>> +err_cleanup_crts:
>> +    drm_crtc_cleanup(&crtc->base);
>> +
>> +err_free_crtc:
>> +    kfree(crtc);
>> +    return NULL;
>> +}
>> +
>> +void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow)
>> +{
>> +    struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
>> +
>> +    drm_crtc_handle_vblank(crtc);
>> +
>> +    vs_crtc_state->underflow = underflow;
>> +}
>> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h b/drivers/gpu/drm/verisilicon/vs_crtc.h
>> new file mode 100644
>> index 000000000000..33b3b14249ce
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
>> @@ -0,0 +1,74 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#ifndef __VS_CRTC_H__
>> +#define __VS_CRTC_H__
>> +
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_crtc_helper.h>
>> +
>> +#include "vs_type.h"
>> +
>> +struct vs_crtc_funcs {
>> +    void (*enable)(struct device *dev, struct drm_crtc *crtc);
>> +    void (*disable)(struct device *dev, struct drm_crtc *crtc);
>> +    bool (*mode_fixup)(struct device *dev,
>> +               const struct drm_display_mode *mode,
>> +               struct drm_display_mode *adjusted_mode);
>> +    void (*set_gamma)(struct device *dev, struct drm_crtc *crtc,
>> +              struct drm_color_lut *lut, unsigned int size);
>> +    void (*enable_gamma)(struct device *dev, struct drm_crtc *crtc,
>> +                 bool enable);
>> +    void (*enable_vblank)(struct device *dev, bool enable);
>> +    void (*commit)(struct device *dev);
>> +};
> 
> Why is this here? You are reproducing our interface with an internal interface. I know where this leads to: you have multiple chipset revisions and each has its own implemenation of these internal interfaces.
> 
> That will absolutely come back to haunt you in the long rung: the more chip revisions you support, the more obscure these internal interfaces and implentations become. And you won't be able to change these callbacks, as that affects all revisions. We've seen this with a few drivers. It will become unmaintainable.
> 
> A better approach is to treat DRM's atomic callback funcs and atomic helper funcs as your interface for each chip revision. So for each model, you implement a separate modesetting pipeline. When you add a new chip revision, you copy the previous chip's code into a new file and adopt it. If you find comon code among individual revisions, you can put it into a shared helper.  With this design, each chip revision stands on its own.
> 
> I suggest to study the mgag200 driver. It detects the chip revision very early and builds a chip-specific modesetting pipline. Although each chip is handled separately, a lot of shared code is in helpers. So the size of the driver remains small.
> 
hi Thomas:
I'm trying to understand what you're thinking

1. Different chip ids should have their own independent drm_dev, and should not be supported based on a same drm_dev.
2. diff chip id , for example dc8200 , dc9000,

struct vs_crtc_funcs {
	void (*enable)(struct device *dev, struct drm_crtc *crtc);
	void (*disable)(struct device *dev, struct drm_crtc *crtc);
	bool (*mode_fixup)(struct device *dev,
			   const struct drm_display_mode *mode,
			   struct drm_display_mode *adjusted_mode);
	void (*set_gamma)(struct device *dev, struct drm_crtc *crtc,
			  struct drm_color_lut *lut, unsigned int size);
	void (*enable_gamma)(struct device *dev, struct drm_crtc *crtc,
			     bool enable);
	void (*enable_vblank)(struct device *dev, bool enable);
	void (*commit)(struct device *dev);
};

static const struct vs_crtc_funcs vs_dc8200_crtc_funcs = {...}
static const struct vs_crtc_funcs vs_dc9200_crtc_funcs = {...}

struct vs_drm_private {
	struct drm_device base;
	struct device *dma_dev;
	struct iommu_domain *domain;
	unsigned int pitch_alignment;

	const struct vs_crtc_funcs *funcs;
};
for dc8200 vs_drm_bind  to make  funcs= &vs_dc8200_crtc_funcs 
for dc9000 vs_drm_bind  to make  funcs= &vs_dc9200_crtc_funcs 

so when run dc8200 modesetting pipline
I get drm_dev , get the funcs points ,  then I can call dc8200 internal interfaces . 

Welcome to correct my thoughts.
thanks
>> +
>> +struct vs_crtc_state {
>> +    struct drm_crtc_state base;
>> +
>> +    u32 sync_mode;
>> +    u32 output_fmt;
>> +    u32 bg_color;
>> +    u8 encoder_type;
>> +    u8 mmu_prefetch;
>> +    u8 bpp;
>> +    bool sync_enable;
>> +    bool dither_enable;
>> +    bool underflow;
>> +};
>> +
>> +struct vs_crtc {
>> +    struct drm_crtc base;
>> +    struct device *dev;
> 
> That's stored in base.dev already.
> 
>> +    struct drm_pending_vblank_event *event;
> 
> That's in drm_crtc_state.event already.
> 
>> +    unsigned int max_bpc;
>> +    unsigned int color_formats; /* supported color format */
> 
> These come from a vs_dc_info. Why not just store a pointer to the info instead?
> 
>> +
>> +    struct drm_property *sync_mode;
>> +    struct drm_property *mmu_prefetch;
>> +    struct drm_property *bg_color;
>> +    struct drm_property *panel_sync;
>> +    struct drm_property *dither;
>> +
>> +    const struct vs_crtc_funcs *funcs;
> 
> Please, see my rant why that's not a good idea.
> 
>> +};
>> +
>> +void vs_crtc_destroy(struct drm_crtc *crtc);
>> +
>> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
>> +                   struct vs_dc_info *info);
>> +void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow);
>> +
>> +static inline struct vs_crtc *to_vs_crtc(struct drm_crtc *crtc)
>> +{
>> +    return container_of(crtc, struct vs_crtc, base);
>> +}
>> +
>> +static inline struct vs_crtc_state *
>> +to_vs_crtc_state(struct drm_crtc_state *state)
>> +{
>> +    return container_of(state, struct vs_crtc_state, base);
>> +}
>> +#endif /* __VS_CRTC_H__ */
>> diff --git a/drivers/gpu/drm/verisilicon/vs_type.h b/drivers/gpu/drm/verisilicon/vs_type.h
>> new file mode 100644
>> index 000000000000..6f8db65a703d
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_type.h
>> @@ -0,0 +1,72 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#ifndef __VS_TYPE_H__
>> +#define __VS_TYPE_H__
>> +
>> +#include <linux/version.h>
> 
> Why?
> 

hi Thomas , 

this line should be deleted. 
Historical reasons It has been compatible with multiple kernel versions

 

> Best regards
> Thomas
> 
>> +
>> +#include <drm/drm_plane.h>
>> +#include <drm/drm_plane_helper.h>
>> +
>> +struct vs_plane_info {
>> +    const char *name;
>> +    u8 id;
>> +    enum drm_plane_type type;
>> +    unsigned int num_formats;
>> +    const u32 *formats;
>> +    u8 num_modifiers;
>> +    const u64 *modifiers;
>> +    unsigned int min_width;
>> +    unsigned int min_height;
>> +    unsigned int max_width;
>> +    unsigned int max_height;
>> +    unsigned int rotation;
>> +    unsigned int blend_mode;
>> +    unsigned int color_encoding;
>> +
>> +    /* 0 means no de-gamma LUT */
>> +    unsigned int degamma_size;
>> +
>> +    int min_scale; /* 16.16 fixed point */
>> +    int max_scale; /* 16.16 fixed point */
>> +
>> +    /* default zorder value,
>> +     * and 255 means unsupported zorder capability
>> +     */
>> +    u8     zpos;
>> +
>> +    bool watermark;
>> +    bool color_mgmt;
>> +    bool roi;
>> +};
>> +
>> +struct vs_dc_info {
>> +    const char *name;
>> +
>> +    u8 panel_num;
>> +
>> +    /* planes */
>> +    u8 plane_num;
>> +    const struct vs_plane_info *planes;
>> +
>> +    u8 layer_num;
>> +    unsigned int max_bpc;
>> +    unsigned int color_formats;
>> +
>> +    /* 0 means no gamma LUT */
>> +    u16 gamma_size;
>> +    u8 gamma_bits;
>> +
>> +    u16 pitch_alignment;
>> +
>> +    bool pipe_sync;
>> +    bool mmu_prefetch;
>> +    bool background;
>> +    bool panel_sync;
>> +    bool cap_dec;
>> +};
>> +
>> +#endif /* __VS_TYPE_H__ */
> 

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

* Re: [PATCH 6/9] drm/verisilicon: Add drm crtc funcs
  2023-07-21 11:57     ` Keith Zhao
@ 2023-07-21 12:32       ` Sam Ravnborg
  0 siblings, 0 replies; 46+ messages in thread
From: Sam Ravnborg @ 2023-07-21 12:32 UTC (permalink / raw)
  To: Keith Zhao
  Cc: Thomas Zimmermann, dri-devel, devicetree, linux-kernel,
	linux-riscv, linux-media, linaro-mm-sig, Krzysztof Kozlowski,
	Sumit Semwal, Emil Renner Berthing, Shengyang Chen, Conor Dooley,
	Albert Ou, Maxime Ripard, Jagan Teki, Rob Herring, Chris Morgan,
	Paul Walmsley, Bjorn Andersson, Changhuang Liang, Jack Zhu,
	Palmer Dabbelt, Shawn Guo, christian.koenig

Hi Keith,
On Fri, Jul 21, 2023 at 07:57:24PM +0800, Keith Zhao wrote:
> >> +
> >> +struct vs_crtc_funcs {
> >> +    void (*enable)(struct device *dev, struct drm_crtc *crtc);
> >> +    void (*disable)(struct device *dev, struct drm_crtc *crtc);
> >> +    bool (*mode_fixup)(struct device *dev,
> >> +               const struct drm_display_mode *mode,
> >> +               struct drm_display_mode *adjusted_mode);
> >> +    void (*set_gamma)(struct device *dev, struct drm_crtc *crtc,
> >> +              struct drm_color_lut *lut, unsigned int size);
> >> +    void (*enable_gamma)(struct device *dev, struct drm_crtc *crtc,
> >> +                 bool enable);
> >> +    void (*enable_vblank)(struct device *dev, bool enable);
> >> +    void (*commit)(struct device *dev);
> >> +};
> > 
> > Why is this here? You are reproducing our interface with an internal interface. I know where this leads to: you have multiple chipset revisions and each has its own implemenation of these internal interfaces.
> > 
> > That will absolutely come back to haunt you in the long rung: the more chip revisions you support, the more obscure these internal interfaces and implentations become. And you won't be able to change these callbacks, as that affects all revisions. We've seen this with a few drivers. It will become unmaintainable.
> > 
> > A better approach is to treat DRM's atomic callback funcs and atomic helper funcs as your interface for each chip revision. So for each model, you implement a separate modesetting pipeline. When you add a new chip revision, you copy the previous chip's code into a new file and adopt it. If you find comon code among individual revisions, you can put it into a shared helper.  With this design, each chip revision stands on its own.
> > 
> > I suggest to study the mgag200 driver. It detects the chip revision very early and builds a chip-specific modesetting pipline. Although each chip is handled separately, a lot of shared code is in helpers. So the size of the driver remains small.
> > 
> hi Thomas:
> I'm trying to understand what you're thinking

I am not Thomas, but let me try to put a few words on this.

> 1. Different chip ids should have their own independent drm_dev, and should not be supported based on a same drm_dev.
Yes, this part is correct understood.

> 2. diff chip id , for example dc8200 , dc9000,
> 
> struct vs_crtc_funcs {
> 	void (*enable)(struct device *dev, struct drm_crtc *crtc);
> 	void (*disable)(struct device *dev, struct drm_crtc *crtc);
> 	bool (*mode_fixup)(struct device *dev,
> 			   const struct drm_display_mode *mode,
> 			   struct drm_display_mode *adjusted_mode);
> 	void (*set_gamma)(struct device *dev, struct drm_crtc *crtc,
> 			  struct drm_color_lut *lut, unsigned int size);
> 	void (*enable_gamma)(struct device *dev, struct drm_crtc *crtc,
> 			     bool enable);
> 	void (*enable_vblank)(struct device *dev, bool enable);
> 	void (*commit)(struct device *dev);
> };
No - the idea is that you populate crtc_funcs direct.
Drop struct vs_crtc_funcs - just fill out your own crtc_funcs structure.

If it turns out that most of the crtc operations are the same then share
them. Avoid the extra layer of indirection that you have with struct vs_crtc_funcs
as this is not needed when you use the pattern described by Thomas.


> static const struct vs_crtc_funcs vs_dc8200_crtc_funcs = {...}
> static const struct vs_crtc_funcs vs_dc9200_crtc_funcs = {...}
> 
> struct vs_drm_private {
> 	struct drm_device base;
> 	struct device *dma_dev;
> 	struct iommu_domain *domain;
> 	unsigned int pitch_alignment;

This parts looks fine.

> 
> 	const struct vs_crtc_funcs *funcs;
No, here you need a pointer to struct crtc_funcs or a struct that embeds
crtc_funcs.
> };

If you, after reading this, thinks you need struct vs_crtc_funcs, then
try to take an extra look at mgag200. It is not needed.

I hope this helps.

	Sam

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

* Re: [PATCH 3/9] drm/verisilicon: Add basic drm driver
  2023-06-07  8:53   ` Lucas Stach
@ 2023-07-25  3:12     ` Keith Zhao
  2023-07-25 11:23       ` Keith Zhao
  0 siblings, 1 reply; 46+ messages in thread
From: Keith Zhao @ 2023-07-25  3:12 UTC (permalink / raw)
  To: Lucas Stach, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: Krzysztof Kozlowski, Sumit Semwal, Emil Renner Berthing,
	Shengyang Chen, Conor Dooley, Albert Ou, Thomas Zimmermann,
	Jagan Teki, Rob Herring, Chris Morgan, Paul Walmsley,
	Bjorn Andersson, Changhuang Liang, Jack Zhu, Palmer Dabbelt,
	Shawn Guo, christian.koenig



On 2023/6/7 16:53, Lucas Stach wrote:
> Hi Keith,
> 
> Am Freitag, dem 02.06.2023 um 15:40 +0800 schrieb Keith Zhao:
>> Add a basic platform driver of the DRM driver for JH7110 SoC.
>> 
>> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
>> ---
>>  MAINTAINERS                          |   2 +
>>  drivers/gpu/drm/Kconfig              |   2 +
>>  drivers/gpu/drm/Makefile             |   1 +
>>  drivers/gpu/drm/verisilicon/Kconfig  |  13 ++
>>  drivers/gpu/drm/verisilicon/Makefile |   6 +
>>  drivers/gpu/drm/verisilicon/vs_drv.c | 284 +++++++++++++++++++++++++++
>>  drivers/gpu/drm/verisilicon/vs_drv.h |  48 +++++
>>  include/uapi/drm/drm_fourcc.h        |  83 ++++++++
>>  include/uapi/drm/vs_drm.h            |  50 +++++
>>  9 files changed, 489 insertions(+)
>>  create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
>>  create mode 100644 drivers/gpu/drm/verisilicon/Makefile
>>  create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
>>  create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
>>  create mode 100644 include/uapi/drm/vs_drm.h
>> 
>> 
>> [...]
>> +#endif /* __VS_DRV_H__ */
>> diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
>> index de703c6be969..af4fb50f9207 100644
>> --- a/include/uapi/drm/drm_fourcc.h
>> +++ b/include/uapi/drm/drm_fourcc.h
>> @@ -419,6 +419,7 @@ extern "C" {
>>  #define DRM_FORMAT_MOD_VENDOR_ARM     0x08
>>  #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09
>>  #define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a
>> +#define DRM_FORMAT_MOD_VENDOR_VS      0x0b
>>  
>>  /* add more to the end as needed */
>>  
>> @@ -1519,6 +1520,88 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
>>  #define AMD_FMT_MOD_CLEAR(field) \
>>  	(~((__u64)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT))
>>  
>> +#define DRM_FORMAT_MOD_VS_TYPE_NORMAL        0x00
>> +#define DRM_FORMAT_MOD_VS_TYPE_COMPRESSED    0x01
>> +#define DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT  0x02
>> +#define DRM_FORMAT_MOD_VS_TYPE_MASK     ((__u64)0x3 << 54)
>> +
>> +#define fourcc_mod_vs_code(type, val) \
>> +	fourcc_mod_code(VS, ((((__u64)type) << 54) | (val)))
>> +
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_MODE_MASK    0x3F
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_XMAJOR   0x00
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_YMAJOR   0x01
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4     0x02
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4      0x03
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_4X8      0x04
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X4   0x06
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X4     0x07
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4     0x08
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X1  0x09
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X1  0x0A
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X4   0x0B
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X2  0x0C
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X2  0x0D
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X4  0x0E
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X1   0x0F
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X8     0x10
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X16     0x11
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_512X1  0x12
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X4   0x13
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X2   0x14
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X2   0x15
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X1   0x16
>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X1   0x17
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X4    0x18
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_256X4    0x19
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_512X4    0x1A
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X16    0x1B
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X16    0x1C
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X16    0x1D
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X8    0x1E
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4_S    0x1F
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_S   0x20
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_S   0x21
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_LSB 0x22
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_LSB 0x23
>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X8     0x24
>> +
>> +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_32      (0x01 << 6)
>> +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_64      (0x01 << 7)
>> +
>> +#define fourcc_mod_vs_dec_code(tile, align) \
>> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_COMPRESSED, \
>> +				((tile) | (align)))
>> +
>> +#define DRM_FORMAT_MOD_VS_NORM_MODE_MASK        0x1F
>> +#define DRM_FORMAT_MOD_VS_LINEAR                0x00
>> +#define DRM_FORMAT_MOD_VS_TILED4x4              0x01
>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR    0x02
>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR    0x03
>> +#define DRM_FORMAT_MOD_VS_TILE_8X8              0x04
>> +#define DRM_FORMAT_MOD_VS_TILE_MODE1            0x05
>> +#define DRM_FORMAT_MOD_VS_TILE_MODE2            0x06
>> +#define DRM_FORMAT_MOD_VS_TILE_8X4              0x07
>> +#define DRM_FORMAT_MOD_VS_TILE_MODE4            0x08
>> +#define DRM_FORMAT_MOD_VS_TILE_MODE5            0x09
>> +#define DRM_FORMAT_MOD_VS_TILE_MODE6            0x0A
>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4    0x0B
>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8    0x0C
>> +#define DRM_FORMAT_MOD_VS_TILE_Y                0x0D
>> +#define DRM_FORMAT_MOD_VS_TILE_128X1            0x0F
>> +#define DRM_FORMAT_MOD_VS_TILE_256X1            0x10
>> +#define DRM_FORMAT_MOD_VS_TILE_32X1             0x11
>> +#define DRM_FORMAT_MOD_VS_TILE_64X1             0x12
>> +#define DRM_FORMAT_MOD_VS_TILE_MODE4X4          0x15
>> +
>> +#define fourcc_mod_vs_norm_code(tile) \
>> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_NORMAL, \
>> +				(tile))
>> +
>> +#define fourcc_mod_vs_custom_code(tile) \
>> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT, \
>> +				(tile))
>> +
> 
> You are opening a new namespace for what is effectively the VIVANTE
> tiling. While your list seems much more exhaustive than the (reverse
> engineered) list provided under the VIVANTE namespace, this is still
> unacceptable as it adds new aliases for existing modifiers.
> 
hi Lucas:
I got what you mean , I will check the whether the current existence can be reused.
In principle, can existing modefiers cover my definition?

> Also any modifier additions should be in a separate patch and not
> buried in another change.
> 
ok , no problem
> Regards,
> Lucas

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

* Re: [PATCH 3/9] drm/verisilicon: Add basic drm driver
  2023-07-25  3:12     ` Keith Zhao
@ 2023-07-25 11:23       ` Keith Zhao
  0 siblings, 0 replies; 46+ messages in thread
From: Keith Zhao @ 2023-07-25 11:23 UTC (permalink / raw)
  To: Lucas Stach, dri-devel, devicetree, linux-kernel, linux-riscv,
	linux-media, linaro-mm-sig
  Cc: Krzysztof Kozlowski, Sumit Semwal, Emil Renner Berthing,
	Shengyang Chen, Conor Dooley, Albert Ou, Thomas Zimmermann,
	Jagan Teki, Rob Herring, Chris Morgan, Paul Walmsley,
	Bjorn Andersson, Changhuang Liang, Jack Zhu, Palmer Dabbelt,
	Shawn Guo, christian.koenig



On 2023/7/25 11:12, Keith Zhao wrote:
> 
> 
> On 2023/6/7 16:53, Lucas Stach wrote:
>> Hi Keith,
>> 
>> Am Freitag, dem 02.06.2023 um 15:40 +0800 schrieb Keith Zhao:
>>> Add a basic platform driver of the DRM driver for JH7110 SoC.
>>> 
>>> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
>>> ---
>>>  MAINTAINERS                          |   2 +
>>>  drivers/gpu/drm/Kconfig              |   2 +
>>>  drivers/gpu/drm/Makefile             |   1 +
>>>  drivers/gpu/drm/verisilicon/Kconfig  |  13 ++
>>>  drivers/gpu/drm/verisilicon/Makefile |   6 +
>>>  drivers/gpu/drm/verisilicon/vs_drv.c | 284 +++++++++++++++++++++++++++
>>>  drivers/gpu/drm/verisilicon/vs_drv.h |  48 +++++
>>>  include/uapi/drm/drm_fourcc.h        |  83 ++++++++
>>>  include/uapi/drm/vs_drm.h            |  50 +++++
>>>  9 files changed, 489 insertions(+)
>>>  create mode 100644 drivers/gpu/drm/verisilicon/Kconfig
>>>  create mode 100644 drivers/gpu/drm/verisilicon/Makefile
>>>  create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c
>>>  create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h
>>>  create mode 100644 include/uapi/drm/vs_drm.h
>>> 
>>> 
>>> [...]
>>> +#endif /* __VS_DRV_H__ */
>>> diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
>>> index de703c6be969..af4fb50f9207 100644
>>> --- a/include/uapi/drm/drm_fourcc.h
>>> +++ b/include/uapi/drm/drm_fourcc.h
>>> @@ -419,6 +419,7 @@ extern "C" {
>>>  #define DRM_FORMAT_MOD_VENDOR_ARM     0x08
>>>  #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09
>>>  #define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a
>>> +#define DRM_FORMAT_MOD_VENDOR_VS      0x0b
>>>  
>>>  /* add more to the end as needed */
>>>  
>>> @@ -1519,6 +1520,88 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
>>>  #define AMD_FMT_MOD_CLEAR(field) \
>>>  	(~((__u64)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT))
>>>  
>>> +#define DRM_FORMAT_MOD_VS_TYPE_NORMAL        0x00
>>> +#define DRM_FORMAT_MOD_VS_TYPE_COMPRESSED    0x01
>>> +#define DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT  0x02
>>> +#define DRM_FORMAT_MOD_VS_TYPE_MASK     ((__u64)0x3 << 54)
>>> +
>>> +#define fourcc_mod_vs_code(type, val) \
>>> +	fourcc_mod_code(VS, ((((__u64)type) << 54) | (val)))
>>> +
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_MODE_MASK    0x3F
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_XMAJOR   0x00
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X8_YMAJOR   0x01
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4     0x02
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4      0x03
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_4X8      0x04
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X4   0x06
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X4     0x07
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4     0x08
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X1  0x09
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X1  0x0A
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X4   0x0B
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_256X2  0x0C
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X2  0x0D
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_128X4  0x0E
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X1   0x0F
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X8     0x10
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X16     0x11
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_512X1  0x12
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X4   0x13
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_64X2   0x14
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X2   0x15
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_32X1   0x16
>>> +#define DRM_FORMAT_MOD_VS_DEC_RASTER_16X1   0x17
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X4    0x18
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_256X4    0x19
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_512X4    0x1A
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X16    0x1B
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X16    0x1C
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_64X16    0x1D
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_128X8    0x1E
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_8X4_S    0x1F
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_S   0x20
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_S   0x21
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_16X4_LSB 0x22
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X4_LSB 0x23
>>> +#define DRM_FORMAT_MOD_VS_DEC_TILE_32X8     0x24
>>> +
>>> +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_32      (0x01 << 6)
>>> +#define DRM_FORMAT_MOD_VS_DEC_ALIGN_64      (0x01 << 7)
>>> +
>>> +#define fourcc_mod_vs_dec_code(tile, align) \
>>> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_COMPRESSED, \
>>> +				((tile) | (align)))
>>> +
>>> +#define DRM_FORMAT_MOD_VS_NORM_MODE_MASK        0x1F
>>> +#define DRM_FORMAT_MOD_VS_LINEAR                0x00
>>> +#define DRM_FORMAT_MOD_VS_TILED4x4              0x01
>>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR    0x02
>>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR    0x03
>>> +#define DRM_FORMAT_MOD_VS_TILE_8X8              0x04
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE1            0x05
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE2            0x06
>>> +#define DRM_FORMAT_MOD_VS_TILE_8X4              0x07
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE4            0x08
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE5            0x09
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE6            0x0A
>>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4    0x0B
>>> +#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8    0x0C
>>> +#define DRM_FORMAT_MOD_VS_TILE_Y                0x0D
>>> +#define DRM_FORMAT_MOD_VS_TILE_128X1            0x0F
>>> +#define DRM_FORMAT_MOD_VS_TILE_256X1            0x10
>>> +#define DRM_FORMAT_MOD_VS_TILE_32X1             0x11
>>> +#define DRM_FORMAT_MOD_VS_TILE_64X1             0x12
>>> +#define DRM_FORMAT_MOD_VS_TILE_MODE4X4          0x15
>>> +
>>> +#define fourcc_mod_vs_norm_code(tile) \
>>> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_NORMAL, \
>>> +				(tile))
>>> +
>>> +#define fourcc_mod_vs_custom_code(tile) \
>>> +	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT, \
>>> +				(tile))
>>> +
>> 
>> You are opening a new namespace for what is effectively the VIVANTE
>> tiling. While your list seems much more exhaustive than the (reverse
>> engineered) list provided under the VIVANTE namespace, this is still
>> unacceptable as it adds new aliases for existing modifiers.
>> 
> hi Lucas:
> I got what you mean , I will check the whether the current existence can be reused.
> In principle, can existing modefiers cover my definition?
> 

hello Lucas:
I made it a little simpler: I removed what I didn't use in the code .
Keep only these:

#define DRM_FORMAT_MOD_VS_TYPE_NORMAL        0x00
#define DRM_FORMAT_MOD_VS_TYPE_COMPRESSED    0x01
#define DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT  0x02
#define DRM_FORMAT_MOD_VS_TYPE_MASK     ((__u64)0x3 << 54)

#define fourcc_mod_vs_code(type, val) \
	fourcc_mod_code(VS, ((((__u64)type) << 54) | (val)))

#define DRM_FORMAT_MOD_VS_NORM_MODE_MASK        0x1F
#define DRM_FORMAT_MOD_VS_LINEAR                0x00
#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR    0x02
#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR    0x03
#define DRM_FORMAT_MOD_VS_TILE_8X8              0x04
#define DRM_FORMAT_MOD_VS_TILE_8X4              0x07
#define DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4    0x0B
#define DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8    0x0C
#define DRM_FORMAT_MOD_VS_TILE_MODE4X4          0x15

#define fourcc_mod_vs_norm_code(tile) \
	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_NORMAL, \
				(tile))

#define fourcc_mod_vs_custom_code(tile) \
	fourcc_mod_vs_code(DRM_FORMAT_MOD_VS_TYPE_CUSTOM_10BIT, \
				(tile))

I need you help to check what modifiers it should be (for existing modifiers) 

DRM_FORMAT_MOD_VS_LINEAR			----> DRM_FORMAT_MOD_LINEAR
DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR 		----> ?
DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR 		----> ?
DRM_FORMAT_MOD_VS_TILE_8X8           		----> ?  
DRM_FORMAT_MOD_VS_TILE_8X4              	----> ?                    
DRM_FORMAT_MOD_VS_SUPER_TILED_XMAJOR_8X4    	----> ?
DRM_FORMAT_MOD_VS_SUPER_TILED_YMAJOR_4X8    	----> ?
DRM_FORMAT_MOD_VS_TILE_MODE4X4          	----> DRM_FORMAT_MOD_VIVANTE_TILED

Thanks a million!!
Keith
>> Also any modifier additions should be in a separate patch and not
>> buried in another change.
>> 
> ok , no problem
>> Regards,
>> Lucas

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

end of thread, other threads:[~2023-07-25 11:24 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-02  7:40 [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Keith Zhao
2023-06-02  7:40 ` [PATCH 1/9] dt-bindings: display: Add yamls for JH7110 display subsystem Keith Zhao
2023-06-02 18:21   ` Conor Dooley
2023-06-06 18:41     ` Shengyu Qu
2023-06-06 22:22       ` Heiko Stübner
2023-06-06 22:37         ` Conor Dooley
2023-06-07  6:41           ` Maxime Ripard
2023-06-07  8:02             ` Keith Zhao
2023-06-07  8:40           ` Heiko Stübner
2023-06-07  7:35   ` Krzysztof Kozlowski
2023-06-02  7:40 ` [PATCH 2/9] riscv: dts: starfive: jh7110: add dc&hdmi controller node Keith Zhao
2023-06-07  7:38   ` Krzysztof Kozlowski
2023-06-02  7:40 ` [PATCH 3/9] drm/verisilicon: Add basic drm driver Keith Zhao
2023-06-07  8:53   ` Lucas Stach
2023-07-25  3:12     ` Keith Zhao
2023-07-25 11:23       ` Keith Zhao
2023-06-19 12:59   ` Thomas Zimmermann
2023-07-07 18:09     ` Nicolas Dufresne
2023-07-08 19:11       ` Thomas Zimmermann
2023-07-13 15:14         ` Nicolas Dufresne
2023-07-03 18:42   ` Shengyu Qu
2023-07-04  6:09     ` Keith Zhao
2023-06-02  7:40 ` [PATCH 4/9] drm/verisilicon: Add gem driver for JH7110 SoC Keith Zhao
2023-06-19 13:18   ` Thomas Zimmermann
2023-07-20 10:00     ` Keith Zhao
2023-06-19 14:22   ` Thomas Zimmermann
2023-06-21 10:44     ` Thomas Zimmermann
2023-06-02  7:40 ` [PATCH 5/9] drm/verisilicon: Add mode config funcs Keith Zhao
2023-06-21 11:04   ` Thomas Zimmermann
2023-07-21  9:06     ` Keith Zhao
2023-06-02  7:40 ` [PATCH 6/9] drm/verisilicon: Add drm crtc funcs Keith Zhao
2023-06-30 11:55   ` Thomas Zimmermann
2023-07-21 11:57     ` Keith Zhao
2023-07-21 12:32       ` Sam Ravnborg
2023-06-02  7:40 ` [PATCH 7/9] drm/verisilicon: Add drm plane funcs Keith Zhao
2023-06-30 12:14   ` Thomas Zimmermann
2023-07-10 16:46   ` Shengyu Qu
2023-07-11  1:44     ` Keith Zhao
2023-06-02  7:40 ` [PATCH 8/9] drm/verisilicon: Add verisilicon dc controller driver Keith Zhao
2023-06-30 12:36   ` Thomas Zimmermann
2023-06-02  7:40 ` [PATCH 9/9] drm/verisilicon: Add starfive hdmi driver Keith Zhao
2023-06-05  8:08   ` Philipp Zabel
2023-06-05  9:56   ` Maxime Ripard
2023-06-23  2:38   ` Hoegeun Kwon
2023-06-26  5:34     ` Keith Zhao
2023-06-22 18:19 ` [PATCH 0/9] Add DRM driver for StarFive SoC JH7110 Palmer Dabbelt

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).