All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/18] drm/rockchip: RK356x VOP2 support
@ 2021-12-08 15:12 ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

This is the second round of the vop2 series. There are still some issues open,
but I thought it's about time to let people see and test it. I integrated the
review feedback I got from v1. Other changes include:

All framesync waiting is gone from the driver which makes it more straight
forward. To accomplish this the port_mux setup is now static in the driver.
This means each video port has a fixed maximum number of planes which is less
flexible but much easier to handle.

I also removed much of the register mapping and shadow register handling around
struct vop_reg. This basically resembles regmap and can eventually replaced by
regmap. Some places are still left in the driver, I plan to remove those in
later versions.

I think I have found the issue why only 1080p resolutions work, this seems to
be an issue in the way the clock tree is arranged. See the last patch in this
series which points to the problem, so far I don't have a good solution for it.

As usual, all comments and feedback welcome.

Sascha

Changes since v1:
- drop all unnecessary waiting for frames within atomic modeset and plane update
- Cluster subwin support removed
- gamma support removed
- unnecessary irq_lock removed
- interrupt handling simplified
- simplified zpos handling
- drop is_alpha_support(), use fb->format->has_alpha instead
- use devm_regulator_get() rather than devm_regulator_get_optional() for hdmi regulators
- Use fixed number of planes per video port
- Drop homegrown regmap code from vop2 driver (not complete yet)
- Add separate include file for vop2 driver to not pollute the vop include

Andy Yan (1):
  drm: rockchip: Add VOP2 driver

Benjamin Gaignard (1):
  dt-bindings: display: rockchip: dw-hdmi: Add compatible for rk3568
    HDMI

Michael Riesch (1):
  arm64: dts: rockchip: enable vop2 and hdmi tx on quartz64a

Sascha Hauer (15):
  drm/rockchip: dw_hdmi: Do not leave clock enabled in error case
  drm/rockchip: dw_hdmi: rename vpll clock to reference clock
  drm/rockchip: dw_hdmi: add rk3568 support
  drm/rockchip: dw_hdmi: add regulator support
  dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
  dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
  dt-bindings: display: rockchip: dw-hdmi: Add regulator support
  arm64: dts: rockchip: rk3399: reorder hmdi clocks
  dt-bindings: display: rockchip: Add binding for VOP2
  arm64: dts: rockchip: rk356x: Add VOP2 nodes
  arm64: dts: rockchip: rk356x: Add HDMI nodes
  arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
  drm/encoder: Add of_graph port to struct drm_encoder
  drm/rockchip: Make VOP driver optional
  [HACK, RFC] clk: rk3568: do not divide dclk_vop0

 .../display/rockchip/rockchip,dw-hdmi.yaml    |   14 +-
 .../display/rockchip/rockchip-vop2.yaml       |  118 +
 arch/arm64/boot/dts/rockchip/rk3399.dtsi      |    6 +-
 .../boot/dts/rockchip/rk3566-quartz64-a.dts   |   31 +
 arch/arm64/boot/dts/rockchip/rk3566.dtsi      |    4 +
 .../boot/dts/rockchip/rk3568-evb1-v10.dts     |   31 +
 arch/arm64/boot/dts/rockchip/rk3568.dtsi      |    4 +
 arch/arm64/boot/dts/rockchip/rk356x.dtsi      |   75 +
 drivers/clk/rockchip/clk-rk3568.c             |    4 +-
 drivers/gpu/drm/rockchip/Kconfig              |   14 +
 drivers/gpu/drm/rockchip/Makefile             |    4 +-
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c   |  107 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c   |    3 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h   |    7 +-
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c    |    2 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h   |   15 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c  | 2636 +++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h  |  625 ++++
 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c  |  505 ++++
 include/drm/drm_encoder.h                     |    2 +
 include/dt-bindings/soc/rockchip,vop2.h       |   14 +
 21 files changed, 4193 insertions(+), 28 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
 create mode 100644 include/dt-bindings/soc/rockchip,vop2.h

-- 
2.30.2


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

* [PATCH v2 00/18] drm/rockchip: RK356x VOP2 support
@ 2021-12-08 15:12 ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

This is the second round of the vop2 series. There are still some issues open,
but I thought it's about time to let people see and test it. I integrated the
review feedback I got from v1. Other changes include:

All framesync waiting is gone from the driver which makes it more straight
forward. To accomplish this the port_mux setup is now static in the driver.
This means each video port has a fixed maximum number of planes which is less
flexible but much easier to handle.

I also removed much of the register mapping and shadow register handling around
struct vop_reg. This basically resembles regmap and can eventually replaced by
regmap. Some places are still left in the driver, I plan to remove those in
later versions.

I think I have found the issue why only 1080p resolutions work, this seems to
be an issue in the way the clock tree is arranged. See the last patch in this
series which points to the problem, so far I don't have a good solution for it.

As usual, all comments and feedback welcome.

Sascha

Changes since v1:
- drop all unnecessary waiting for frames within atomic modeset and plane update
- Cluster subwin support removed
- gamma support removed
- unnecessary irq_lock removed
- interrupt handling simplified
- simplified zpos handling
- drop is_alpha_support(), use fb->format->has_alpha instead
- use devm_regulator_get() rather than devm_regulator_get_optional() for hdmi regulators
- Use fixed number of planes per video port
- Drop homegrown regmap code from vop2 driver (not complete yet)
- Add separate include file for vop2 driver to not pollute the vop include

Andy Yan (1):
  drm: rockchip: Add VOP2 driver

Benjamin Gaignard (1):
  dt-bindings: display: rockchip: dw-hdmi: Add compatible for rk3568
    HDMI

Michael Riesch (1):
  arm64: dts: rockchip: enable vop2 and hdmi tx on quartz64a

Sascha Hauer (15):
  drm/rockchip: dw_hdmi: Do not leave clock enabled in error case
  drm/rockchip: dw_hdmi: rename vpll clock to reference clock
  drm/rockchip: dw_hdmi: add rk3568 support
  drm/rockchip: dw_hdmi: add regulator support
  dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
  dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
  dt-bindings: display: rockchip: dw-hdmi: Add regulator support
  arm64: dts: rockchip: rk3399: reorder hmdi clocks
  dt-bindings: display: rockchip: Add binding for VOP2
  arm64: dts: rockchip: rk356x: Add VOP2 nodes
  arm64: dts: rockchip: rk356x: Add HDMI nodes
  arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
  drm/encoder: Add of_graph port to struct drm_encoder
  drm/rockchip: Make VOP driver optional
  [HACK, RFC] clk: rk3568: do not divide dclk_vop0

 .../display/rockchip/rockchip,dw-hdmi.yaml    |   14 +-
 .../display/rockchip/rockchip-vop2.yaml       |  118 +
 arch/arm64/boot/dts/rockchip/rk3399.dtsi      |    6 +-
 .../boot/dts/rockchip/rk3566-quartz64-a.dts   |   31 +
 arch/arm64/boot/dts/rockchip/rk3566.dtsi      |    4 +
 .../boot/dts/rockchip/rk3568-evb1-v10.dts     |   31 +
 arch/arm64/boot/dts/rockchip/rk3568.dtsi      |    4 +
 arch/arm64/boot/dts/rockchip/rk356x.dtsi      |   75 +
 drivers/clk/rockchip/clk-rk3568.c             |    4 +-
 drivers/gpu/drm/rockchip/Kconfig              |   14 +
 drivers/gpu/drm/rockchip/Makefile             |    4 +-
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c   |  107 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c   |    3 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h   |    7 +-
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c    |    2 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h   |   15 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c  | 2636 +++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h  |  625 ++++
 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c  |  505 ++++
 include/drm/drm_encoder.h                     |    2 +
 include/dt-bindings/soc/rockchip,vop2.h       |   14 +
 21 files changed, 4193 insertions(+), 28 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
 create mode 100644 include/dt-bindings/soc/rockchip,vop2.h

-- 
2.30.2


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

* [PATCH v2 00/18] drm/rockchip: RK356x VOP2 support
@ 2021-12-08 15:12 ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

This is the second round of the vop2 series. There are still some issues open,
but I thought it's about time to let people see and test it. I integrated the
review feedback I got from v1. Other changes include:

All framesync waiting is gone from the driver which makes it more straight
forward. To accomplish this the port_mux setup is now static in the driver.
This means each video port has a fixed maximum number of planes which is less
flexible but much easier to handle.

I also removed much of the register mapping and shadow register handling around
struct vop_reg. This basically resembles regmap and can eventually replaced by
regmap. Some places are still left in the driver, I plan to remove those in
later versions.

I think I have found the issue why only 1080p resolutions work, this seems to
be an issue in the way the clock tree is arranged. See the last patch in this
series which points to the problem, so far I don't have a good solution for it.

As usual, all comments and feedback welcome.

Sascha

Changes since v1:
- drop all unnecessary waiting for frames within atomic modeset and plane update
- Cluster subwin support removed
- gamma support removed
- unnecessary irq_lock removed
- interrupt handling simplified
- simplified zpos handling
- drop is_alpha_support(), use fb->format->has_alpha instead
- use devm_regulator_get() rather than devm_regulator_get_optional() for hdmi regulators
- Use fixed number of planes per video port
- Drop homegrown regmap code from vop2 driver (not complete yet)
- Add separate include file for vop2 driver to not pollute the vop include

Andy Yan (1):
  drm: rockchip: Add VOP2 driver

Benjamin Gaignard (1):
  dt-bindings: display: rockchip: dw-hdmi: Add compatible for rk3568
    HDMI

Michael Riesch (1):
  arm64: dts: rockchip: enable vop2 and hdmi tx on quartz64a

Sascha Hauer (15):
  drm/rockchip: dw_hdmi: Do not leave clock enabled in error case
  drm/rockchip: dw_hdmi: rename vpll clock to reference clock
  drm/rockchip: dw_hdmi: add rk3568 support
  drm/rockchip: dw_hdmi: add regulator support
  dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
  dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
  dt-bindings: display: rockchip: dw-hdmi: Add regulator support
  arm64: dts: rockchip: rk3399: reorder hmdi clocks
  dt-bindings: display: rockchip: Add binding for VOP2
  arm64: dts: rockchip: rk356x: Add VOP2 nodes
  arm64: dts: rockchip: rk356x: Add HDMI nodes
  arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
  drm/encoder: Add of_graph port to struct drm_encoder
  drm/rockchip: Make VOP driver optional
  [HACK, RFC] clk: rk3568: do not divide dclk_vop0

 .../display/rockchip/rockchip,dw-hdmi.yaml    |   14 +-
 .../display/rockchip/rockchip-vop2.yaml       |  118 +
 arch/arm64/boot/dts/rockchip/rk3399.dtsi      |    6 +-
 .../boot/dts/rockchip/rk3566-quartz64-a.dts   |   31 +
 arch/arm64/boot/dts/rockchip/rk3566.dtsi      |    4 +
 .../boot/dts/rockchip/rk3568-evb1-v10.dts     |   31 +
 arch/arm64/boot/dts/rockchip/rk3568.dtsi      |    4 +
 arch/arm64/boot/dts/rockchip/rk356x.dtsi      |   75 +
 drivers/clk/rockchip/clk-rk3568.c             |    4 +-
 drivers/gpu/drm/rockchip/Kconfig              |   14 +
 drivers/gpu/drm/rockchip/Makefile             |    4 +-
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c   |  107 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c   |    3 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h   |    7 +-
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c    |    2 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h   |   15 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c  | 2636 +++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h  |  625 ++++
 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c  |  505 ++++
 include/drm/drm_encoder.h                     |    2 +
 include/dt-bindings/soc/rockchip,vop2.h       |   14 +
 21 files changed, 4193 insertions(+), 28 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
 create mode 100644 include/dt-bindings/soc/rockchip,vop2.h

-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v2 00/18] drm/rockchip: RK356x VOP2 support
@ 2021-12-08 15:12 ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

This is the second round of the vop2 series. There are still some issues open,
but I thought it's about time to let people see and test it. I integrated the
review feedback I got from v1. Other changes include:

All framesync waiting is gone from the driver which makes it more straight
forward. To accomplish this the port_mux setup is now static in the driver.
This means each video port has a fixed maximum number of planes which is less
flexible but much easier to handle.

I also removed much of the register mapping and shadow register handling around
struct vop_reg. This basically resembles regmap and can eventually replaced by
regmap. Some places are still left in the driver, I plan to remove those in
later versions.

I think I have found the issue why only 1080p resolutions work, this seems to
be an issue in the way the clock tree is arranged. See the last patch in this
series which points to the problem, so far I don't have a good solution for it.

As usual, all comments and feedback welcome.

Sascha

Changes since v1:
- drop all unnecessary waiting for frames within atomic modeset and plane update
- Cluster subwin support removed
- gamma support removed
- unnecessary irq_lock removed
- interrupt handling simplified
- simplified zpos handling
- drop is_alpha_support(), use fb->format->has_alpha instead
- use devm_regulator_get() rather than devm_regulator_get_optional() for hdmi regulators
- Use fixed number of planes per video port
- Drop homegrown regmap code from vop2 driver (not complete yet)
- Add separate include file for vop2 driver to not pollute the vop include

Andy Yan (1):
  drm: rockchip: Add VOP2 driver

Benjamin Gaignard (1):
  dt-bindings: display: rockchip: dw-hdmi: Add compatible for rk3568
    HDMI

Michael Riesch (1):
  arm64: dts: rockchip: enable vop2 and hdmi tx on quartz64a

Sascha Hauer (15):
  drm/rockchip: dw_hdmi: Do not leave clock enabled in error case
  drm/rockchip: dw_hdmi: rename vpll clock to reference clock
  drm/rockchip: dw_hdmi: add rk3568 support
  drm/rockchip: dw_hdmi: add regulator support
  dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
  dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
  dt-bindings: display: rockchip: dw-hdmi: Add regulator support
  arm64: dts: rockchip: rk3399: reorder hmdi clocks
  dt-bindings: display: rockchip: Add binding for VOP2
  arm64: dts: rockchip: rk356x: Add VOP2 nodes
  arm64: dts: rockchip: rk356x: Add HDMI nodes
  arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
  drm/encoder: Add of_graph port to struct drm_encoder
  drm/rockchip: Make VOP driver optional
  [HACK, RFC] clk: rk3568: do not divide dclk_vop0

 .../display/rockchip/rockchip,dw-hdmi.yaml    |   14 +-
 .../display/rockchip/rockchip-vop2.yaml       |  118 +
 arch/arm64/boot/dts/rockchip/rk3399.dtsi      |    6 +-
 .../boot/dts/rockchip/rk3566-quartz64-a.dts   |   31 +
 arch/arm64/boot/dts/rockchip/rk3566.dtsi      |    4 +
 .../boot/dts/rockchip/rk3568-evb1-v10.dts     |   31 +
 arch/arm64/boot/dts/rockchip/rk3568.dtsi      |    4 +
 arch/arm64/boot/dts/rockchip/rk356x.dtsi      |   75 +
 drivers/clk/rockchip/clk-rk3568.c             |    4 +-
 drivers/gpu/drm/rockchip/Kconfig              |   14 +
 drivers/gpu/drm/rockchip/Makefile             |    4 +-
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c   |  107 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c   |    3 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h   |    7 +-
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c    |    2 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h   |   15 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c  | 2636 +++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h  |  625 ++++
 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c  |  505 ++++
 include/drm/drm_encoder.h                     |    2 +
 include/dt-bindings/soc/rockchip,vop2.h       |   14 +
 21 files changed, 4193 insertions(+), 28 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
 create mode 100644 include/dt-bindings/soc/rockchip,vop2.h

-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 01/18] drm/rockchip: dw_hdmi: Do not leave clock enabled in error case
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The driver returns an error when devm_phy_optional_get() fails leaving
the previously enabled clock turned on. Change order and enable the
clock only after the phy has been acquired.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 830bdd5e9b7ce..8677c82716784 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -529,13 +529,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
-	ret = clk_prepare_enable(hdmi->vpll_clk);
-	if (ret) {
-		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
-			      ret);
-		return ret;
-	}
-
 	hdmi->phy = devm_phy_optional_get(dev, "hdmi");
 	if (IS_ERR(hdmi->phy)) {
 		ret = PTR_ERR(hdmi->phy);
@@ -544,6 +537,13 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	ret = clk_prepare_enable(hdmi->vpll_clk);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+			      ret);
+		return ret;
+	}
+
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 
-- 
2.30.2


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

* [PATCH 01/18] drm/rockchip: dw_hdmi: Do not leave clock enabled in error case
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

The driver returns an error when devm_phy_optional_get() fails leaving
the previously enabled clock turned on. Change order and enable the
clock only after the phy has been acquired.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 830bdd5e9b7ce..8677c82716784 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -529,13 +529,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
-	ret = clk_prepare_enable(hdmi->vpll_clk);
-	if (ret) {
-		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
-			      ret);
-		return ret;
-	}
-
 	hdmi->phy = devm_phy_optional_get(dev, "hdmi");
 	if (IS_ERR(hdmi->phy)) {
 		ret = PTR_ERR(hdmi->phy);
@@ -544,6 +537,13 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	ret = clk_prepare_enable(hdmi->vpll_clk);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+			      ret);
+		return ret;
+	}
+
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 
-- 
2.30.2


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

* [PATCH 01/18] drm/rockchip: dw_hdmi: Do not leave clock enabled in error case
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The driver returns an error when devm_phy_optional_get() fails leaving
the previously enabled clock turned on. Change order and enable the
clock only after the phy has been acquired.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 830bdd5e9b7ce..8677c82716784 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -529,13 +529,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
-	ret = clk_prepare_enable(hdmi->vpll_clk);
-	if (ret) {
-		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
-			      ret);
-		return ret;
-	}
-
 	hdmi->phy = devm_phy_optional_get(dev, "hdmi");
 	if (IS_ERR(hdmi->phy)) {
 		ret = PTR_ERR(hdmi->phy);
@@ -544,6 +537,13 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	ret = clk_prepare_enable(hdmi->vpll_clk);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+			      ret);
+		return ret;
+	}
+
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 01/18] drm/rockchip: dw_hdmi: Do not leave clock enabled in error case
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The driver returns an error when devm_phy_optional_get() fails leaving
the previously enabled clock turned on. Change order and enable the
clock only after the phy has been acquired.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 830bdd5e9b7ce..8677c82716784 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -529,13 +529,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
-	ret = clk_prepare_enable(hdmi->vpll_clk);
-	if (ret) {
-		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
-			      ret);
-		return ret;
-	}
-
 	hdmi->phy = devm_phy_optional_get(dev, "hdmi");
 	if (IS_ERR(hdmi->phy)) {
 		ret = PTR_ERR(hdmi->phy);
@@ -544,6 +537,13 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	ret = clk_prepare_enable(hdmi->vpll_clk);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+			      ret);
+		return ret;
+	}
+
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 02/18] drm/rockchip: dw_hdmi: rename vpll clock to reference clock
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

"vpll" is a misnomer. A clock input to a device should be named after
the usage in the device, not after the clock that drives it. On the
rk3568 the same clock is driven by the HPLL.
To fix that, this patch renames the vpll clock to ref clock. The clock
name "vpll" is left for compatibility to old device trees.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 29 ++++++++++++---------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 8677c82716784..e352e0404f772 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -69,7 +69,7 @@ struct rockchip_hdmi {
 	struct regmap *regmap;
 	struct drm_encoder encoder;
 	const struct rockchip_hdmi_chip_data *chip_data;
-	struct clk *vpll_clk;
+	struct clk *ref_clk;
 	struct clk *grf_clk;
 	struct dw_hdmi *hdmi;
 	struct phy *phy;
@@ -196,14 +196,17 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 		return PTR_ERR(hdmi->regmap);
 	}
 
-	hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll");
-	if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) {
-		hdmi->vpll_clk = NULL;
-	} else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) {
+	hdmi->ref_clk = devm_clk_get(hdmi->dev, "ref");
+	if (PTR_ERR(hdmi->ref_clk) == -ENOENT)
+		hdmi->ref_clk = devm_clk_get(hdmi->dev, "vpll");
+
+	if (PTR_ERR(hdmi->ref_clk) == -ENOENT) {
+		hdmi->ref_clk = NULL;
+	} else if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) {
 		return -EPROBE_DEFER;
-	} else if (IS_ERR(hdmi->vpll_clk)) {
-		DRM_DEV_ERROR(hdmi->dev, "failed to get vpll clock\n");
-		return PTR_ERR(hdmi->vpll_clk);
+	} else if (IS_ERR(hdmi->ref_clk)) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to get reference clock\n");
+		return PTR_ERR(hdmi->ref_clk);
 	}
 
 	hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf");
@@ -257,7 +260,7 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
 {
 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
 
-	clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000);
+	clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000);
 }
 
 static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
@@ -537,9 +540,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
-	ret = clk_prepare_enable(hdmi->vpll_clk);
+	ret = clk_prepare_enable(hdmi->ref_clk);
 	if (ret) {
-		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
 			      ret);
 		return ret;
 	}
@@ -558,7 +561,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	if (IS_ERR(hdmi->hdmi)) {
 		ret = PTR_ERR(hdmi->hdmi);
 		drm_encoder_cleanup(encoder);
-		clk_disable_unprepare(hdmi->vpll_clk);
+		clk_disable_unprepare(hdmi->ref_clk);
 	}
 
 	return ret;
@@ -570,7 +573,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
 
 	dw_hdmi_unbind(hdmi->hdmi);
-	clk_disable_unprepare(hdmi->vpll_clk);
+	clk_disable_unprepare(hdmi->ref_clk);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
-- 
2.30.2


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

* [PATCH 02/18] drm/rockchip: dw_hdmi: rename vpll clock to reference clock
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

"vpll" is a misnomer. A clock input to a device should be named after
the usage in the device, not after the clock that drives it. On the
rk3568 the same clock is driven by the HPLL.
To fix that, this patch renames the vpll clock to ref clock. The clock
name "vpll" is left for compatibility to old device trees.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 29 ++++++++++++---------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 8677c82716784..e352e0404f772 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -69,7 +69,7 @@ struct rockchip_hdmi {
 	struct regmap *regmap;
 	struct drm_encoder encoder;
 	const struct rockchip_hdmi_chip_data *chip_data;
-	struct clk *vpll_clk;
+	struct clk *ref_clk;
 	struct clk *grf_clk;
 	struct dw_hdmi *hdmi;
 	struct phy *phy;
@@ -196,14 +196,17 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 		return PTR_ERR(hdmi->regmap);
 	}
 
-	hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll");
-	if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) {
-		hdmi->vpll_clk = NULL;
-	} else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) {
+	hdmi->ref_clk = devm_clk_get(hdmi->dev, "ref");
+	if (PTR_ERR(hdmi->ref_clk) == -ENOENT)
+		hdmi->ref_clk = devm_clk_get(hdmi->dev, "vpll");
+
+	if (PTR_ERR(hdmi->ref_clk) == -ENOENT) {
+		hdmi->ref_clk = NULL;
+	} else if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) {
 		return -EPROBE_DEFER;
-	} else if (IS_ERR(hdmi->vpll_clk)) {
-		DRM_DEV_ERROR(hdmi->dev, "failed to get vpll clock\n");
-		return PTR_ERR(hdmi->vpll_clk);
+	} else if (IS_ERR(hdmi->ref_clk)) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to get reference clock\n");
+		return PTR_ERR(hdmi->ref_clk);
 	}
 
 	hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf");
@@ -257,7 +260,7 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
 {
 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
 
-	clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000);
+	clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000);
 }
 
 static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
@@ -537,9 +540,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
-	ret = clk_prepare_enable(hdmi->vpll_clk);
+	ret = clk_prepare_enable(hdmi->ref_clk);
 	if (ret) {
-		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
 			      ret);
 		return ret;
 	}
@@ -558,7 +561,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	if (IS_ERR(hdmi->hdmi)) {
 		ret = PTR_ERR(hdmi->hdmi);
 		drm_encoder_cleanup(encoder);
-		clk_disable_unprepare(hdmi->vpll_clk);
+		clk_disable_unprepare(hdmi->ref_clk);
 	}
 
 	return ret;
@@ -570,7 +573,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
 
 	dw_hdmi_unbind(hdmi->hdmi);
-	clk_disable_unprepare(hdmi->vpll_clk);
+	clk_disable_unprepare(hdmi->ref_clk);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
-- 
2.30.2


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

* [PATCH 02/18] drm/rockchip: dw_hdmi: rename vpll clock to reference clock
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

"vpll" is a misnomer. A clock input to a device should be named after
the usage in the device, not after the clock that drives it. On the
rk3568 the same clock is driven by the HPLL.
To fix that, this patch renames the vpll clock to ref clock. The clock
name "vpll" is left for compatibility to old device trees.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 29 ++++++++++++---------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 8677c82716784..e352e0404f772 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -69,7 +69,7 @@ struct rockchip_hdmi {
 	struct regmap *regmap;
 	struct drm_encoder encoder;
 	const struct rockchip_hdmi_chip_data *chip_data;
-	struct clk *vpll_clk;
+	struct clk *ref_clk;
 	struct clk *grf_clk;
 	struct dw_hdmi *hdmi;
 	struct phy *phy;
@@ -196,14 +196,17 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 		return PTR_ERR(hdmi->regmap);
 	}
 
-	hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll");
-	if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) {
-		hdmi->vpll_clk = NULL;
-	} else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) {
+	hdmi->ref_clk = devm_clk_get(hdmi->dev, "ref");
+	if (PTR_ERR(hdmi->ref_clk) == -ENOENT)
+		hdmi->ref_clk = devm_clk_get(hdmi->dev, "vpll");
+
+	if (PTR_ERR(hdmi->ref_clk) == -ENOENT) {
+		hdmi->ref_clk = NULL;
+	} else if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) {
 		return -EPROBE_DEFER;
-	} else if (IS_ERR(hdmi->vpll_clk)) {
-		DRM_DEV_ERROR(hdmi->dev, "failed to get vpll clock\n");
-		return PTR_ERR(hdmi->vpll_clk);
+	} else if (IS_ERR(hdmi->ref_clk)) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to get reference clock\n");
+		return PTR_ERR(hdmi->ref_clk);
 	}
 
 	hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf");
@@ -257,7 +260,7 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
 {
 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
 
-	clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000);
+	clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000);
 }
 
 static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
@@ -537,9 +540,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
-	ret = clk_prepare_enable(hdmi->vpll_clk);
+	ret = clk_prepare_enable(hdmi->ref_clk);
 	if (ret) {
-		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
 			      ret);
 		return ret;
 	}
@@ -558,7 +561,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	if (IS_ERR(hdmi->hdmi)) {
 		ret = PTR_ERR(hdmi->hdmi);
 		drm_encoder_cleanup(encoder);
-		clk_disable_unprepare(hdmi->vpll_clk);
+		clk_disable_unprepare(hdmi->ref_clk);
 	}
 
 	return ret;
@@ -570,7 +573,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
 
 	dw_hdmi_unbind(hdmi->hdmi);
-	clk_disable_unprepare(hdmi->vpll_clk);
+	clk_disable_unprepare(hdmi->ref_clk);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 02/18] drm/rockchip: dw_hdmi: rename vpll clock to reference clock
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

"vpll" is a misnomer. A clock input to a device should be named after
the usage in the device, not after the clock that drives it. On the
rk3568 the same clock is driven by the HPLL.
To fix that, this patch renames the vpll clock to ref clock. The clock
name "vpll" is left for compatibility to old device trees.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 29 ++++++++++++---------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 8677c82716784..e352e0404f772 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -69,7 +69,7 @@ struct rockchip_hdmi {
 	struct regmap *regmap;
 	struct drm_encoder encoder;
 	const struct rockchip_hdmi_chip_data *chip_data;
-	struct clk *vpll_clk;
+	struct clk *ref_clk;
 	struct clk *grf_clk;
 	struct dw_hdmi *hdmi;
 	struct phy *phy;
@@ -196,14 +196,17 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 		return PTR_ERR(hdmi->regmap);
 	}
 
-	hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll");
-	if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) {
-		hdmi->vpll_clk = NULL;
-	} else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) {
+	hdmi->ref_clk = devm_clk_get(hdmi->dev, "ref");
+	if (PTR_ERR(hdmi->ref_clk) == -ENOENT)
+		hdmi->ref_clk = devm_clk_get(hdmi->dev, "vpll");
+
+	if (PTR_ERR(hdmi->ref_clk) == -ENOENT) {
+		hdmi->ref_clk = NULL;
+	} else if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) {
 		return -EPROBE_DEFER;
-	} else if (IS_ERR(hdmi->vpll_clk)) {
-		DRM_DEV_ERROR(hdmi->dev, "failed to get vpll clock\n");
-		return PTR_ERR(hdmi->vpll_clk);
+	} else if (IS_ERR(hdmi->ref_clk)) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to get reference clock\n");
+		return PTR_ERR(hdmi->ref_clk);
 	}
 
 	hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf");
@@ -257,7 +260,7 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
 {
 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
 
-	clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000);
+	clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000);
 }
 
 static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
@@ -537,9 +540,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
-	ret = clk_prepare_enable(hdmi->vpll_clk);
+	ret = clk_prepare_enable(hdmi->ref_clk);
 	if (ret) {
-		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
 			      ret);
 		return ret;
 	}
@@ -558,7 +561,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	if (IS_ERR(hdmi->hdmi)) {
 		ret = PTR_ERR(hdmi->hdmi);
 		drm_encoder_cleanup(encoder);
-		clk_disable_unprepare(hdmi->vpll_clk);
+		clk_disable_unprepare(hdmi->ref_clk);
 	}
 
 	return ret;
@@ -570,7 +573,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
 
 	dw_hdmi_unbind(hdmi->hdmi);
-	clk_disable_unprepare(hdmi->vpll_clk);
+	clk_disable_unprepare(hdmi->ref_clk);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 03/18] drm/rockchip: dw_hdmi: add rk3568 support
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Add a new dw_hdmi_plat_data struct and new compatible for rk3568.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 31 +++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index e352e0404f772..262eef614cb12 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -50,6 +50,10 @@
 #define RK3399_GRF_SOC_CON20		0x6250
 #define RK3399_HDMI_LCDC_SEL		BIT(6)
 
+#define RK3568_GRF_VO_CON1		0x0364
+#define RK3568_HDMI_SDAIN_MSK		BIT(15)
+#define RK3568_HDMI_SCLIN_MSK		BIT(14)
+
 #define HIWORD_UPDATE(val, mask)	(val | (mask) << 16)
 
 /**
@@ -470,6 +474,19 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
 	.use_drm_infoframe = true,
 };
 
+static struct rockchip_hdmi_chip_data rk3568_chip_data = {
+	.lcdsel_grf_reg = -1,
+};
+
+static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = {
+	.mode_valid = dw_hdmi_rockchip_mode_valid,
+	.mpll_cfg   = rockchip_mpll_cfg,
+	.cur_ctr    = rockchip_cur_ctr,
+	.phy_config = rockchip_phy_config,
+	.phy_data = &rk3568_chip_data,
+	.use_drm_infoframe = true,
+};
+
 static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
 	{ .compatible = "rockchip,rk3228-dw-hdmi",
 	  .data = &rk3228_hdmi_drv_data
@@ -483,6 +500,9 @@ static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
 	{ .compatible = "rockchip,rk3399-dw-hdmi",
 	  .data = &rk3399_hdmi_drv_data
 	},
+	{ .compatible = "rockchip,rk3568-dw-hdmi",
+	  .data = &rk3568_hdmi_drv_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
@@ -517,6 +537,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	encoder = &hdmi->encoder;
 
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+	encoder->port = of_graph_get_port_by_id(dev->of_node, 0);
+
 	/*
 	 * If we failed to find the CRTC(s) which this encoder is
 	 * supposed to be connected to, it's because the CRTC has
@@ -547,6 +570,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	if (hdmi->chip_data == &rk3568_chip_data) {
+		regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1,
+			     HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK |
+					   RK3568_HDMI_SCLIN_MSK,
+					   RK3568_HDMI_SDAIN_MSK |
+					   RK3568_HDMI_SCLIN_MSK));
+	}
+
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 
-- 
2.30.2


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

* [PATCH 03/18] drm/rockchip: dw_hdmi: add rk3568 support
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

Add a new dw_hdmi_plat_data struct and new compatible for rk3568.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 31 +++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index e352e0404f772..262eef614cb12 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -50,6 +50,10 @@
 #define RK3399_GRF_SOC_CON20		0x6250
 #define RK3399_HDMI_LCDC_SEL		BIT(6)
 
+#define RK3568_GRF_VO_CON1		0x0364
+#define RK3568_HDMI_SDAIN_MSK		BIT(15)
+#define RK3568_HDMI_SCLIN_MSK		BIT(14)
+
 #define HIWORD_UPDATE(val, mask)	(val | (mask) << 16)
 
 /**
@@ -470,6 +474,19 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
 	.use_drm_infoframe = true,
 };
 
+static struct rockchip_hdmi_chip_data rk3568_chip_data = {
+	.lcdsel_grf_reg = -1,
+};
+
+static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = {
+	.mode_valid = dw_hdmi_rockchip_mode_valid,
+	.mpll_cfg   = rockchip_mpll_cfg,
+	.cur_ctr    = rockchip_cur_ctr,
+	.phy_config = rockchip_phy_config,
+	.phy_data = &rk3568_chip_data,
+	.use_drm_infoframe = true,
+};
+
 static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
 	{ .compatible = "rockchip,rk3228-dw-hdmi",
 	  .data = &rk3228_hdmi_drv_data
@@ -483,6 +500,9 @@ static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
 	{ .compatible = "rockchip,rk3399-dw-hdmi",
 	  .data = &rk3399_hdmi_drv_data
 	},
+	{ .compatible = "rockchip,rk3568-dw-hdmi",
+	  .data = &rk3568_hdmi_drv_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
@@ -517,6 +537,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	encoder = &hdmi->encoder;
 
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+	encoder->port = of_graph_get_port_by_id(dev->of_node, 0);
+
 	/*
 	 * If we failed to find the CRTC(s) which this encoder is
 	 * supposed to be connected to, it's because the CRTC has
@@ -547,6 +570,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	if (hdmi->chip_data == &rk3568_chip_data) {
+		regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1,
+			     HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK |
+					   RK3568_HDMI_SCLIN_MSK,
+					   RK3568_HDMI_SDAIN_MSK |
+					   RK3568_HDMI_SCLIN_MSK));
+	}
+
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 
-- 
2.30.2


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

* [PATCH 03/18] drm/rockchip: dw_hdmi: add rk3568 support
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Add a new dw_hdmi_plat_data struct and new compatible for rk3568.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 31 +++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index e352e0404f772..262eef614cb12 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -50,6 +50,10 @@
 #define RK3399_GRF_SOC_CON20		0x6250
 #define RK3399_HDMI_LCDC_SEL		BIT(6)
 
+#define RK3568_GRF_VO_CON1		0x0364
+#define RK3568_HDMI_SDAIN_MSK		BIT(15)
+#define RK3568_HDMI_SCLIN_MSK		BIT(14)
+
 #define HIWORD_UPDATE(val, mask)	(val | (mask) << 16)
 
 /**
@@ -470,6 +474,19 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
 	.use_drm_infoframe = true,
 };
 
+static struct rockchip_hdmi_chip_data rk3568_chip_data = {
+	.lcdsel_grf_reg = -1,
+};
+
+static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = {
+	.mode_valid = dw_hdmi_rockchip_mode_valid,
+	.mpll_cfg   = rockchip_mpll_cfg,
+	.cur_ctr    = rockchip_cur_ctr,
+	.phy_config = rockchip_phy_config,
+	.phy_data = &rk3568_chip_data,
+	.use_drm_infoframe = true,
+};
+
 static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
 	{ .compatible = "rockchip,rk3228-dw-hdmi",
 	  .data = &rk3228_hdmi_drv_data
@@ -483,6 +500,9 @@ static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
 	{ .compatible = "rockchip,rk3399-dw-hdmi",
 	  .data = &rk3399_hdmi_drv_data
 	},
+	{ .compatible = "rockchip,rk3568-dw-hdmi",
+	  .data = &rk3568_hdmi_drv_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
@@ -517,6 +537,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	encoder = &hdmi->encoder;
 
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+	encoder->port = of_graph_get_port_by_id(dev->of_node, 0);
+
 	/*
 	 * If we failed to find the CRTC(s) which this encoder is
 	 * supposed to be connected to, it's because the CRTC has
@@ -547,6 +570,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	if (hdmi->chip_data == &rk3568_chip_data) {
+		regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1,
+			     HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK |
+					   RK3568_HDMI_SCLIN_MSK,
+					   RK3568_HDMI_SDAIN_MSK |
+					   RK3568_HDMI_SCLIN_MSK));
+	}
+
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 03/18] drm/rockchip: dw_hdmi: add rk3568 support
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Add a new dw_hdmi_plat_data struct and new compatible for rk3568.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 31 +++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index e352e0404f772..262eef614cb12 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -50,6 +50,10 @@
 #define RK3399_GRF_SOC_CON20		0x6250
 #define RK3399_HDMI_LCDC_SEL		BIT(6)
 
+#define RK3568_GRF_VO_CON1		0x0364
+#define RK3568_HDMI_SDAIN_MSK		BIT(15)
+#define RK3568_HDMI_SCLIN_MSK		BIT(14)
+
 #define HIWORD_UPDATE(val, mask)	(val | (mask) << 16)
 
 /**
@@ -470,6 +474,19 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
 	.use_drm_infoframe = true,
 };
 
+static struct rockchip_hdmi_chip_data rk3568_chip_data = {
+	.lcdsel_grf_reg = -1,
+};
+
+static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = {
+	.mode_valid = dw_hdmi_rockchip_mode_valid,
+	.mpll_cfg   = rockchip_mpll_cfg,
+	.cur_ctr    = rockchip_cur_ctr,
+	.phy_config = rockchip_phy_config,
+	.phy_data = &rk3568_chip_data,
+	.use_drm_infoframe = true,
+};
+
 static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
 	{ .compatible = "rockchip,rk3228-dw-hdmi",
 	  .data = &rk3228_hdmi_drv_data
@@ -483,6 +500,9 @@ static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
 	{ .compatible = "rockchip,rk3399-dw-hdmi",
 	  .data = &rk3399_hdmi_drv_data
 	},
+	{ .compatible = "rockchip,rk3568-dw-hdmi",
+	  .data = &rk3568_hdmi_drv_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
@@ -517,6 +537,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	encoder = &hdmi->encoder;
 
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+	encoder->port = of_graph_get_port_by_id(dev->of_node, 0);
+
 	/*
 	 * If we failed to find the CRTC(s) which this encoder is
 	 * supposed to be connected to, it's because the CRTC has
@@ -547,6 +570,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	if (hdmi->chip_data == &rk3568_chip_data) {
+		regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1,
+			     HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK |
+					   RK3568_HDMI_SCLIN_MSK,
+					   RK3568_HDMI_SDAIN_MSK |
+					   RK3568_HDMI_SCLIN_MSK));
+	}
+
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 04/18] drm/rockchip: dw_hdmi: add regulator support
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The RK3568 has HDMI_TX_AVDD0V9 and HDMI_TX_AVDD_1V8 supply inputs needed
for the HDMI port. add support for these to the driver for boards which
have them supplied by switchable regulators.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++--
 1 file changed, 38 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 262eef614cb12..3d7c3f6fdf223 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -9,6 +9,7 @@
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 
 #include <drm/bridge/dw_hdmi.h>
 #include <drm/drm_edid.h>
@@ -76,6 +77,8 @@ struct rockchip_hdmi {
 	struct clk *ref_clk;
 	struct clk *grf_clk;
 	struct dw_hdmi *hdmi;
+	struct regulator *avdd_0v9;
+	struct regulator *avdd_1v8;
 	struct phy *phy;
 };
 
@@ -223,6 +226,14 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 		return PTR_ERR(hdmi->grf_clk);
 	}
 
+	hdmi->avdd_0v9 = devm_regulator_get(hdmi->dev, "avdd-0v9");
+	if (IS_ERR(hdmi->avdd_0v9))
+		return PTR_ERR(hdmi->avdd_0v9);
+
+	hdmi->avdd_1v8 = devm_regulator_get(hdmi->dev, "avdd-1v8");
+	if (IS_ERR(hdmi->avdd_1v8))
+		return PTR_ERR(hdmi->avdd_1v8);
+
 	return 0;
 }
 
@@ -563,11 +574,23 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	ret = regulator_enable(hdmi->avdd_0v9);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd0v9: %d\n", ret);
+		goto err_avdd_0v9;
+	}
+
+	ret = regulator_enable(hdmi->avdd_1v8);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd1v8: %d\n", ret);
+		goto err_avdd_1v8;
+	}
+
 	ret = clk_prepare_enable(hdmi->ref_clk);
 	if (ret) {
 		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
 			      ret);
-		return ret;
+		goto err_clk;
 	}
 
 	if (hdmi->chip_data == &rk3568_chip_data) {
@@ -591,10 +614,19 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	 */
 	if (IS_ERR(hdmi->hdmi)) {
 		ret = PTR_ERR(hdmi->hdmi);
-		drm_encoder_cleanup(encoder);
-		clk_disable_unprepare(hdmi->ref_clk);
+		goto err_bind;
 	}
 
+	return 0;
+
+err_bind:
+	clk_disable_unprepare(hdmi->ref_clk);
+	drm_encoder_cleanup(encoder);
+err_clk:
+	regulator_disable(hdmi->avdd_1v8);
+err_avdd_1v8:
+	regulator_disable(hdmi->avdd_0v9);
+err_avdd_0v9:
 	return ret;
 }
 
@@ -605,6 +637,9 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 
 	dw_hdmi_unbind(hdmi->hdmi);
 	clk_disable_unprepare(hdmi->ref_clk);
+
+	regulator_disable(hdmi->avdd_1v8);
+	regulator_disable(hdmi->avdd_0v9);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
-- 
2.30.2


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

* [PATCH 04/18] drm/rockchip: dw_hdmi: add regulator support
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

The RK3568 has HDMI_TX_AVDD0V9 and HDMI_TX_AVDD_1V8 supply inputs needed
for the HDMI port. add support for these to the driver for boards which
have them supplied by switchable regulators.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++--
 1 file changed, 38 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 262eef614cb12..3d7c3f6fdf223 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -9,6 +9,7 @@
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 
 #include <drm/bridge/dw_hdmi.h>
 #include <drm/drm_edid.h>
@@ -76,6 +77,8 @@ struct rockchip_hdmi {
 	struct clk *ref_clk;
 	struct clk *grf_clk;
 	struct dw_hdmi *hdmi;
+	struct regulator *avdd_0v9;
+	struct regulator *avdd_1v8;
 	struct phy *phy;
 };
 
@@ -223,6 +226,14 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 		return PTR_ERR(hdmi->grf_clk);
 	}
 
+	hdmi->avdd_0v9 = devm_regulator_get(hdmi->dev, "avdd-0v9");
+	if (IS_ERR(hdmi->avdd_0v9))
+		return PTR_ERR(hdmi->avdd_0v9);
+
+	hdmi->avdd_1v8 = devm_regulator_get(hdmi->dev, "avdd-1v8");
+	if (IS_ERR(hdmi->avdd_1v8))
+		return PTR_ERR(hdmi->avdd_1v8);
+
 	return 0;
 }
 
@@ -563,11 +574,23 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	ret = regulator_enable(hdmi->avdd_0v9);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd0v9: %d\n", ret);
+		goto err_avdd_0v9;
+	}
+
+	ret = regulator_enable(hdmi->avdd_1v8);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd1v8: %d\n", ret);
+		goto err_avdd_1v8;
+	}
+
 	ret = clk_prepare_enable(hdmi->ref_clk);
 	if (ret) {
 		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
 			      ret);
-		return ret;
+		goto err_clk;
 	}
 
 	if (hdmi->chip_data == &rk3568_chip_data) {
@@ -591,10 +614,19 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	 */
 	if (IS_ERR(hdmi->hdmi)) {
 		ret = PTR_ERR(hdmi->hdmi);
-		drm_encoder_cleanup(encoder);
-		clk_disable_unprepare(hdmi->ref_clk);
+		goto err_bind;
 	}
 
+	return 0;
+
+err_bind:
+	clk_disable_unprepare(hdmi->ref_clk);
+	drm_encoder_cleanup(encoder);
+err_clk:
+	regulator_disable(hdmi->avdd_1v8);
+err_avdd_1v8:
+	regulator_disable(hdmi->avdd_0v9);
+err_avdd_0v9:
 	return ret;
 }
 
@@ -605,6 +637,9 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 
 	dw_hdmi_unbind(hdmi->hdmi);
 	clk_disable_unprepare(hdmi->ref_clk);
+
+	regulator_disable(hdmi->avdd_1v8);
+	regulator_disable(hdmi->avdd_0v9);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
-- 
2.30.2


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

* [PATCH 04/18] drm/rockchip: dw_hdmi: add regulator support
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The RK3568 has HDMI_TX_AVDD0V9 and HDMI_TX_AVDD_1V8 supply inputs needed
for the HDMI port. add support for these to the driver for boards which
have them supplied by switchable regulators.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++--
 1 file changed, 38 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 262eef614cb12..3d7c3f6fdf223 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -9,6 +9,7 @@
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 
 #include <drm/bridge/dw_hdmi.h>
 #include <drm/drm_edid.h>
@@ -76,6 +77,8 @@ struct rockchip_hdmi {
 	struct clk *ref_clk;
 	struct clk *grf_clk;
 	struct dw_hdmi *hdmi;
+	struct regulator *avdd_0v9;
+	struct regulator *avdd_1v8;
 	struct phy *phy;
 };
 
@@ -223,6 +226,14 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 		return PTR_ERR(hdmi->grf_clk);
 	}
 
+	hdmi->avdd_0v9 = devm_regulator_get(hdmi->dev, "avdd-0v9");
+	if (IS_ERR(hdmi->avdd_0v9))
+		return PTR_ERR(hdmi->avdd_0v9);
+
+	hdmi->avdd_1v8 = devm_regulator_get(hdmi->dev, "avdd-1v8");
+	if (IS_ERR(hdmi->avdd_1v8))
+		return PTR_ERR(hdmi->avdd_1v8);
+
 	return 0;
 }
 
@@ -563,11 +574,23 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	ret = regulator_enable(hdmi->avdd_0v9);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd0v9: %d\n", ret);
+		goto err_avdd_0v9;
+	}
+
+	ret = regulator_enable(hdmi->avdd_1v8);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd1v8: %d\n", ret);
+		goto err_avdd_1v8;
+	}
+
 	ret = clk_prepare_enable(hdmi->ref_clk);
 	if (ret) {
 		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
 			      ret);
-		return ret;
+		goto err_clk;
 	}
 
 	if (hdmi->chip_data == &rk3568_chip_data) {
@@ -591,10 +614,19 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	 */
 	if (IS_ERR(hdmi->hdmi)) {
 		ret = PTR_ERR(hdmi->hdmi);
-		drm_encoder_cleanup(encoder);
-		clk_disable_unprepare(hdmi->ref_clk);
+		goto err_bind;
 	}
 
+	return 0;
+
+err_bind:
+	clk_disable_unprepare(hdmi->ref_clk);
+	drm_encoder_cleanup(encoder);
+err_clk:
+	regulator_disable(hdmi->avdd_1v8);
+err_avdd_1v8:
+	regulator_disable(hdmi->avdd_0v9);
+err_avdd_0v9:
 	return ret;
 }
 
@@ -605,6 +637,9 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 
 	dw_hdmi_unbind(hdmi->hdmi);
 	clk_disable_unprepare(hdmi->ref_clk);
+
+	regulator_disable(hdmi->avdd_1v8);
+	regulator_disable(hdmi->avdd_0v9);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 04/18] drm/rockchip: dw_hdmi: add regulator support
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The RK3568 has HDMI_TX_AVDD0V9 and HDMI_TX_AVDD_1V8 supply inputs needed
for the HDMI port. add support for these to the driver for boards which
have them supplied by switchable regulators.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++--
 1 file changed, 38 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 262eef614cb12..3d7c3f6fdf223 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -9,6 +9,7 @@
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 
 #include <drm/bridge/dw_hdmi.h>
 #include <drm/drm_edid.h>
@@ -76,6 +77,8 @@ struct rockchip_hdmi {
 	struct clk *ref_clk;
 	struct clk *grf_clk;
 	struct dw_hdmi *hdmi;
+	struct regulator *avdd_0v9;
+	struct regulator *avdd_1v8;
 	struct phy *phy;
 };
 
@@ -223,6 +226,14 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 		return PTR_ERR(hdmi->grf_clk);
 	}
 
+	hdmi->avdd_0v9 = devm_regulator_get(hdmi->dev, "avdd-0v9");
+	if (IS_ERR(hdmi->avdd_0v9))
+		return PTR_ERR(hdmi->avdd_0v9);
+
+	hdmi->avdd_1v8 = devm_regulator_get(hdmi->dev, "avdd-1v8");
+	if (IS_ERR(hdmi->avdd_1v8))
+		return PTR_ERR(hdmi->avdd_1v8);
+
 	return 0;
 }
 
@@ -563,11 +574,23 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	ret = regulator_enable(hdmi->avdd_0v9);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd0v9: %d\n", ret);
+		goto err_avdd_0v9;
+	}
+
+	ret = regulator_enable(hdmi->avdd_1v8);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd1v8: %d\n", ret);
+		goto err_avdd_1v8;
+	}
+
 	ret = clk_prepare_enable(hdmi->ref_clk);
 	if (ret) {
 		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
 			      ret);
-		return ret;
+		goto err_clk;
 	}
 
 	if (hdmi->chip_data == &rk3568_chip_data) {
@@ -591,10 +614,19 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	 */
 	if (IS_ERR(hdmi->hdmi)) {
 		ret = PTR_ERR(hdmi->hdmi);
-		drm_encoder_cleanup(encoder);
-		clk_disable_unprepare(hdmi->ref_clk);
+		goto err_bind;
 	}
 
+	return 0;
+
+err_bind:
+	clk_disable_unprepare(hdmi->ref_clk);
+	drm_encoder_cleanup(encoder);
+err_clk:
+	regulator_disable(hdmi->avdd_1v8);
+err_avdd_1v8:
+	regulator_disable(hdmi->avdd_0v9);
+err_avdd_0v9:
 	return ret;
 }
 
@@ -605,6 +637,9 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 
 	dw_hdmi_unbind(hdmi->hdmi);
 	clk_disable_unprepare(hdmi->ref_clk);
+
+	regulator_disable(hdmi->avdd_1v8);
+	regulator_disable(hdmi->avdd_0v9);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 05/18] dt-bindings: display: rockchip: dw-hdmi: Add compatible for rk3568 HDMI
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Rob Herring, Sascha Hauer

From: Benjamin Gaignard <benjamin.gaignard@collabora.com>

Define a new compatible for rk3568 HDMI.
This version of HDMI hardware block needs two new clocks hclk_vio and hclk
to provide phy reference clocks.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20210707120323.401785-2-benjamin.gaignard@collabora.com
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index da3b889ad8fcd..45cae4f57a1c1 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -23,6 +23,7 @@ properties:
       - rockchip,rk3288-dw-hdmi
       - rockchip,rk3328-dw-hdmi
       - rockchip,rk3399-dw-hdmi
+      - rockchip,rk3568-dw-hdmi
 
   reg-io-width:
     const: 4
-- 
2.30.2


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

* [PATCH 05/18] dt-bindings: display: rockchip: dw-hdmi: Add compatible for rk3568 HDMI
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

From: Benjamin Gaignard <benjamin.gaignard@collabora.com>

Define a new compatible for rk3568 HDMI.
This version of HDMI hardware block needs two new clocks hclk_vio and hclk
to provide phy reference clocks.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20210707120323.401785-2-benjamin.gaignard@collabora.com
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index da3b889ad8fcd..45cae4f57a1c1 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -23,6 +23,7 @@ properties:
       - rockchip,rk3288-dw-hdmi
       - rockchip,rk3328-dw-hdmi
       - rockchip,rk3399-dw-hdmi
+      - rockchip,rk3568-dw-hdmi
 
   reg-io-width:
     const: 4
-- 
2.30.2


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

* [PATCH 05/18] dt-bindings: display: rockchip: dw-hdmi: Add compatible for rk3568 HDMI
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Rob Herring, Sascha Hauer

From: Benjamin Gaignard <benjamin.gaignard@collabora.com>

Define a new compatible for rk3568 HDMI.
This version of HDMI hardware block needs two new clocks hclk_vio and hclk
to provide phy reference clocks.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20210707120323.401785-2-benjamin.gaignard@collabora.com
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index da3b889ad8fcd..45cae4f57a1c1 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -23,6 +23,7 @@ properties:
       - rockchip,rk3288-dw-hdmi
       - rockchip,rk3328-dw-hdmi
       - rockchip,rk3399-dw-hdmi
+      - rockchip,rk3568-dw-hdmi
 
   reg-io-width:
     const: 4
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 05/18] dt-bindings: display: rockchip: dw-hdmi: Add compatible for rk3568 HDMI
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Rob Herring, Sascha Hauer

From: Benjamin Gaignard <benjamin.gaignard@collabora.com>

Define a new compatible for rk3568 HDMI.
This version of HDMI hardware block needs two new clocks hclk_vio and hclk
to provide phy reference clocks.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20210707120323.401785-2-benjamin.gaignard@collabora.com
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index da3b889ad8fcd..45cae4f57a1c1 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -23,6 +23,7 @@ properties:
       - rockchip,rk3288-dw-hdmi
       - rockchip,rk3328-dw-hdmi
       - rockchip,rk3399-dw-hdmi
+      - rockchip,rk3568-dw-hdmi
 
   reg-io-width:
     const: 4
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 06/18] dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

None of the upstream device tree files has a "unwedge" pinctrl
specified. Make it optional.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 45cae4f57a1c1..6e09dd2ee05ac 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -73,6 +73,7 @@ properties:
       The unwedge pinctrl entry shall drive the DDC SDA line low. This is
       intended to work around a hardware errata that can cause the DDC I2C
       bus to be wedged.
+    minItems: 1
     items:
       - const: default
       - const: unwedge
-- 
2.30.2


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

* [PATCH 06/18] dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

None of the upstream device tree files has a "unwedge" pinctrl
specified. Make it optional.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 45cae4f57a1c1..6e09dd2ee05ac 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -73,6 +73,7 @@ properties:
       The unwedge pinctrl entry shall drive the DDC SDA line low. This is
       intended to work around a hardware errata that can cause the DDC I2C
       bus to be wedged.
+    minItems: 1
     items:
       - const: default
       - const: unwedge
-- 
2.30.2


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

* [PATCH 06/18] dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

None of the upstream device tree files has a "unwedge" pinctrl
specified. Make it optional.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 45cae4f57a1c1..6e09dd2ee05ac 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -73,6 +73,7 @@ properties:
       The unwedge pinctrl entry shall drive the DDC SDA line low. This is
       intended to work around a hardware errata that can cause the DDC I2C
       bus to be wedged.
+    minItems: 1
     items:
       - const: default
       - const: unwedge
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 06/18] dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

None of the upstream device tree files has a "unwedge" pinctrl
specified. Make it optional.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 45cae4f57a1c1..6e09dd2ee05ac 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -73,6 +73,7 @@ properties:
       The unwedge pinctrl entry shall drive the DDC SDA line low. This is
       intended to work around a hardware errata that can cause the DDC I2C
       bus to be wedged.
+    minItems: 1
     items:
       - const: default
       - const: unwedge
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

"vpll" is a misnomer. A clock input to a device should be named after
the usage in the device, not after the clock that drives it. On the
rk3568 the same clock is driven by the HPLL.
To fix that, this patch renames the vpll clock to ref clock.  The clock
name "vpll" is left for compatibility to old device trees.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 6e09dd2ee05ac..2ab6578033da2 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -48,10 +48,14 @@ properties:
           - cec
           - grf
           - vpll
+          - ref
       - enum:
           - grf
           - vpll
-      - const: vpll
+          - ref
+      - enum:
+          - vpll
+          - ref
 
   ddc-i2c-bus:
     $ref: /schemas/types.yaml#/definitions/phandle
-- 
2.30.2


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

* [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

"vpll" is a misnomer. A clock input to a device should be named after
the usage in the device, not after the clock that drives it. On the
rk3568 the same clock is driven by the HPLL.
To fix that, this patch renames the vpll clock to ref clock.  The clock
name "vpll" is left for compatibility to old device trees.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 6e09dd2ee05ac..2ab6578033da2 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -48,10 +48,14 @@ properties:
           - cec
           - grf
           - vpll
+          - ref
       - enum:
           - grf
           - vpll
-      - const: vpll
+          - ref
+      - enum:
+          - vpll
+          - ref
 
   ddc-i2c-bus:
     $ref: /schemas/types.yaml#/definitions/phandle
-- 
2.30.2


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

* [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

"vpll" is a misnomer. A clock input to a device should be named after
the usage in the device, not after the clock that drives it. On the
rk3568 the same clock is driven by the HPLL.
To fix that, this patch renames the vpll clock to ref clock.  The clock
name "vpll" is left for compatibility to old device trees.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 6e09dd2ee05ac..2ab6578033da2 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -48,10 +48,14 @@ properties:
           - cec
           - grf
           - vpll
+          - ref
       - enum:
           - grf
           - vpll
-      - const: vpll
+          - ref
+      - enum:
+          - vpll
+          - ref
 
   ddc-i2c-bus:
     $ref: /schemas/types.yaml#/definitions/phandle
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

"vpll" is a misnomer. A clock input to a device should be named after
the usage in the device, not after the clock that drives it. On the
rk3568 the same clock is driven by the HPLL.
To fix that, this patch renames the vpll clock to ref clock.  The clock
name "vpll" is left for compatibility to old device trees.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 6e09dd2ee05ac..2ab6578033da2 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -48,10 +48,14 @@ properties:
           - cec
           - grf
           - vpll
+          - ref
       - enum:
           - grf
           - vpll
-      - const: vpll
+          - ref
+      - enum:
+          - vpll
+          - ref
 
   ddc-i2c-bus:
     $ref: /schemas/types.yaml#/definitions/phandle
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 08/18] dt-bindings: display: rockchip: dw-hdmi: Add regulator support
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 2ab6578033da2..b9dca49aa6e05 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -28,6 +28,12 @@ properties:
   reg-io-width:
     const: 4
 
+  avdd-0v9-supply:
+    description: A 0.9V supply that powers up the SoC internal circuitry.
+
+  avdd-1v8-supply:
+    description: A 1.8V supply that powers up the SoC internal circuitry.
+
   clocks:
     minItems: 2
     items:
-- 
2.30.2


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

* [PATCH 08/18] dt-bindings: display: rockchip: dw-hdmi: Add regulator support
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 2ab6578033da2..b9dca49aa6e05 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -28,6 +28,12 @@ properties:
   reg-io-width:
     const: 4
 
+  avdd-0v9-supply:
+    description: A 0.9V supply that powers up the SoC internal circuitry.
+
+  avdd-1v8-supply:
+    description: A 1.8V supply that powers up the SoC internal circuitry.
+
   clocks:
     minItems: 2
     items:
-- 
2.30.2


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

* [PATCH 08/18] dt-bindings: display: rockchip: dw-hdmi: Add regulator support
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 2ab6578033da2..b9dca49aa6e05 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -28,6 +28,12 @@ properties:
   reg-io-width:
     const: 4
 
+  avdd-0v9-supply:
+    description: A 0.9V supply that powers up the SoC internal circuitry.
+
+  avdd-1v8-supply:
+    description: A 1.8V supply that powers up the SoC internal circuitry.
+
   clocks:
     minItems: 2
     items:
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 08/18] dt-bindings: display: rockchip: dw-hdmi: Add regulator support
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
index 2ab6578033da2..b9dca49aa6e05 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
@@ -28,6 +28,12 @@ properties:
   reg-io-width:
     const: 4
 
+  avdd-0v9-supply:
+    description: A 0.9V supply that powers up the SoC internal circuitry.
+
+  avdd-1v8-supply:
+    description: A 1.8V supply that powers up the SoC internal circuitry.
+
   clocks:
     minItems: 2
     items:
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 09/18] arm64: dts: rockchip: rk3399: reorder hmdi clocks
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The binding specifies the clock order to "cec", "grf", "vpll". Reorder
the clocks accordingly.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index d3cdf6f42a303..080457a68e3c7 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1881,10 +1881,10 @@ hdmi: hdmi@ff940000 {
 		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH 0>;
 		clocks = <&cru PCLK_HDMI_CTRL>,
 			 <&cru SCLK_HDMI_SFR>,
-			 <&cru PLL_VPLL>,
+			 <&cru SCLK_HDMI_CEC>,
 			 <&cru PCLK_VIO_GRF>,
-			 <&cru SCLK_HDMI_CEC>;
-		clock-names = "iahb", "isfr", "vpll", "grf", "cec";
+			 <&cru PLL_VPLL>;
+		clock-names = "iahb", "isfr", "cec", "grf", "vpll";
 		power-domains = <&power RK3399_PD_HDCP>;
 		reg-io-width = <4>;
 		rockchip,grf = <&grf>;
-- 
2.30.2


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

* [PATCH 09/18] arm64: dts: rockchip: rk3399: reorder hmdi clocks
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

The binding specifies the clock order to "cec", "grf", "vpll". Reorder
the clocks accordingly.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index d3cdf6f42a303..080457a68e3c7 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1881,10 +1881,10 @@ hdmi: hdmi@ff940000 {
 		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH 0>;
 		clocks = <&cru PCLK_HDMI_CTRL>,
 			 <&cru SCLK_HDMI_SFR>,
-			 <&cru PLL_VPLL>,
+			 <&cru SCLK_HDMI_CEC>,
 			 <&cru PCLK_VIO_GRF>,
-			 <&cru SCLK_HDMI_CEC>;
-		clock-names = "iahb", "isfr", "vpll", "grf", "cec";
+			 <&cru PLL_VPLL>;
+		clock-names = "iahb", "isfr", "cec", "grf", "vpll";
 		power-domains = <&power RK3399_PD_HDCP>;
 		reg-io-width = <4>;
 		rockchip,grf = <&grf>;
-- 
2.30.2


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

* [PATCH 09/18] arm64: dts: rockchip: rk3399: reorder hmdi clocks
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The binding specifies the clock order to "cec", "grf", "vpll". Reorder
the clocks accordingly.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index d3cdf6f42a303..080457a68e3c7 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1881,10 +1881,10 @@ hdmi: hdmi@ff940000 {
 		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH 0>;
 		clocks = <&cru PCLK_HDMI_CTRL>,
 			 <&cru SCLK_HDMI_SFR>,
-			 <&cru PLL_VPLL>,
+			 <&cru SCLK_HDMI_CEC>,
 			 <&cru PCLK_VIO_GRF>,
-			 <&cru SCLK_HDMI_CEC>;
-		clock-names = "iahb", "isfr", "vpll", "grf", "cec";
+			 <&cru PLL_VPLL>;
+		clock-names = "iahb", "isfr", "cec", "grf", "vpll";
 		power-domains = <&power RK3399_PD_HDCP>;
 		reg-io-width = <4>;
 		rockchip,grf = <&grf>;
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 09/18] arm64: dts: rockchip: rk3399: reorder hmdi clocks
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The binding specifies the clock order to "cec", "grf", "vpll". Reorder
the clocks accordingly.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index d3cdf6f42a303..080457a68e3c7 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1881,10 +1881,10 @@ hdmi: hdmi@ff940000 {
 		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH 0>;
 		clocks = <&cru PCLK_HDMI_CTRL>,
 			 <&cru SCLK_HDMI_SFR>,
-			 <&cru PLL_VPLL>,
+			 <&cru SCLK_HDMI_CEC>,
 			 <&cru PCLK_VIO_GRF>,
-			 <&cru SCLK_HDMI_CEC>;
-		clock-names = "iahb", "isfr", "vpll", "grf", "cec";
+			 <&cru PLL_VPLL>;
+		clock-names = "iahb", "isfr", "cec", "grf", "vpll";
 		power-domains = <&power RK3399_PD_HDCP>;
 		reg-io-width = <4>;
 		rockchip,grf = <&grf>;
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 10/18] dt-bindings: display: rockchip: Add binding for VOP2
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The VOP2 is found on newer Rockchip SoCs like the rk3568 or the rk3566.
The binding differs slightly from the existing VOP binding, so add a new
binding file for it.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../display/rockchip/rockchip-vop2.yaml       | 118 ++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
new file mode 100644
index 0000000000000..6533c4ae4ec3a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
@@ -0,0 +1,118 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/rockchip/rockchip-vop2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip SoC display controller (VOP2)
+
+description:
+  VOP2 (Video Output Processor v2) is the display controller for the Rockchip
+  series of SoCs which transfers the image data from a video memory
+  buffer to an external LCD interface.
+
+maintainers:
+  - Sandy Huang <hjc@rock-chips.com>
+  - Heiko Stuebner <heiko@sntech.de>
+
+properties:
+  compatible:
+    enum:
+      - rockchip,rk3566-vop
+      - rockchip,rk3568-vop
+
+  reg:
+    minItems: 1
+    items:
+      - description:
+          Must contain one entry corresponding to the base address and length
+          of the register space.
+      - description:
+          Can optionally contain a second entry corresponding to
+          the CRTC gamma LUT address.
+
+  interrupts:
+    maxItems: 1
+    description:
+      The VOP interrupt is shared by several interrupt sources, such as
+      frame start (VSYNC), line flag and other status interrupts.
+
+  clocks:
+    items:
+      - description: Clock for ddr buffer transfer.
+      - description: Clock for the ahb bus to R/W the phy regs.
+      - description: Pixel clock for video port 0.
+      - description: Pixel clock for video port 1.
+      - description: Pixel clock for video port 2.
+
+  clock-names:
+    items:
+      - const: aclk_vop
+      - const: hclk_vop
+      - const: dclk_vp0
+      - const: dclk_vp1
+      - const: dclk_vp2
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+
+  assigned-clocks:
+    maxItems: 2
+
+  assigned-clock-rates:
+    maxItems: 2
+
+  iommus:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+        #include <dt-bindings/clock/rk3568-cru.h>
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+        #include <dt-bindings/power/rk3568-power.h>
+        bus {
+            #address-cells = <2>;
+            #size-cells = <2>;
+            vop: vop@fe040000 {
+                compatible = "rockchip,rk3568-vop";
+                reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
+                interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&cru ACLK_VOP>,
+                         <&cru HCLK_VOP>,
+                         <&cru DCLK_VOP0>,
+                         <&cru DCLK_VOP1>,
+                         <&cru DCLK_VOP2>;
+                clock-names = "aclk_vop",
+                              "hclk_vop",
+                              "dclk_vp0",
+                              "dclk_vp1",
+                              "dclk_vp2";
+                power-domains = <&power RK3568_PD_VO>;
+                iommus = <&vop_mmu>;
+                vop_out: port {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+                    vp0_out_dsi0: endpoint@0 {
+                        reg = <0>;
+                        remote-endpoint = <&dsi0_in_vp0>;
+                    };
+                    vp0_out_hdmi: endpoint@1 {
+                        reg = <1>;
+                        remote-endpoint = <&hdmi0_in_vp0>;
+                    };
+                };
+            };
+        };
-- 
2.30.2


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

* [PATCH 10/18] dt-bindings: display: rockchip: Add binding for VOP2
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

The VOP2 is found on newer Rockchip SoCs like the rk3568 or the rk3566.
The binding differs slightly from the existing VOP binding, so add a new
binding file for it.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../display/rockchip/rockchip-vop2.yaml       | 118 ++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
new file mode 100644
index 0000000000000..6533c4ae4ec3a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
@@ -0,0 +1,118 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/rockchip/rockchip-vop2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip SoC display controller (VOP2)
+
+description:
+  VOP2 (Video Output Processor v2) is the display controller for the Rockchip
+  series of SoCs which transfers the image data from a video memory
+  buffer to an external LCD interface.
+
+maintainers:
+  - Sandy Huang <hjc@rock-chips.com>
+  - Heiko Stuebner <heiko@sntech.de>
+
+properties:
+  compatible:
+    enum:
+      - rockchip,rk3566-vop
+      - rockchip,rk3568-vop
+
+  reg:
+    minItems: 1
+    items:
+      - description:
+          Must contain one entry corresponding to the base address and length
+          of the register space.
+      - description:
+          Can optionally contain a second entry corresponding to
+          the CRTC gamma LUT address.
+
+  interrupts:
+    maxItems: 1
+    description:
+      The VOP interrupt is shared by several interrupt sources, such as
+      frame start (VSYNC), line flag and other status interrupts.
+
+  clocks:
+    items:
+      - description: Clock for ddr buffer transfer.
+      - description: Clock for the ahb bus to R/W the phy regs.
+      - description: Pixel clock for video port 0.
+      - description: Pixel clock for video port 1.
+      - description: Pixel clock for video port 2.
+
+  clock-names:
+    items:
+      - const: aclk_vop
+      - const: hclk_vop
+      - const: dclk_vp0
+      - const: dclk_vp1
+      - const: dclk_vp2
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+
+  assigned-clocks:
+    maxItems: 2
+
+  assigned-clock-rates:
+    maxItems: 2
+
+  iommus:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+        #include <dt-bindings/clock/rk3568-cru.h>
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+        #include <dt-bindings/power/rk3568-power.h>
+        bus {
+            #address-cells = <2>;
+            #size-cells = <2>;
+            vop: vop@fe040000 {
+                compatible = "rockchip,rk3568-vop";
+                reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
+                interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&cru ACLK_VOP>,
+                         <&cru HCLK_VOP>,
+                         <&cru DCLK_VOP0>,
+                         <&cru DCLK_VOP1>,
+                         <&cru DCLK_VOP2>;
+                clock-names = "aclk_vop",
+                              "hclk_vop",
+                              "dclk_vp0",
+                              "dclk_vp1",
+                              "dclk_vp2";
+                power-domains = <&power RK3568_PD_VO>;
+                iommus = <&vop_mmu>;
+                vop_out: port {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+                    vp0_out_dsi0: endpoint@0 {
+                        reg = <0>;
+                        remote-endpoint = <&dsi0_in_vp0>;
+                    };
+                    vp0_out_hdmi: endpoint@1 {
+                        reg = <1>;
+                        remote-endpoint = <&hdmi0_in_vp0>;
+                    };
+                };
+            };
+        };
-- 
2.30.2


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

* [PATCH 10/18] dt-bindings: display: rockchip: Add binding for VOP2
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The VOP2 is found on newer Rockchip SoCs like the rk3568 or the rk3566.
The binding differs slightly from the existing VOP binding, so add a new
binding file for it.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../display/rockchip/rockchip-vop2.yaml       | 118 ++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
new file mode 100644
index 0000000000000..6533c4ae4ec3a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
@@ -0,0 +1,118 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/rockchip/rockchip-vop2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip SoC display controller (VOP2)
+
+description:
+  VOP2 (Video Output Processor v2) is the display controller for the Rockchip
+  series of SoCs which transfers the image data from a video memory
+  buffer to an external LCD interface.
+
+maintainers:
+  - Sandy Huang <hjc@rock-chips.com>
+  - Heiko Stuebner <heiko@sntech.de>
+
+properties:
+  compatible:
+    enum:
+      - rockchip,rk3566-vop
+      - rockchip,rk3568-vop
+
+  reg:
+    minItems: 1
+    items:
+      - description:
+          Must contain one entry corresponding to the base address and length
+          of the register space.
+      - description:
+          Can optionally contain a second entry corresponding to
+          the CRTC gamma LUT address.
+
+  interrupts:
+    maxItems: 1
+    description:
+      The VOP interrupt is shared by several interrupt sources, such as
+      frame start (VSYNC), line flag and other status interrupts.
+
+  clocks:
+    items:
+      - description: Clock for ddr buffer transfer.
+      - description: Clock for the ahb bus to R/W the phy regs.
+      - description: Pixel clock for video port 0.
+      - description: Pixel clock for video port 1.
+      - description: Pixel clock for video port 2.
+
+  clock-names:
+    items:
+      - const: aclk_vop
+      - const: hclk_vop
+      - const: dclk_vp0
+      - const: dclk_vp1
+      - const: dclk_vp2
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+
+  assigned-clocks:
+    maxItems: 2
+
+  assigned-clock-rates:
+    maxItems: 2
+
+  iommus:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+        #include <dt-bindings/clock/rk3568-cru.h>
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+        #include <dt-bindings/power/rk3568-power.h>
+        bus {
+            #address-cells = <2>;
+            #size-cells = <2>;
+            vop: vop@fe040000 {
+                compatible = "rockchip,rk3568-vop";
+                reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
+                interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&cru ACLK_VOP>,
+                         <&cru HCLK_VOP>,
+                         <&cru DCLK_VOP0>,
+                         <&cru DCLK_VOP1>,
+                         <&cru DCLK_VOP2>;
+                clock-names = "aclk_vop",
+                              "hclk_vop",
+                              "dclk_vp0",
+                              "dclk_vp1",
+                              "dclk_vp2";
+                power-domains = <&power RK3568_PD_VO>;
+                iommus = <&vop_mmu>;
+                vop_out: port {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+                    vp0_out_dsi0: endpoint@0 {
+                        reg = <0>;
+                        remote-endpoint = <&dsi0_in_vp0>;
+                    };
+                    vp0_out_hdmi: endpoint@1 {
+                        reg = <1>;
+                        remote-endpoint = <&hdmi0_in_vp0>;
+                    };
+                };
+            };
+        };
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 10/18] dt-bindings: display: rockchip: Add binding for VOP2
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The VOP2 is found on newer Rockchip SoCs like the rk3568 or the rk3566.
The binding differs slightly from the existing VOP binding, so add a new
binding file for it.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../display/rockchip/rockchip-vop2.yaml       | 118 ++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
new file mode 100644
index 0000000000000..6533c4ae4ec3a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
@@ -0,0 +1,118 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/rockchip/rockchip-vop2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip SoC display controller (VOP2)
+
+description:
+  VOP2 (Video Output Processor v2) is the display controller for the Rockchip
+  series of SoCs which transfers the image data from a video memory
+  buffer to an external LCD interface.
+
+maintainers:
+  - Sandy Huang <hjc@rock-chips.com>
+  - Heiko Stuebner <heiko@sntech.de>
+
+properties:
+  compatible:
+    enum:
+      - rockchip,rk3566-vop
+      - rockchip,rk3568-vop
+
+  reg:
+    minItems: 1
+    items:
+      - description:
+          Must contain one entry corresponding to the base address and length
+          of the register space.
+      - description:
+          Can optionally contain a second entry corresponding to
+          the CRTC gamma LUT address.
+
+  interrupts:
+    maxItems: 1
+    description:
+      The VOP interrupt is shared by several interrupt sources, such as
+      frame start (VSYNC), line flag and other status interrupts.
+
+  clocks:
+    items:
+      - description: Clock for ddr buffer transfer.
+      - description: Clock for the ahb bus to R/W the phy regs.
+      - description: Pixel clock for video port 0.
+      - description: Pixel clock for video port 1.
+      - description: Pixel clock for video port 2.
+
+  clock-names:
+    items:
+      - const: aclk_vop
+      - const: hclk_vop
+      - const: dclk_vp0
+      - const: dclk_vp1
+      - const: dclk_vp2
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+
+  assigned-clocks:
+    maxItems: 2
+
+  assigned-clock-rates:
+    maxItems: 2
+
+  iommus:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+        #include <dt-bindings/clock/rk3568-cru.h>
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+        #include <dt-bindings/power/rk3568-power.h>
+        bus {
+            #address-cells = <2>;
+            #size-cells = <2>;
+            vop: vop@fe040000 {
+                compatible = "rockchip,rk3568-vop";
+                reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
+                interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&cru ACLK_VOP>,
+                         <&cru HCLK_VOP>,
+                         <&cru DCLK_VOP0>,
+                         <&cru DCLK_VOP1>,
+                         <&cru DCLK_VOP2>;
+                clock-names = "aclk_vop",
+                              "hclk_vop",
+                              "dclk_vp0",
+                              "dclk_vp1",
+                              "dclk_vp2";
+                power-domains = <&power RK3568_PD_VO>;
+                iommus = <&vop_mmu>;
+                vop_out: port {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+                    vp0_out_dsi0: endpoint@0 {
+                        reg = <0>;
+                        remote-endpoint = <&dsi0_in_vp0>;
+                    };
+                    vp0_out_hdmi: endpoint@1 {
+                        reg = <1>;
+                        remote-endpoint = <&hdmi0_in_vp0>;
+                    };
+                };
+            };
+        };
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 11/18] arm64: dts: rockchip: rk356x: Add VOP2 nodes
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The VOP2 is the display output controller on the RK3568. Add the node
for it to the dtsi file along with the required display-subsystem node
and the iommu node.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk3566.dtsi |  4 ++
 arch/arm64/boot/dts/rockchip/rk3568.dtsi |  4 ++
 arch/arm64/boot/dts/rockchip/rk356x.dtsi | 51 ++++++++++++++++++++++++
 include/dt-bindings/soc/rockchip,vop2.h  | 14 +++++++
 4 files changed, 73 insertions(+)
 create mode 100644 include/dt-bindings/soc/rockchip,vop2.h

diff --git a/arch/arm64/boot/dts/rockchip/rk3566.dtsi b/arch/arm64/boot/dts/rockchip/rk3566.dtsi
index 3839eef5e4f76..595fa2562cb8e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3566.dtsi
@@ -18,3 +18,7 @@ power-domain@RK3568_PD_PIPE {
 		#power-domain-cells = <0>;
 	};
 };
+
+&vop {
+	compatible = "rockchip,rk3566-vop";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
index 2fd313a295f8a..1e55efb6fcfde 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
@@ -95,3 +95,7 @@ power-domain@RK3568_PD_PIPE {
 		#power-domain-cells = <0>;
 	};
 };
+
+&vop {
+	compatible = "rockchip,rk3568-vop";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
index 46d9552f60284..3c1e65e851023 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
@@ -10,6 +10,7 @@
 #include <dt-bindings/pinctrl/rockchip.h>
 #include <dt-bindings/power/rk3568-power.h>
 #include <dt-bindings/soc/rockchip,boot-mode.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include <dt-bindings/thermal/thermal.h>
 
 / {
@@ -125,6 +126,11 @@ opp-1800000000 {
 		};
 	};
 
+	display_subsystem: display-subsystem {
+		compatible = "rockchip,display-subsystem";
+		ports = <&vop_out>;
+	};
+
 	firmware {
 		scmi: scmi {
 			compatible = "arm,scmi-smc";
@@ -447,6 +453,51 @@ gmac1_mtl_tx_setup: tx-queues-config {
 		};
 	};
 
+	vop: vop@fe040000 {
+		reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
+		reg-names = "regs", "gamma_lut";
+		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>, <&cru DCLK_VOP0>, <&cru DCLK_VOP1>, <&cru DCLK_VOP2>;
+		clock-names = "aclk_vop", "hclk_vop", "dclk_vp0", "dclk_vp1", "dclk_vp2";
+		iommus = <&vop_mmu>;
+		power-domains = <&power RK3568_PD_VO>;
+		rockchip,grf = <&grf>;
+		status = "disabled";
+
+		vop_out: ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			vp0: port@0 {
+				reg = <0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			vp1: port@1 {
+				reg = <1>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			vp2: port@2 {
+				reg = <2>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+	};
+
+	vop_mmu: iommu@fe043e00 {
+		compatible = "rockchip,rk3568-iommu";
+		reg = <0x0 0xfe043e00 0x0 0x100>, <0x0 0xfe043f00 0x0 0x100>;
+		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>;
+		clock-names = "aclk", "iface";
+		#iommu-cells = <0>;
+		status = "disabled";
+	};
+
 	qos_gpu: qos@fe128000 {
 		compatible = "rockchip,rk3568-qos", "syscon";
 		reg = <0x0 0xfe128000 0x0 0x20>;
diff --git a/include/dt-bindings/soc/rockchip,vop2.h b/include/dt-bindings/soc/rockchip,vop2.h
new file mode 100644
index 0000000000000..0a87bc90564a7
--- /dev/null
+++ b/include/dt-bindings/soc/rockchip,vop2.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_ROCKCHIP_VOP2_H
+#define __DT_BINDINGS_ROCKCHIP_VOP2_H
+
+#define RK3568_VOP2_EP_RGB	0
+#define RK3568_VOP2_EP_HDMI	1
+#define RK3568_VOP2_EP_EDP	2
+#define RK3568_VOP2_EP_MIPI0	3
+#define RK3568_VOP2_EP_LVDS0	4
+#define RK3568_VOP2_EP_MIPI1	5
+#define RK3568_VOP2_EP_LVDS1	6
+
+#endif /* __DT_BINDINGS_ROCKCHIP_VOP2_H */
-- 
2.30.2


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

* [PATCH 11/18] arm64: dts: rockchip: rk356x: Add VOP2 nodes
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

The VOP2 is the display output controller on the RK3568. Add the node
for it to the dtsi file along with the required display-subsystem node
and the iommu node.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk3566.dtsi |  4 ++
 arch/arm64/boot/dts/rockchip/rk3568.dtsi |  4 ++
 arch/arm64/boot/dts/rockchip/rk356x.dtsi | 51 ++++++++++++++++++++++++
 include/dt-bindings/soc/rockchip,vop2.h  | 14 +++++++
 4 files changed, 73 insertions(+)
 create mode 100644 include/dt-bindings/soc/rockchip,vop2.h

diff --git a/arch/arm64/boot/dts/rockchip/rk3566.dtsi b/arch/arm64/boot/dts/rockchip/rk3566.dtsi
index 3839eef5e4f76..595fa2562cb8e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3566.dtsi
@@ -18,3 +18,7 @@ power-domain@RK3568_PD_PIPE {
 		#power-domain-cells = <0>;
 	};
 };
+
+&vop {
+	compatible = "rockchip,rk3566-vop";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
index 2fd313a295f8a..1e55efb6fcfde 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
@@ -95,3 +95,7 @@ power-domain@RK3568_PD_PIPE {
 		#power-domain-cells = <0>;
 	};
 };
+
+&vop {
+	compatible = "rockchip,rk3568-vop";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
index 46d9552f60284..3c1e65e851023 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
@@ -10,6 +10,7 @@
 #include <dt-bindings/pinctrl/rockchip.h>
 #include <dt-bindings/power/rk3568-power.h>
 #include <dt-bindings/soc/rockchip,boot-mode.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include <dt-bindings/thermal/thermal.h>
 
 / {
@@ -125,6 +126,11 @@ opp-1800000000 {
 		};
 	};
 
+	display_subsystem: display-subsystem {
+		compatible = "rockchip,display-subsystem";
+		ports = <&vop_out>;
+	};
+
 	firmware {
 		scmi: scmi {
 			compatible = "arm,scmi-smc";
@@ -447,6 +453,51 @@ gmac1_mtl_tx_setup: tx-queues-config {
 		};
 	};
 
+	vop: vop@fe040000 {
+		reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
+		reg-names = "regs", "gamma_lut";
+		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>, <&cru DCLK_VOP0>, <&cru DCLK_VOP1>, <&cru DCLK_VOP2>;
+		clock-names = "aclk_vop", "hclk_vop", "dclk_vp0", "dclk_vp1", "dclk_vp2";
+		iommus = <&vop_mmu>;
+		power-domains = <&power RK3568_PD_VO>;
+		rockchip,grf = <&grf>;
+		status = "disabled";
+
+		vop_out: ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			vp0: port@0 {
+				reg = <0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			vp1: port@1 {
+				reg = <1>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			vp2: port@2 {
+				reg = <2>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+	};
+
+	vop_mmu: iommu@fe043e00 {
+		compatible = "rockchip,rk3568-iommu";
+		reg = <0x0 0xfe043e00 0x0 0x100>, <0x0 0xfe043f00 0x0 0x100>;
+		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>;
+		clock-names = "aclk", "iface";
+		#iommu-cells = <0>;
+		status = "disabled";
+	};
+
 	qos_gpu: qos@fe128000 {
 		compatible = "rockchip,rk3568-qos", "syscon";
 		reg = <0x0 0xfe128000 0x0 0x20>;
diff --git a/include/dt-bindings/soc/rockchip,vop2.h b/include/dt-bindings/soc/rockchip,vop2.h
new file mode 100644
index 0000000000000..0a87bc90564a7
--- /dev/null
+++ b/include/dt-bindings/soc/rockchip,vop2.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_ROCKCHIP_VOP2_H
+#define __DT_BINDINGS_ROCKCHIP_VOP2_H
+
+#define RK3568_VOP2_EP_RGB	0
+#define RK3568_VOP2_EP_HDMI	1
+#define RK3568_VOP2_EP_EDP	2
+#define RK3568_VOP2_EP_MIPI0	3
+#define RK3568_VOP2_EP_LVDS0	4
+#define RK3568_VOP2_EP_MIPI1	5
+#define RK3568_VOP2_EP_LVDS1	6
+
+#endif /* __DT_BINDINGS_ROCKCHIP_VOP2_H */
-- 
2.30.2


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

* [PATCH 11/18] arm64: dts: rockchip: rk356x: Add VOP2 nodes
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The VOP2 is the display output controller on the RK3568. Add the node
for it to the dtsi file along with the required display-subsystem node
and the iommu node.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk3566.dtsi |  4 ++
 arch/arm64/boot/dts/rockchip/rk3568.dtsi |  4 ++
 arch/arm64/boot/dts/rockchip/rk356x.dtsi | 51 ++++++++++++++++++++++++
 include/dt-bindings/soc/rockchip,vop2.h  | 14 +++++++
 4 files changed, 73 insertions(+)
 create mode 100644 include/dt-bindings/soc/rockchip,vop2.h

diff --git a/arch/arm64/boot/dts/rockchip/rk3566.dtsi b/arch/arm64/boot/dts/rockchip/rk3566.dtsi
index 3839eef5e4f76..595fa2562cb8e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3566.dtsi
@@ -18,3 +18,7 @@ power-domain@RK3568_PD_PIPE {
 		#power-domain-cells = <0>;
 	};
 };
+
+&vop {
+	compatible = "rockchip,rk3566-vop";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
index 2fd313a295f8a..1e55efb6fcfde 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
@@ -95,3 +95,7 @@ power-domain@RK3568_PD_PIPE {
 		#power-domain-cells = <0>;
 	};
 };
+
+&vop {
+	compatible = "rockchip,rk3568-vop";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
index 46d9552f60284..3c1e65e851023 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
@@ -10,6 +10,7 @@
 #include <dt-bindings/pinctrl/rockchip.h>
 #include <dt-bindings/power/rk3568-power.h>
 #include <dt-bindings/soc/rockchip,boot-mode.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include <dt-bindings/thermal/thermal.h>
 
 / {
@@ -125,6 +126,11 @@ opp-1800000000 {
 		};
 	};
 
+	display_subsystem: display-subsystem {
+		compatible = "rockchip,display-subsystem";
+		ports = <&vop_out>;
+	};
+
 	firmware {
 		scmi: scmi {
 			compatible = "arm,scmi-smc";
@@ -447,6 +453,51 @@ gmac1_mtl_tx_setup: tx-queues-config {
 		};
 	};
 
+	vop: vop@fe040000 {
+		reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
+		reg-names = "regs", "gamma_lut";
+		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>, <&cru DCLK_VOP0>, <&cru DCLK_VOP1>, <&cru DCLK_VOP2>;
+		clock-names = "aclk_vop", "hclk_vop", "dclk_vp0", "dclk_vp1", "dclk_vp2";
+		iommus = <&vop_mmu>;
+		power-domains = <&power RK3568_PD_VO>;
+		rockchip,grf = <&grf>;
+		status = "disabled";
+
+		vop_out: ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			vp0: port@0 {
+				reg = <0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			vp1: port@1 {
+				reg = <1>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			vp2: port@2 {
+				reg = <2>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+	};
+
+	vop_mmu: iommu@fe043e00 {
+		compatible = "rockchip,rk3568-iommu";
+		reg = <0x0 0xfe043e00 0x0 0x100>, <0x0 0xfe043f00 0x0 0x100>;
+		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>;
+		clock-names = "aclk", "iface";
+		#iommu-cells = <0>;
+		status = "disabled";
+	};
+
 	qos_gpu: qos@fe128000 {
 		compatible = "rockchip,rk3568-qos", "syscon";
 		reg = <0x0 0xfe128000 0x0 0x20>;
diff --git a/include/dt-bindings/soc/rockchip,vop2.h b/include/dt-bindings/soc/rockchip,vop2.h
new file mode 100644
index 0000000000000..0a87bc90564a7
--- /dev/null
+++ b/include/dt-bindings/soc/rockchip,vop2.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_ROCKCHIP_VOP2_H
+#define __DT_BINDINGS_ROCKCHIP_VOP2_H
+
+#define RK3568_VOP2_EP_RGB	0
+#define RK3568_VOP2_EP_HDMI	1
+#define RK3568_VOP2_EP_EDP	2
+#define RK3568_VOP2_EP_MIPI0	3
+#define RK3568_VOP2_EP_LVDS0	4
+#define RK3568_VOP2_EP_MIPI1	5
+#define RK3568_VOP2_EP_LVDS1	6
+
+#endif /* __DT_BINDINGS_ROCKCHIP_VOP2_H */
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 11/18] arm64: dts: rockchip: rk356x: Add VOP2 nodes
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

The VOP2 is the display output controller on the RK3568. Add the node
for it to the dtsi file along with the required display-subsystem node
and the iommu node.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk3566.dtsi |  4 ++
 arch/arm64/boot/dts/rockchip/rk3568.dtsi |  4 ++
 arch/arm64/boot/dts/rockchip/rk356x.dtsi | 51 ++++++++++++++++++++++++
 include/dt-bindings/soc/rockchip,vop2.h  | 14 +++++++
 4 files changed, 73 insertions(+)
 create mode 100644 include/dt-bindings/soc/rockchip,vop2.h

diff --git a/arch/arm64/boot/dts/rockchip/rk3566.dtsi b/arch/arm64/boot/dts/rockchip/rk3566.dtsi
index 3839eef5e4f76..595fa2562cb8e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3566.dtsi
@@ -18,3 +18,7 @@ power-domain@RK3568_PD_PIPE {
 		#power-domain-cells = <0>;
 	};
 };
+
+&vop {
+	compatible = "rockchip,rk3566-vop";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
index 2fd313a295f8a..1e55efb6fcfde 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
@@ -95,3 +95,7 @@ power-domain@RK3568_PD_PIPE {
 		#power-domain-cells = <0>;
 	};
 };
+
+&vop {
+	compatible = "rockchip,rk3568-vop";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
index 46d9552f60284..3c1e65e851023 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
@@ -10,6 +10,7 @@
 #include <dt-bindings/pinctrl/rockchip.h>
 #include <dt-bindings/power/rk3568-power.h>
 #include <dt-bindings/soc/rockchip,boot-mode.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include <dt-bindings/thermal/thermal.h>
 
 / {
@@ -125,6 +126,11 @@ opp-1800000000 {
 		};
 	};
 
+	display_subsystem: display-subsystem {
+		compatible = "rockchip,display-subsystem";
+		ports = <&vop_out>;
+	};
+
 	firmware {
 		scmi: scmi {
 			compatible = "arm,scmi-smc";
@@ -447,6 +453,51 @@ gmac1_mtl_tx_setup: tx-queues-config {
 		};
 	};
 
+	vop: vop@fe040000 {
+		reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
+		reg-names = "regs", "gamma_lut";
+		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>, <&cru DCLK_VOP0>, <&cru DCLK_VOP1>, <&cru DCLK_VOP2>;
+		clock-names = "aclk_vop", "hclk_vop", "dclk_vp0", "dclk_vp1", "dclk_vp2";
+		iommus = <&vop_mmu>;
+		power-domains = <&power RK3568_PD_VO>;
+		rockchip,grf = <&grf>;
+		status = "disabled";
+
+		vop_out: ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			vp0: port@0 {
+				reg = <0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			vp1: port@1 {
+				reg = <1>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			vp2: port@2 {
+				reg = <2>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+	};
+
+	vop_mmu: iommu@fe043e00 {
+		compatible = "rockchip,rk3568-iommu";
+		reg = <0x0 0xfe043e00 0x0 0x100>, <0x0 0xfe043f00 0x0 0x100>;
+		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>;
+		clock-names = "aclk", "iface";
+		#iommu-cells = <0>;
+		status = "disabled";
+	};
+
 	qos_gpu: qos@fe128000 {
 		compatible = "rockchip,rk3568-qos", "syscon";
 		reg = <0x0 0xfe128000 0x0 0x20>;
diff --git a/include/dt-bindings/soc/rockchip,vop2.h b/include/dt-bindings/soc/rockchip,vop2.h
new file mode 100644
index 0000000000000..0a87bc90564a7
--- /dev/null
+++ b/include/dt-bindings/soc/rockchip,vop2.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_ROCKCHIP_VOP2_H
+#define __DT_BINDINGS_ROCKCHIP_VOP2_H
+
+#define RK3568_VOP2_EP_RGB	0
+#define RK3568_VOP2_EP_HDMI	1
+#define RK3568_VOP2_EP_EDP	2
+#define RK3568_VOP2_EP_MIPI0	3
+#define RK3568_VOP2_EP_LVDS0	4
+#define RK3568_VOP2_EP_MIPI1	5
+#define RK3568_VOP2_EP_LVDS1	6
+
+#endif /* __DT_BINDINGS_ROCKCHIP_VOP2_H */
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 12/18] arm64: dts: rockchip: rk356x: Add HDMI nodes
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Add support for the HDMI port found on RK3568.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk356x.dtsi | 26 +++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
index 3c1e65e851023..702065bdcf282 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
@@ -10,7 +10,6 @@
 #include <dt-bindings/pinctrl/rockchip.h>
 #include <dt-bindings/power/rk3568-power.h>
 #include <dt-bindings/soc/rockchip,boot-mode.h>
-#include <dt-bindings/soc/rockchip,vop2.h>
 #include <dt-bindings/thermal/thermal.h>
 
 / {
@@ -498,6 +497,31 @@ vop_mmu: iommu@fe043e00 {
 		status = "disabled";
 	};
 
+	hdmi: hdmi@fe0a0000 {
+		compatible = "rockchip,rk3568-dw-hdmi";
+		reg = <0x0 0xfe0a0000 0x0 0x20000>;
+		interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru PCLK_HDMI_HOST>,
+			 <&cru CLK_HDMI_SFR>,
+			 <&cru CLK_HDMI_CEC>,
+			 <&cru HCLK_VOP>;
+		clock-names = "iahb", "isfr", "cec", "ref";
+		pinctrl-names = "default";
+		pinctrl-0 = <&hdmitx_scl &hdmitx_sda &hdmitxm0_cec>;
+		power-domains = <&power RK3568_PD_VO>;
+		reg-io-width = <4>;
+		rockchip,grf = <&grf>;
+		#sound-dai-cells = <0>;
+		status = "disabled";
+
+		ports {
+			hdmi_in: port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+	};
+
 	qos_gpu: qos@fe128000 {
 		compatible = "rockchip,rk3568-qos", "syscon";
 		reg = <0x0 0xfe128000 0x0 0x20>;
-- 
2.30.2


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

* [PATCH 12/18] arm64: dts: rockchip: rk356x: Add HDMI nodes
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

Add support for the HDMI port found on RK3568.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk356x.dtsi | 26 +++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
index 3c1e65e851023..702065bdcf282 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
@@ -10,7 +10,6 @@
 #include <dt-bindings/pinctrl/rockchip.h>
 #include <dt-bindings/power/rk3568-power.h>
 #include <dt-bindings/soc/rockchip,boot-mode.h>
-#include <dt-bindings/soc/rockchip,vop2.h>
 #include <dt-bindings/thermal/thermal.h>
 
 / {
@@ -498,6 +497,31 @@ vop_mmu: iommu@fe043e00 {
 		status = "disabled";
 	};
 
+	hdmi: hdmi@fe0a0000 {
+		compatible = "rockchip,rk3568-dw-hdmi";
+		reg = <0x0 0xfe0a0000 0x0 0x20000>;
+		interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru PCLK_HDMI_HOST>,
+			 <&cru CLK_HDMI_SFR>,
+			 <&cru CLK_HDMI_CEC>,
+			 <&cru HCLK_VOP>;
+		clock-names = "iahb", "isfr", "cec", "ref";
+		pinctrl-names = "default";
+		pinctrl-0 = <&hdmitx_scl &hdmitx_sda &hdmitxm0_cec>;
+		power-domains = <&power RK3568_PD_VO>;
+		reg-io-width = <4>;
+		rockchip,grf = <&grf>;
+		#sound-dai-cells = <0>;
+		status = "disabled";
+
+		ports {
+			hdmi_in: port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+	};
+
 	qos_gpu: qos@fe128000 {
 		compatible = "rockchip,rk3568-qos", "syscon";
 		reg = <0x0 0xfe128000 0x0 0x20>;
-- 
2.30.2


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

* [PATCH 12/18] arm64: dts: rockchip: rk356x: Add HDMI nodes
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Add support for the HDMI port found on RK3568.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk356x.dtsi | 26 +++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
index 3c1e65e851023..702065bdcf282 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
@@ -10,7 +10,6 @@
 #include <dt-bindings/pinctrl/rockchip.h>
 #include <dt-bindings/power/rk3568-power.h>
 #include <dt-bindings/soc/rockchip,boot-mode.h>
-#include <dt-bindings/soc/rockchip,vop2.h>
 #include <dt-bindings/thermal/thermal.h>
 
 / {
@@ -498,6 +497,31 @@ vop_mmu: iommu@fe043e00 {
 		status = "disabled";
 	};
 
+	hdmi: hdmi@fe0a0000 {
+		compatible = "rockchip,rk3568-dw-hdmi";
+		reg = <0x0 0xfe0a0000 0x0 0x20000>;
+		interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru PCLK_HDMI_HOST>,
+			 <&cru CLK_HDMI_SFR>,
+			 <&cru CLK_HDMI_CEC>,
+			 <&cru HCLK_VOP>;
+		clock-names = "iahb", "isfr", "cec", "ref";
+		pinctrl-names = "default";
+		pinctrl-0 = <&hdmitx_scl &hdmitx_sda &hdmitxm0_cec>;
+		power-domains = <&power RK3568_PD_VO>;
+		reg-io-width = <4>;
+		rockchip,grf = <&grf>;
+		#sound-dai-cells = <0>;
+		status = "disabled";
+
+		ports {
+			hdmi_in: port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+	};
+
 	qos_gpu: qos@fe128000 {
 		compatible = "rockchip,rk3568-qos", "syscon";
 		reg = <0x0 0xfe128000 0x0 0x20>;
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 12/18] arm64: dts: rockchip: rk356x: Add HDMI nodes
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Add support for the HDMI port found on RK3568.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk356x.dtsi | 26 +++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
index 3c1e65e851023..702065bdcf282 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
@@ -10,7 +10,6 @@
 #include <dt-bindings/pinctrl/rockchip.h>
 #include <dt-bindings/power/rk3568-power.h>
 #include <dt-bindings/soc/rockchip,boot-mode.h>
-#include <dt-bindings/soc/rockchip,vop2.h>
 #include <dt-bindings/thermal/thermal.h>
 
 / {
@@ -498,6 +497,31 @@ vop_mmu: iommu@fe043e00 {
 		status = "disabled";
 	};
 
+	hdmi: hdmi@fe0a0000 {
+		compatible = "rockchip,rk3568-dw-hdmi";
+		reg = <0x0 0xfe0a0000 0x0 0x20000>;
+		interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru PCLK_HDMI_HOST>,
+			 <&cru CLK_HDMI_SFR>,
+			 <&cru CLK_HDMI_CEC>,
+			 <&cru HCLK_VOP>;
+		clock-names = "iahb", "isfr", "cec", "ref";
+		pinctrl-names = "default";
+		pinctrl-0 = <&hdmitx_scl &hdmitx_sda &hdmitxm0_cec>;
+		power-domains = <&power RK3568_PD_VO>;
+		reg-io-width = <4>;
+		rockchip,grf = <&grf>;
+		#sound-dai-cells = <0>;
+		status = "disabled";
+
+		ports {
+			hdmi_in: port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+	};
+
 	qos_gpu: qos@fe128000 {
 		compatible = "rockchip,rk3568-qos", "syscon";
 		reg = <0x0 0xfe128000 0x0 0x20>;
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 13/18] arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

This enabled the VOP2 display controller along with hdmi and the
required port routes which is enough to get a picture out of the
hdmi port of the board.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../boot/dts/rockchip/rk3568-evb1-v10.dts     | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
index 184e2aa2416af..b1b0963fa8525 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
@@ -7,6 +7,7 @@
 /dts-v1/;
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3568.dtsi"
 
 / {
@@ -106,6 +107,12 @@ &gmac1m1_rgmii_clk
 	status = "okay";
 };
 
+&hdmi {
+	status = "okay";
+	avdd-0v9-supply = <&vdda0v9_image>;
+	avdd-1v8-supply = <&vcca1v8_image>;
+};
+
 &i2c0 {
 	status = "okay";
 
@@ -390,3 +397,27 @@ &sdmmc0 {
 &uart2 {
 	status = "okay";
 };
+
+&vop {
+	status = "okay";
+	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint@0 {
+		reg = <0>;
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
+		reg = <RK3568_VOP2_EP_HDMI>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
-- 
2.30.2


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

* [PATCH 13/18] arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

This enabled the VOP2 display controller along with hdmi and the
required port routes which is enough to get a picture out of the
hdmi port of the board.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../boot/dts/rockchip/rk3568-evb1-v10.dts     | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
index 184e2aa2416af..b1b0963fa8525 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
@@ -7,6 +7,7 @@
 /dts-v1/;
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3568.dtsi"
 
 / {
@@ -106,6 +107,12 @@ &gmac1m1_rgmii_clk
 	status = "okay";
 };
 
+&hdmi {
+	status = "okay";
+	avdd-0v9-supply = <&vdda0v9_image>;
+	avdd-1v8-supply = <&vcca1v8_image>;
+};
+
 &i2c0 {
 	status = "okay";
 
@@ -390,3 +397,27 @@ &sdmmc0 {
 &uart2 {
 	status = "okay";
 };
+
+&vop {
+	status = "okay";
+	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint@0 {
+		reg = <0>;
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
+		reg = <RK3568_VOP2_EP_HDMI>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
-- 
2.30.2


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

* [PATCH 13/18] arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

This enabled the VOP2 display controller along with hdmi and the
required port routes which is enough to get a picture out of the
hdmi port of the board.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../boot/dts/rockchip/rk3568-evb1-v10.dts     | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
index 184e2aa2416af..b1b0963fa8525 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
@@ -7,6 +7,7 @@
 /dts-v1/;
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3568.dtsi"
 
 / {
@@ -106,6 +107,12 @@ &gmac1m1_rgmii_clk
 	status = "okay";
 };
 
+&hdmi {
+	status = "okay";
+	avdd-0v9-supply = <&vdda0v9_image>;
+	avdd-1v8-supply = <&vcca1v8_image>;
+};
+
 &i2c0 {
 	status = "okay";
 
@@ -390,3 +397,27 @@ &sdmmc0 {
 &uart2 {
 	status = "okay";
 };
+
+&vop {
+	status = "okay";
+	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint@0 {
+		reg = <0>;
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
+		reg = <RK3568_VOP2_EP_HDMI>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 13/18] arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

This enabled the VOP2 display controller along with hdmi and the
required port routes which is enough to get a picture out of the
hdmi port of the board.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../boot/dts/rockchip/rk3568-evb1-v10.dts     | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
index 184e2aa2416af..b1b0963fa8525 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
@@ -7,6 +7,7 @@
 /dts-v1/;
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3568.dtsi"
 
 / {
@@ -106,6 +107,12 @@ &gmac1m1_rgmii_clk
 	status = "okay";
 };
 
+&hdmi {
+	status = "okay";
+	avdd-0v9-supply = <&vdda0v9_image>;
+	avdd-1v8-supply = <&vcca1v8_image>;
+};
+
 &i2c0 {
 	status = "okay";
 
@@ -390,3 +397,27 @@ &sdmmc0 {
 &uart2 {
 	status = "okay";
 };
+
+&vop {
+	status = "okay";
+	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint@0 {
+		reg = <0>;
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
+		reg = <RK3568_VOP2_EP_HDMI>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 14/18] arm64: dts: rockchip: enable vop2 and hdmi tx on quartz64a
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

From: Michael Riesch <michael.riesch@wolfvision.net>

Enable the RK356x Video Output Processor (VOP) 2 on the Pine64
Quartz64 Model A.

Signed-off-by: Michael Riesch <michael.riesch@wolfvision.net>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../boot/dts/rockchip/rk3566-quartz64-a.dts   | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
index 4d4b2a301b1a4..ccebd6bb19cea 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
@@ -4,6 +4,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3566.dtsi"
 
 / {
@@ -205,6 +206,12 @@ &gmac1m0_clkinout
 	status = "okay";
 };
 
+&hdmi {
+	avdd-0v9-supply = <&vdda_0v9>;
+	avdd-1v8-supply = <&vcc_1v8>;
+	status = "okay";
+};
+
 &i2c0 {
 	status = "okay";
 
@@ -546,3 +553,27 @@ bluetooth {
 &uart2 {
 	status = "okay";
 };
+
+&vop {
+	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint@0 {
+		reg = <0>;
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
+		reg = <RK3568_VOP2_EP_HDMI>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
-- 
2.30.2


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

* [PATCH 14/18] arm64: dts: rockchip: enable vop2 and hdmi tx on quartz64a
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

From: Michael Riesch <michael.riesch@wolfvision.net>

Enable the RK356x Video Output Processor (VOP) 2 on the Pine64
Quartz64 Model A.

Signed-off-by: Michael Riesch <michael.riesch@wolfvision.net>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../boot/dts/rockchip/rk3566-quartz64-a.dts   | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
index 4d4b2a301b1a4..ccebd6bb19cea 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
@@ -4,6 +4,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3566.dtsi"
 
 / {
@@ -205,6 +206,12 @@ &gmac1m0_clkinout
 	status = "okay";
 };
 
+&hdmi {
+	avdd-0v9-supply = <&vdda_0v9>;
+	avdd-1v8-supply = <&vcc_1v8>;
+	status = "okay";
+};
+
 &i2c0 {
 	status = "okay";
 
@@ -546,3 +553,27 @@ bluetooth {
 &uart2 {
 	status = "okay";
 };
+
+&vop {
+	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint@0 {
+		reg = <0>;
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
+		reg = <RK3568_VOP2_EP_HDMI>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
-- 
2.30.2


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

* [PATCH 14/18] arm64: dts: rockchip: enable vop2 and hdmi tx on quartz64a
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

From: Michael Riesch <michael.riesch@wolfvision.net>

Enable the RK356x Video Output Processor (VOP) 2 on the Pine64
Quartz64 Model A.

Signed-off-by: Michael Riesch <michael.riesch@wolfvision.net>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../boot/dts/rockchip/rk3566-quartz64-a.dts   | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
index 4d4b2a301b1a4..ccebd6bb19cea 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
@@ -4,6 +4,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3566.dtsi"
 
 / {
@@ -205,6 +206,12 @@ &gmac1m0_clkinout
 	status = "okay";
 };
 
+&hdmi {
+	avdd-0v9-supply = <&vdda_0v9>;
+	avdd-1v8-supply = <&vcc_1v8>;
+	status = "okay";
+};
+
 &i2c0 {
 	status = "okay";
 
@@ -546,3 +553,27 @@ bluetooth {
 &uart2 {
 	status = "okay";
 };
+
+&vop {
+	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint@0 {
+		reg = <0>;
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
+		reg = <RK3568_VOP2_EP_HDMI>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 14/18] arm64: dts: rockchip: enable vop2 and hdmi tx on quartz64a
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

From: Michael Riesch <michael.riesch@wolfvision.net>

Enable the RK356x Video Output Processor (VOP) 2 on the Pine64
Quartz64 Model A.

Signed-off-by: Michael Riesch <michael.riesch@wolfvision.net>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../boot/dts/rockchip/rk3566-quartz64-a.dts   | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
index 4d4b2a301b1a4..ccebd6bb19cea 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
@@ -4,6 +4,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3566.dtsi"
 
 / {
@@ -205,6 +206,12 @@ &gmac1m0_clkinout
 	status = "okay";
 };
 
+&hdmi {
+	avdd-0v9-supply = <&vdda_0v9>;
+	avdd-1v8-supply = <&vcc_1v8>;
+	status = "okay";
+};
+
 &i2c0 {
 	status = "okay";
 
@@ -546,3 +553,27 @@ bluetooth {
 &uart2 {
 	status = "okay";
 };
+
+&vop {
+	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint@0 {
+		reg = <0>;
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
+		reg = <RK3568_VOP2_EP_HDMI>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 15/18] drm/encoder: Add of_graph port to struct drm_encoder
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Add a device node to drm_encoder which corresponds with the port node
in the DT description of the encoder. This allows drivers to find the
of_graph link between a crtc and an encoder.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/drm/drm_encoder.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
index 6e91a0280f31b..3acd054b1eb3e 100644
--- a/include/drm/drm_encoder.h
+++ b/include/drm/drm_encoder.h
@@ -99,6 +99,8 @@ struct drm_encoder {
 	struct drm_device *dev;
 	struct list_head head;
 
+	struct device_node *port;
+
 	struct drm_mode_object base;
 	char *name;
 	/**
-- 
2.30.2


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

* [PATCH 15/18] drm/encoder: Add of_graph port to struct drm_encoder
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

Add a device node to drm_encoder which corresponds with the port node
in the DT description of the encoder. This allows drivers to find the
of_graph link between a crtc and an encoder.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/drm/drm_encoder.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
index 6e91a0280f31b..3acd054b1eb3e 100644
--- a/include/drm/drm_encoder.h
+++ b/include/drm/drm_encoder.h
@@ -99,6 +99,8 @@ struct drm_encoder {
 	struct drm_device *dev;
 	struct list_head head;
 
+	struct device_node *port;
+
 	struct drm_mode_object base;
 	char *name;
 	/**
-- 
2.30.2


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

* [PATCH 15/18] drm/encoder: Add of_graph port to struct drm_encoder
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Add a device node to drm_encoder which corresponds with the port node
in the DT description of the encoder. This allows drivers to find the
of_graph link between a crtc and an encoder.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/drm/drm_encoder.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
index 6e91a0280f31b..3acd054b1eb3e 100644
--- a/include/drm/drm_encoder.h
+++ b/include/drm/drm_encoder.h
@@ -99,6 +99,8 @@ struct drm_encoder {
 	struct drm_device *dev;
 	struct list_head head;
 
+	struct device_node *port;
+
 	struct drm_mode_object base;
 	char *name;
 	/**
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 15/18] drm/encoder: Add of_graph port to struct drm_encoder
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

Add a device node to drm_encoder which corresponds with the port node
in the DT description of the encoder. This allows drivers to find the
of_graph link between a crtc and an encoder.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/drm/drm_encoder.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
index 6e91a0280f31b..3acd054b1eb3e 100644
--- a/include/drm/drm_encoder.h
+++ b/include/drm/drm_encoder.h
@@ -99,6 +99,8 @@ struct drm_encoder {
 	struct drm_device *dev;
 	struct list_head head;
 
+	struct device_node *port;
+
 	struct drm_mode_object base;
 	char *name;
 	/**
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 16/18] drm/rockchip: Make VOP driver optional
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

With upcoming VOP2 support VOP won't be the only choice anymore, so make
the VOP driver optional.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/Kconfig            | 8 ++++++++
 drivers/gpu/drm/rockchip/Makefile           | 3 ++-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +-
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 9f1ecefc39332..b9b156308460a 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -21,8 +21,16 @@ config DRM_ROCKCHIP
 
 if DRM_ROCKCHIP
 
+config ROCKCHIP_VOP
+	bool "Rockchip VOP driver"
+	default y
+	help
+	  This selects support for the VOP driver. You should enable it
+	  on all older SoCs up to RK3399.
+
 config ROCKCHIP_ANALOGIX_DP
 	bool "Rockchip specific extensions for Analogix DP driver"
+	depends on ROCKCHIP_VOP
 	help
 	  This selects support for Rockchip SoC specific extensions
 	  for the Analogix Core DP driver. If you want to enable DP
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 17a9e7eb2130d..cd6e7bb5ce9c5 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -4,9 +4,10 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-		rockchip_drm_gem.o rockchip_drm_vop.o rockchip_vop_reg.o
+		rockchip_drm_gem.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
+rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index e4ebe60b3cc1a..64fa5fd62c01a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -473,7 +473,7 @@ static int __init rockchip_drm_init(void)
 	int ret;
 
 	num_rockchip_sub_drivers = 0;
-	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP);
+	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver,
 				CONFIG_ROCKCHIP_LVDS);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
-- 
2.30.2


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

* [PATCH 16/18] drm/rockchip: Make VOP driver optional
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

With upcoming VOP2 support VOP won't be the only choice anymore, so make
the VOP driver optional.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/Kconfig            | 8 ++++++++
 drivers/gpu/drm/rockchip/Makefile           | 3 ++-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +-
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 9f1ecefc39332..b9b156308460a 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -21,8 +21,16 @@ config DRM_ROCKCHIP
 
 if DRM_ROCKCHIP
 
+config ROCKCHIP_VOP
+	bool "Rockchip VOP driver"
+	default y
+	help
+	  This selects support for the VOP driver. You should enable it
+	  on all older SoCs up to RK3399.
+
 config ROCKCHIP_ANALOGIX_DP
 	bool "Rockchip specific extensions for Analogix DP driver"
+	depends on ROCKCHIP_VOP
 	help
 	  This selects support for Rockchip SoC specific extensions
 	  for the Analogix Core DP driver. If you want to enable DP
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 17a9e7eb2130d..cd6e7bb5ce9c5 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -4,9 +4,10 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-		rockchip_drm_gem.o rockchip_drm_vop.o rockchip_vop_reg.o
+		rockchip_drm_gem.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
+rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index e4ebe60b3cc1a..64fa5fd62c01a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -473,7 +473,7 @@ static int __init rockchip_drm_init(void)
 	int ret;
 
 	num_rockchip_sub_drivers = 0;
-	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP);
+	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver,
 				CONFIG_ROCKCHIP_LVDS);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
-- 
2.30.2


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

* [PATCH 16/18] drm/rockchip: Make VOP driver optional
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

With upcoming VOP2 support VOP won't be the only choice anymore, so make
the VOP driver optional.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/Kconfig            | 8 ++++++++
 drivers/gpu/drm/rockchip/Makefile           | 3 ++-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +-
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 9f1ecefc39332..b9b156308460a 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -21,8 +21,16 @@ config DRM_ROCKCHIP
 
 if DRM_ROCKCHIP
 
+config ROCKCHIP_VOP
+	bool "Rockchip VOP driver"
+	default y
+	help
+	  This selects support for the VOP driver. You should enable it
+	  on all older SoCs up to RK3399.
+
 config ROCKCHIP_ANALOGIX_DP
 	bool "Rockchip specific extensions for Analogix DP driver"
+	depends on ROCKCHIP_VOP
 	help
 	  This selects support for Rockchip SoC specific extensions
 	  for the Analogix Core DP driver. If you want to enable DP
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 17a9e7eb2130d..cd6e7bb5ce9c5 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -4,9 +4,10 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-		rockchip_drm_gem.o rockchip_drm_vop.o rockchip_vop_reg.o
+		rockchip_drm_gem.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
+rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index e4ebe60b3cc1a..64fa5fd62c01a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -473,7 +473,7 @@ static int __init rockchip_drm_init(void)
 	int ret;
 
 	num_rockchip_sub_drivers = 0;
-	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP);
+	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver,
 				CONFIG_ROCKCHIP_LVDS);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 16/18] drm/rockchip: Make VOP driver optional
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

With upcoming VOP2 support VOP won't be the only choice anymore, so make
the VOP driver optional.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/Kconfig            | 8 ++++++++
 drivers/gpu/drm/rockchip/Makefile           | 3 ++-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +-
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 9f1ecefc39332..b9b156308460a 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -21,8 +21,16 @@ config DRM_ROCKCHIP
 
 if DRM_ROCKCHIP
 
+config ROCKCHIP_VOP
+	bool "Rockchip VOP driver"
+	default y
+	help
+	  This selects support for the VOP driver. You should enable it
+	  on all older SoCs up to RK3399.
+
 config ROCKCHIP_ANALOGIX_DP
 	bool "Rockchip specific extensions for Analogix DP driver"
+	depends on ROCKCHIP_VOP
 	help
 	  This selects support for Rockchip SoC specific extensions
 	  for the Analogix Core DP driver. If you want to enable DP
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 17a9e7eb2130d..cd6e7bb5ce9c5 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -4,9 +4,10 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-		rockchip_drm_gem.o rockchip_drm_vop.o rockchip_vop_reg.o
+		rockchip_drm_gem.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
+rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index e4ebe60b3cc1a..64fa5fd62c01a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -473,7 +473,7 @@ static int __init rockchip_drm_init(void)
 	int ret;
 
 	num_rockchip_sub_drivers = 0;
-	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP);
+	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver,
 				CONFIG_ROCKCHIP_LVDS);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 17/18] drm: rockchip: Add VOP2 driver
  2021-12-08 15:12 ` Sascha Hauer
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

From: Andy Yan <andy.yan@rock-chips.com>

The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
It replaces the VOP unit found in the older Rockchip SoCs.

This driver has been derived from the downstream Rockchip Kernel and
heavily modified:

- All nonstandard DRM properties have been removed
- dropped struct vop2_plane_state and pass around less data between
  functions
- Dropped all DRM_FORMAT_* not known on upstream
- rework register access to get rid of excessively used macros
- Drop all waiting for framesyncs

The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
board. Overlay support is tested with the modetest utility. AFBC support
on the cluster windows is tested with weston-simple-dmabuf-egl on
weston using the (yet to be upstreamed) panfrost driver support.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/Kconfig             |    6 +
 drivers/gpu/drm/rockchip/Makefile            |    1 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c  |    1 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h  |    7 +-
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c   |    2 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h  |   15 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2636 ++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |  625 +++++
 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c |  505 ++++
 9 files changed, 3797 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index b9b156308460a..4ff0043f0ee70 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -28,6 +28,12 @@ config ROCKCHIP_VOP
 	  This selects support for the VOP driver. You should enable it
 	  on all older SoCs up to RK3399.
 
+config ROCKCHIP_VOP2
+	bool "Rockchip VOP2 driver"
+	help
+	  This selects support for the VOP2 driver. You should enable it
+	  on all newer SoCs beginning form RK3568.
+
 config ROCKCHIP_ANALOGIX_DP
 	bool "Rockchip specific extensions for Analogix DP driver"
 	depends on ROCKCHIP_VOP
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index cd6e7bb5ce9c5..29848caef5c21 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -7,6 +7,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
 		rockchip_drm_gem.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
+rockchipdrm-$(CONFIG_ROCKCHIP_VOP2) += rockchip_drm_vop2.o rockchip_vop2_reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 64fa5fd62c01a..2bd9acb265e5a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -474,6 +474,7 @@ static int __init rockchip_drm_init(void)
 
 	num_rockchip_sub_drivers = 0;
 	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP);
+	ADD_ROCKCHIP_SUB_DRIVER(vop2_platform_driver, CONFIG_ROCKCHIP_VOP2);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver,
 				CONFIG_ROCKCHIP_LVDS);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index aa0909e8edf93..fd6994f21817e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -18,7 +18,7 @@
 
 #define ROCKCHIP_MAX_FB_BUFFER	3
 #define ROCKCHIP_MAX_CONNECTOR	2
-#define ROCKCHIP_MAX_CRTC	2
+#define ROCKCHIP_MAX_CRTC	4
 
 struct drm_device;
 struct drm_connector;
@@ -31,6 +31,9 @@ struct rockchip_crtc_state {
 	int output_bpc;
 	int output_flags;
 	bool enable_afbc;
+	uint32_t bus_format;
+	u32 bus_flags;
+	int color_space;
 };
 #define to_rockchip_crtc_state(s) \
 		container_of(s, struct rockchip_crtc_state, base)
@@ -65,4 +68,6 @@ extern struct platform_driver rockchip_dp_driver;
 extern struct platform_driver rockchip_lvds_driver;
 extern struct platform_driver vop_platform_driver;
 extern struct platform_driver rk3066_hdmi_driver;
+extern struct platform_driver vop2_platform_driver;
+
 #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 3aa37e177667e..0d2cb4f3922b8 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -134,4 +134,6 @@ void rockchip_drm_mode_config_init(struct drm_device *dev)
 
 	dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
 	dev->mode_config.helper_private = &rockchip_mode_config_helpers;
+
+	dev->mode_config.normalize_zpos = true;
 }
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 857d97cdc67c6..1e364d7b50e69 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -54,9 +54,23 @@ struct vop_afbc {
 	struct vop_reg enable;
 	struct vop_reg win_sel;
 	struct vop_reg format;
+	struct vop_reg rb_swap;
+	struct vop_reg uv_swap;
+	struct vop_reg auto_gating_en;
+	struct vop_reg block_split_en;
+	struct vop_reg pic_vir_width;
+	struct vop_reg tile_num;
 	struct vop_reg hreg_block_split;
+	struct vop_reg pic_offset;
 	struct vop_reg pic_size;
+	struct vop_reg dsp_offset;
+	struct vop_reg transform_offset;
 	struct vop_reg hdr_ptr;
+	struct vop_reg half_block_en;
+	struct vop_reg xmirror;
+	struct vop_reg ymirror;
+	struct vop_reg rotate_270;
+	struct vop_reg rotate_90;
 	struct vop_reg rstn;
 };
 
@@ -410,4 +424,5 @@ static inline int scl_vop_cal_lb_mode(int width, bool is_yuv)
 }
 
 extern const struct component_ops vop_component_ops;
+
 #endif /* _ROCKCHIP_DRM_VOP_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
new file mode 100644
index 0000000000000..411440d898ab0
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -0,0 +1,2636 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Rockchip Electronics Co., Ltd.
+ * Author: Andy Yan <andy.yan@rock-chips.com>
+ */
+#include <drm/drm.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_flip_work.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_writeback.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_atomic_uapi.h>
+
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <linux/component.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/delay.h>
+#include <linux/swab.h>
+#include <drm/drm_debugfs.h>
+#include <uapi/linux/videodev2.h>
+#include <drm/drm_vblank.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_vop2.h"
+#include "rockchip_vop_reg.h"
+
+/*
+ * VOP2 architecture
+ *
+ +----------+   +-------------+                                                        +-----------+
+ |  Cluster |   | Sel 1 from 6|                                                        | 1 from 3  |
+ |  window0 |   |    Layer0   |                                                        |    RGB    |
+ +----------+   +-------------+              +---------------+    +-------------+      +-----------+
+ +----------+   +-------------+              |N from 6 layers|    |             |
+ |  Cluster |   | Sel 1 from 6|              |   Overlay0    +--->| Video Port0 |      +-----------+
+ |  window1 |   |    Layer1   |              |               |    |             |      | 1 from 3  |
+ +----------+   +-------------+              +---------------+    +-------------+      |   LVDS    |
+ +----------+   +-------------+                                                        +-----------+
+ |  Esmart  |   | Sel 1 from 6|
+ |  window0 |   |   Layer2    |              +---------------+    +-------------+      +-----------+
+ +----------+   +-------------+              |N from 6 Layers|    |             | +--> | 1 from 3  |
+ +----------+   +-------------+   -------->  |   Overlay1    +--->| Video Port1 |      |   MIPI    |
+ |  Esmart  |   | Sel 1 from 6|   -------->  |               |    |             |      +-----------+
+ |  Window1 |   |   Layer3    |              +---------------+    +-------------+
+ +----------+   +-------------+                                                        +-----------+
+ +----------+   +-------------+                                                        | 1 from 3  |
+ |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |   HDMI    |
+ |  Window0 |   |    Layer4   |              |N from 6 Layers|    |             |      +-----------+
+ +----------+   +-------------+              |   Overlay2    +--->| Video Port2 |
+ +----------+   +-------------+              |               |    |             |      +-----------+
+ |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |  1 from 3 |
+ |  Window1 |   |    Layer5   |                                                        |    eDP    |
+ +----------+   +-------------+                                                        +-----------+
+ *
+ */
+
+enum vop2_data_format {
+	VOP2_FMT_ARGB8888 = 0,
+	VOP2_FMT_RGB888,
+	VOP2_FMT_RGB565,
+	VOP2_FMT_XRGB101010,
+	VOP2_FMT_YUV420SP,
+	VOP2_FMT_YUV422SP,
+	VOP2_FMT_YUV444SP,
+	VOP2_FMT_YUYV422 = 8,
+	VOP2_FMT_YUYV420,
+	VOP2_FMT_VYUY422,
+	VOP2_FMT_VYUY420,
+	VOP2_FMT_YUV420SP_TILE_8x4 = 0x10,
+	VOP2_FMT_YUV420SP_TILE_16x2,
+	VOP2_FMT_YUV422SP_TILE_8x4,
+	VOP2_FMT_YUV422SP_TILE_16x2,
+	VOP2_FMT_YUV420SP_10,
+	VOP2_FMT_YUV422SP_10,
+	VOP2_FMT_YUV444SP_10,
+};
+
+enum vop2_afbc_format {
+	VOP2_AFBC_FMT_RGB565,
+	VOP2_AFBC_FMT_ARGB2101010 = 2,
+	VOP2_AFBC_FMT_YUV420_10BIT,
+	VOP2_AFBC_FMT_RGB888,
+	VOP2_AFBC_FMT_ARGB8888,
+	VOP2_AFBC_FMT_YUV420 = 9,
+	VOP2_AFBC_FMT_YUV422 = 0xb,
+	VOP2_AFBC_FMT_YUV422_10BIT = 0xe,
+	VOP2_AFBC_FMT_INVALID = -1,
+};
+
+union vop2_alpha_ctrl {
+	uint32_t val;
+	struct {
+		/* [0:1] */
+		uint32_t color_mode:1;
+		uint32_t alpha_mode:1;
+		/* [2:3] */
+		uint32_t blend_mode:2;
+		uint32_t alpha_cal_mode:1;
+		/* [5:7] */
+		uint32_t factor_mode:3;
+		/* [8:9] */
+		uint32_t alpha_en:1;
+		uint32_t src_dst_swap:1;
+		uint32_t reserved:6;
+		/* [16:23] */
+		uint32_t glb_alpha:8;
+	} bits;
+};
+
+struct vop2_alpha {
+	union vop2_alpha_ctrl src_color_ctrl;
+	union vop2_alpha_ctrl dst_color_ctrl;
+	union vop2_alpha_ctrl src_alpha_ctrl;
+	union vop2_alpha_ctrl dst_alpha_ctrl;
+};
+
+struct vop2_alpha_config {
+	bool src_premulti_en;
+	bool dst_premulti_en;
+	bool src_pixel_alpha_en;
+	bool dst_pixel_alpha_en;
+	uint16_t src_glb_alpha_value;
+	uint16_t dst_glb_alpha_value;
+};
+
+struct vop2_win {
+	struct vop2 *vop2;
+	struct drm_plane base;
+	const struct vop2_win_data *data;
+
+	/**
+	 * @win_id: graphic window id, a cluster maybe split into two
+	 * graphics windows.
+	 */
+	uint8_t win_id;
+
+	uint32_t offset;
+
+	uint8_t delay;
+	enum drm_plane_type type;
+
+	const struct vop2_win_regs *regs;
+};
+
+struct vop2_video_port {
+	struct drm_crtc crtc;
+	struct vop2 *vop2;
+	struct clk *dclk;
+	uint8_t id;
+	const struct vop2_video_port_regs *regs;
+	const struct vop2_video_port_data *data;
+
+	struct completion dsp_hold_completion;
+
+	/**
+	 * @win_mask: Bitmask of wins attached to the video port;
+	 */
+	uint32_t win_mask;
+
+	struct vop2_win *primary_plane;
+	struct drm_pending_vblank_event *event;
+
+	int nlayers;
+};
+
+struct vop2 {
+	struct device *dev;
+	struct drm_device *drm;
+	struct vop2_video_port vps[ROCKCHIP_MAX_CRTC];
+
+	const struct vop2_data *data;
+	/* Number of win that registered as plane,
+	 * maybe less than the total number of hardware
+	 * win.
+	 */
+	uint32_t registered_num_wins;
+
+	uint32_t *regsbak;
+	void __iomem *regs;
+	struct regmap *grf;
+
+	/* physical map length of vop2 register */
+	uint32_t len;
+
+	void __iomem *lut_regs;
+	/* one time only one process allowed to config the register */
+	spinlock_t reg_lock;
+
+	/* protects crtc enable/disable */
+	struct mutex vop2_lock;
+
+	int irq;
+
+	/*
+	 * Some globle resource are shared between all
+	 * the vidoe ports(crtcs), so we need a ref counter here.
+	 */
+	unsigned int enable_count;
+	struct clk *hclk;
+	struct clk *aclk;
+
+	/* must put at the end of the struct */
+	struct vop2_win win[];
+};
+
+static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct vop2_video_port, crtc);
+}
+
+static struct vop2_win *to_vop2_win(struct drm_plane *p)
+{
+	return container_of(p, struct vop2_win, base);
+}
+
+static void vop2_lock(struct vop2 *vop2)
+{
+	mutex_lock(&vop2->vop2_lock);
+}
+
+static void vop2_unlock(struct vop2 *vop2)
+{
+	mutex_unlock(&vop2->vop2_lock);
+}
+
+static void vop2_grf_writel(struct vop2 *vop2, const struct vop_reg *reg,
+				   uint32_t v)
+{
+	uint32_t val = 0;
+
+	if (IS_ERR_OR_NULL(vop2->grf))
+		return;
+
+	if (reg->mask) {
+		val = (v << reg->shift) | (reg->mask << (reg->shift + 16));
+		regmap_write(vop2->grf, reg->offset, val);
+	}
+}
+
+static void vop2_writel(struct vop2 *vop2, uint32_t offset, uint32_t v)
+{
+	writel(v, vop2->regs + offset);
+	vop2->regsbak[offset >> 2] = v;
+}
+
+static uint32_t vop2_readl(struct vop2 *vop2, uint32_t offset)
+{
+	return readl(vop2->regs + offset);
+}
+
+static void vop2_write_reg(struct vop2 *vop2, uint32_t offset,
+			   const struct vop_reg *reg, uint32_t v, bool relaxed)
+{
+	uint32_t mask = reg->mask;
+	uint32_t shift = reg->shift;
+
+	if (!mask)
+		return;
+
+	offset += reg->offset;
+
+	if (reg->write_mask) {
+		v = ((v & mask) << shift) | (mask << (shift + 16));
+	} else {
+		/*
+		 * Several registers in the VOP2 are double buffered and read back
+		 * the new values only after config_done bits have been set. As we
+		 * read-modify-write the hardware registers we need to cache the values
+		 * in memory to make sure we do not overwrite previous values when a
+		 * hardware register is modified multiple times before config_done is
+		 * set.
+		 */
+		uint32_t cached_val = vop2->regsbak[offset >> 2];
+
+		v = (cached_val & ~(mask << shift)) | ((v & mask) << shift);
+		vop2->regsbak[offset >> 2] = v;
+	}
+
+	if (relaxed)
+		writel_relaxed(v, vop2->regs + offset);
+	else
+		writel(v, vop2->regs + offset);
+}
+
+static void vop2_win_write(const struct vop2_win *win, const struct vop_reg *reg,
+			   uint32_t v)
+{
+	vop2_write_reg(win->vop2, win->offset, reg, v, true);
+}
+
+static bool vop2_cluster_window(struct vop2_win *win)
+{
+	return win->data->feature & WIN_FEATURE_CLUSTER;
+}
+
+static void vop2_cfg_done(struct vop2_video_port *vp)
+{
+	struct vop2 *vop2 = vp->vop2;
+	uint32_t val;
+
+	val = vop2_readl(vop2, RK3568_REG_CFG_DONE);
+
+	val &= 0x7;
+
+	vop2_writel(vop2, RK3568_REG_CFG_DONE,
+		    val | BIT(vp->id) | RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
+}
+
+static void vop2_win_disable(struct vop2_win *win)
+{
+	vop2_win_write(win, &win->regs->enable, 0);
+
+	if (vop2_cluster_window(win))
+		vop2_win_write(win, &win->regs->cluster->enable, 0);
+}
+
+static enum vop2_data_format vop2_convert_format(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		return VOP2_FMT_ARGB8888;
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		return VOP2_FMT_RGB888;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		return VOP2_FMT_RGB565;
+	case DRM_FORMAT_NV12:
+		return VOP2_FMT_YUV420SP;
+	case DRM_FORMAT_NV16:
+		return VOP2_FMT_YUV422SP;
+	case DRM_FORMAT_NV24:
+		return VOP2_FMT_YUV444SP;
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_YVYU:
+		return VOP2_FMT_VYUY422;
+	case DRM_FORMAT_VYUY:
+	case DRM_FORMAT_UYVY:
+		return VOP2_FMT_YUYV422;
+	default:
+		DRM_ERROR("unsupported format[%08x]\n", format);
+		return -EINVAL;
+	}
+}
+
+static enum vop2_afbc_format vop2_convert_afbc_format(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		return VOP2_AFBC_FMT_ARGB8888;
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		return VOP2_AFBC_FMT_RGB888;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		return VOP2_AFBC_FMT_RGB565;
+	case DRM_FORMAT_NV12:
+		return VOP2_AFBC_FMT_YUV420;
+	case DRM_FORMAT_NV16:
+		return VOP2_AFBC_FMT_YUV422;
+	default:
+		return VOP2_AFBC_FMT_INVALID;
+	}
+
+	return VOP2_AFBC_FMT_INVALID;
+}
+
+static bool vop2_win_rb_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_BGR888:
+	case DRM_FORMAT_BGR565:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_afbc_rb_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV24:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_afbc_uv_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV16:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_win_uv_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV24:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_win_dither_up(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_BGR565:
+	case DRM_FORMAT_RGB565:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_output_uv_swap(uint32_t bus_format, uint32_t output_mode)
+{
+	/*
+	 * FIXME:
+	 *
+	 * There is no media type for YUV444 output,
+	 * so when out_mode is AAAA or P888, assume output is YUV444 on
+	 * yuv format.
+	 *
+	 * From H/W testing, YUV444 mode need a rb swap.
+	 */
+	if (bus_format == MEDIA_BUS_FMT_YVYU8_1X16 ||
+	    bus_format == MEDIA_BUS_FMT_VYUY8_1X16 ||
+	    bus_format == MEDIA_BUS_FMT_YVYU8_2X8 ||
+	    bus_format == MEDIA_BUS_FMT_VYUY8_2X8 ||
+	    ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||
+	      bus_format == MEDIA_BUS_FMT_YUV10_1X30) &&
+	     (output_mode == ROCKCHIP_OUT_MODE_AAAA ||
+	      output_mode == ROCKCHIP_OUT_MODE_P888)))
+		return true;
+	else
+		return false;
+}
+
+static bool is_yuv_output(uint32_t bus_format)
+{
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_YUV8_1X24:
+	case MEDIA_BUS_FMT_YUV10_1X30:
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+	case MEDIA_BUS_FMT_YUYV8_2X8:
+	case MEDIA_BUS_FMT_YVYU8_2X8:
+	case MEDIA_BUS_FMT_UYVY8_2X8:
+	case MEDIA_BUS_FMT_VYUY8_2X8:
+	case MEDIA_BUS_FMT_YUYV8_1X16:
+	case MEDIA_BUS_FMT_YVYU8_1X16:
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+	case MEDIA_BUS_FMT_VYUY8_1X16:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rockchip_afbc(struct drm_plane *plane, u64 modifier)
+{
+	int i;
+
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return false;
+
+	for (i = 0 ; i < plane->modifier_count; i++)
+		if (plane->modifiers[i] == modifier)
+			break;
+
+	return (i < plane->modifier_count) ? true : false;
+
+}
+
+static bool rockchip_vop2_mod_supported(struct drm_plane *plane, uint32_t format, u64 modifier)
+{
+	struct vop2_win *win = to_vop2_win(plane);
+	struct vop2 *vop2 = win->vop2;
+
+	if (modifier == DRM_FORMAT_MOD_INVALID)
+		return false;
+
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return true;
+
+	if (!rockchip_afbc(plane, modifier)) {
+		drm_err(vop2->drm, "Unsupported format modifier 0x%llx\n", modifier);
+
+		return false;
+	}
+
+	return vop2_convert_afbc_format(format) >= 0;
+}
+
+static int vop2_afbc_half_block_enable(struct drm_plane_state *pstate)
+{
+	if ((pstate->rotation & DRM_MODE_ROTATE_270) || (pstate->rotation & DRM_MODE_ROTATE_90))
+		return 0;
+	else
+		return 1;
+}
+
+static uint32_t vop2_afbc_transform_offset(struct drm_plane_state *pstate,
+					   bool afbc_half_block_en)
+{
+	struct drm_rect *src = &pstate->src;
+	struct drm_framebuffer *fb = pstate->fb;
+	uint32_t bpp = fb->format->cpp[0] * 8;
+	uint32_t vir_width = (fb->pitches[0] << 3) / bpp;
+	uint32_t width = drm_rect_width(src) >> 16;
+	uint32_t height = drm_rect_height(src) >> 16;
+	uint32_t act_xoffset = src->x1 >> 16;
+	uint32_t act_yoffset = src->y1 >> 16;
+	uint32_t align16_crop = 0;
+	uint32_t align64_crop = 0;
+	uint32_t height_tmp = 0;
+	uint32_t transform_tmp = 0;
+	uint8_t transform_xoffset = 0;
+	uint8_t transform_yoffset = 0;
+	uint8_t top_crop = 0;
+	uint8_t top_crop_line_num = 0;
+	uint8_t bottom_crop_line_num = 0;
+
+	/* 16 pixel align */
+	if (height & 0xf)
+		align16_crop = 16 - (height & 0xf);
+
+	height_tmp = height + align16_crop;
+
+	/* 64 pixel align */
+	if (height_tmp & 0x3f)
+		align64_crop = 64 - (height_tmp & 0x3f);
+
+	top_crop_line_num = top_crop << 2;
+	if (top_crop == 0)
+		bottom_crop_line_num = align16_crop + align64_crop;
+	else if (top_crop == 1)
+		bottom_crop_line_num = align16_crop + align64_crop + 12;
+	else if (top_crop == 2)
+		bottom_crop_line_num = align16_crop + align64_crop + 8;
+
+	switch (pstate->rotation &
+		(DRM_MODE_REFLECT_X |
+		 DRM_MODE_REFLECT_Y |
+		 DRM_MODE_ROTATE_90 |
+		 DRM_MODE_ROTATE_270)) {
+	case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
+		transform_tmp = act_xoffset + width;
+		transform_xoffset = 16 - (transform_tmp & 0xf);
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = (transform_tmp & 0xf);
+
+		break;
+	case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90:
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = vir_width - width - act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270:
+		transform_tmp = top_crop_line_num + act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case DRM_MODE_REFLECT_X:
+		transform_tmp = act_xoffset + width;
+		transform_xoffset = 16 - (transform_tmp & 0xf);
+		transform_tmp = top_crop_line_num + act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = transform_tmp & 0xf;
+
+		break;
+	case DRM_MODE_REFLECT_Y:
+		transform_tmp = act_xoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = transform_tmp & 0xf;
+
+		break;
+	case DRM_MODE_ROTATE_90:
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case DRM_MODE_ROTATE_270:
+		transform_tmp = top_crop_line_num + act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = vir_width - width - act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case 0:
+		transform_tmp = act_xoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = top_crop_line_num + act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = transform_tmp & 0xf;
+
+		break;
+	}
+
+	return (transform_xoffset & 0xf) | ((transform_yoffset & 0xf) << 16);
+}
+
+/*
+ * A Cluster window has 2048 x 16 line buffer, which can
+ * works at 2048 x 16(Full) or 4096 x 8 (Half) mode.
+ * for Cluster_lb_mode register:
+ * 0: half mode, for plane input width range 2048 ~ 4096
+ * 1: half mode, for cluster work at 2 * 2048 plane mode
+ * 2: half mode, for rotate_90/270 mode
+ *
+ */
+static int vop2_get_cluster_lb_mode(struct vop2_win *win, struct drm_plane_state *pstate)
+{
+	if ((pstate->rotation & DRM_MODE_ROTATE_270) || (pstate->rotation & DRM_MODE_ROTATE_90))
+		return 2;
+	else
+		return 0;
+}
+
+/*
+ * bli_sd_factor = (src - 1) / (dst - 1) << 12;
+ * avg_sd_factor:
+ * bli_su_factor:
+ * bic_su_factor:
+ * = (src - 1) / (dst - 1) << 16;
+ *
+ * gt2 enable: dst get one line from two line of the src
+ * gt4 enable: dst get one line from four line of the src.
+ *
+ */
+static uint16_t vop2_scale_factor(enum scale_mode mode,
+				  int32_t filter_mode,
+				  uint32_t src, uint32_t dst)
+{
+	uint32_t fac;
+	int i;
+
+	if (mode == SCALE_NONE)
+		return 0;
+
+	/*
+	 * A workaround to avoid zero div.
+	 */
+	if (dst == 1 || src == 1) {
+		dst++;
+		src++;
+	}
+
+	if ((mode == SCALE_DOWN) && (filter_mode == VOP2_SCALE_DOWN_BIL)) {
+		fac = ((src - 1) << 12) / (dst - 1);
+		for (i = 0; i < 100; i++) {
+			if (fac * (dst - 1) >> 12 < (src - 1))
+				break;
+			fac -= 1;
+			DRM_DEBUG("down fac cali: src:%d, dst:%d, fac:0x%x\n", src, dst, fac);
+		}
+	} else {
+		fac = ((src - 1) << 16) / (dst - 1);
+		for (i = 0; i < 100; i++) {
+			if (fac * (dst - 1) >> 16 < (src - 1))
+				break;
+			fac -= 1;
+			DRM_DEBUG("up fac cali:  src:%d, dst:%d, fac:0x%x\n", src, dst, fac);
+		}
+	}
+
+	return fac;
+}
+
+static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win,
+			     uint32_t src_w, uint32_t src_h, uint32_t dst_w,
+			     uint32_t dst_h, uint32_t pixel_format)
+{
+	const struct vop2_win_data *win_data = win->data;
+	const struct drm_format_info *info;
+	uint16_t cbcr_src_w;
+	uint16_t cbcr_src_h;
+	uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode;
+	uint16_t cbcr_hor_scl_mode, cbcr_ver_scl_mode;
+	uint16_t hscl_filter_mode, vscl_filter_mode;
+	uint8_t gt2 = 0;
+	uint8_t gt4 = 0;
+	uint32_t val;
+
+	info = drm_format_info(pixel_format);
+
+	cbcr_src_w = src_w / info->hsub;
+	cbcr_src_h = src_h / info->vsub;
+
+	if (src_h >= (4 * dst_h)) {
+		gt4 = 1;
+		src_h >>= 2;
+	} else if (src_h >= (2 * dst_h)) {
+		gt2 = 1;
+		src_h >>= 1;
+	}
+
+	yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
+	yrgb_ver_scl_mode = scl_get_scl_mode(src_h, dst_h);
+
+	if (yrgb_hor_scl_mode == SCALE_UP)
+		hscl_filter_mode = win_data->hsu_filter_mode;
+	else
+		hscl_filter_mode = win_data->hsd_filter_mode;
+
+	if (yrgb_ver_scl_mode == SCALE_UP)
+		vscl_filter_mode = win_data->vsu_filter_mode;
+	else
+		vscl_filter_mode = win_data->vsd_filter_mode;
+
+	/*
+	 * RK3568 VOP Esmart/Smart dsp_w should be even pixel
+	 * at scale down mode
+	 */
+	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
+		if ((yrgb_hor_scl_mode == SCALE_DOWN) && (dst_w & 0x1)) {
+			drm_dbg(vop2->drm, "%s dst_w[%d] should align as 2 pixel\n",
+				win->data->name, dst_w);
+			dst_w += 1;
+		}
+	}
+
+	val = vop2_scale_factor(yrgb_hor_scl_mode, hscl_filter_mode,
+				src_w, dst_w);
+	vop2_win_write(win, &win->regs->scl->scale_yrgb_x, val);
+	val = vop2_scale_factor(yrgb_ver_scl_mode, vscl_filter_mode,
+				src_h, dst_h);
+	vop2_win_write(win, &win->regs->scl->scale_yrgb_y, val);
+
+	vop2_win_write(win, &win->regs->scl->vsd_yrgb_gt4, gt4);
+	vop2_win_write(win, &win->regs->scl->vsd_yrgb_gt2, gt2);
+
+	vop2_win_write(win, &win->regs->scl->yrgb_hor_scl_mode, yrgb_hor_scl_mode);
+	vop2_win_write(win, &win->regs->scl->yrgb_ver_scl_mode, yrgb_ver_scl_mode);
+
+	vop2_win_write(win, &win->regs->scl->yrgb_hscl_filter_mode, hscl_filter_mode);
+	vop2_win_write(win, &win->regs->scl->yrgb_vscl_filter_mode, vscl_filter_mode);
+
+	if (info->is_yuv) {
+		gt4 = gt2 = 0;
+
+		if (cbcr_src_h >= (4 * dst_h))
+			gt4 = 1;
+		else if (cbcr_src_h >= (2 * dst_h))
+			gt2 = 1;
+
+		if (gt4)
+			cbcr_src_h >>= 2;
+		else if (gt2)
+			cbcr_src_h >>= 1;
+
+		cbcr_hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w);
+		cbcr_ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h);
+
+		val = vop2_scale_factor(cbcr_hor_scl_mode, hscl_filter_mode,
+					cbcr_src_w, dst_w);
+		vop2_win_write(win, &win->regs->scl->scale_cbcr_x, val);
+		val = vop2_scale_factor(cbcr_ver_scl_mode, vscl_filter_mode,
+					cbcr_src_h, dst_h);
+		vop2_win_write(win, &win->regs->scl->scale_cbcr_y, val);
+
+		vop2_win_write(win, &win->regs->scl->vsd_cbcr_gt4, gt4);
+		vop2_win_write(win, &win->regs->scl->vsd_cbcr_gt2, gt2);
+		vop2_win_write(win, &win->regs->scl->cbcr_hor_scl_mode, cbcr_hor_scl_mode);
+		vop2_win_write(win, &win->regs->scl->cbcr_ver_scl_mode, cbcr_ver_scl_mode);
+		vop2_win_write(win, &win->regs->scl->cbcr_hscl_filter_mode, hscl_filter_mode);
+		vop2_win_write(win, &win->regs->scl->cbcr_vscl_filter_mode, vscl_filter_mode);
+	}
+}
+
+static int vop2_convert_csc_mode(int csc_mode)
+{
+	switch (csc_mode) {
+	case V4L2_COLORSPACE_SMPTE170M:
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+		return CSC_BT601L;
+	case V4L2_COLORSPACE_REC709:
+	case V4L2_COLORSPACE_SMPTE240M:
+	case V4L2_COLORSPACE_DEFAULT:
+		return CSC_BT709L;
+	case V4L2_COLORSPACE_JPEG:
+		return CSC_BT601F;
+	case V4L2_COLORSPACE_BT2020:
+		return CSC_BT2020;
+	default:
+		return CSC_BT709L;
+	}
+}
+
+/*
+ * colorspace path:
+ *      Input        Win csc                     Output
+ * 1. YUV(2020)  --> Y2R->2020To709->R2Y   --> YUV_OUTPUT(601/709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 2. YUV(2020)  --> bypasss               --> YUV_OUTPUT(2020)
+ *    RGB        --> 709To2020->R2Y       __/
+ *
+ * 3. YUV(2020)  --> Y2R->2020To709        --> RGB_OUTPUT(709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 4. YUV(601/709)-> Y2R->709To2020->R2Y   --> YUV_OUTPUT(2020)
+ *    RGB        --> 709To2020->R2Y       __/
+ *
+ * 5. YUV(601/709)-> bypass                --> YUV_OUTPUT(709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 6. YUV(601/709)-> bypass                --> YUV_OUTPUT(601)
+ *    RGB        --> R2Y(601)             __/
+ *
+ * 7. YUV        --> Y2R(709)              --> RGB_OUTPUT(709)
+ *    RGB        --> bypass               __/
+ *
+ * 8. RGB        --> 709To2020->R2Y        --> YUV_OUTPUT(2020)
+ *
+ * 9. RGB        --> R2Y(709)              --> YUV_OUTPUT(709)
+ *
+ * 10. RGB       --> R2Y(601)              --> YUV_OUTPUT(601)
+ *
+ * 11. RGB       --> bypass                --> RGB_OUTPUT(709)
+ */
+
+static void vop2_setup_csc_mode(struct vop2_video_port *vp,
+				struct vop2_win *win,
+				struct drm_plane_state *pstate)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);
+	int is_input_yuv = pstate->fb->format->is_yuv;
+	int is_output_yuv = is_yuv_output(vcstate->bus_format);
+	int input_csc = V4L2_COLORSPACE_DEFAULT;
+	int output_csc = vcstate->color_space;
+	bool r2y_en, y2r_en;
+	int csc_mode;
+
+	if (is_input_yuv && !is_output_yuv) {
+		y2r_en = 1;
+		r2y_en = 0;
+		csc_mode = vop2_convert_csc_mode(input_csc);
+	} else if (!is_input_yuv && is_output_yuv) {
+		y2r_en = 0;
+		r2y_en = 1;
+		csc_mode = vop2_convert_csc_mode(output_csc);
+	} else {
+		y2r_en = 0;
+		r2y_en = 0;
+		csc_mode = 0;
+	}
+
+	vop2_win_write(win, &win->regs->y2r_en, y2r_en);
+	vop2_win_write(win, &win->regs->r2y_en, r2y_en);
+	vop2_win_write(win, &win->regs->csc_mode, csc_mode);
+}
+
+static void vop2_crtc_enable_irq(struct vop2_video_port *vp, uint32_t irq)
+{
+	struct vop2 *vop2 = vp->vop2;
+
+	vop2_writel(vop2, vp->data->regs->irq_clear, irq << 16 | irq);
+	vop2_writel(vop2, vp->data->regs->irq_enable, irq << 16 | irq);
+}
+
+static void vop2_crtc_disable_irq(struct vop2_video_port *vp, uint32_t irq)
+{
+	struct vop2 *vop2 = vp->vop2;
+
+	vop2_writel(vop2, vp->data->regs->irq_enable, irq << 16);
+}
+
+static int vop2_core_clks_prepare_enable(struct vop2 *vop2)
+{
+	int ret;
+
+	ret = clk_prepare_enable(vop2->hclk);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to enable hclk - %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(vop2->aclk);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to enable aclk - %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+err:
+	clk_disable_unprepare(vop2->hclk);
+
+	return ret;
+}
+
+static void vop2_enable(struct vop2 *vop2)
+{
+	int ret;
+	uint32_t v;
+
+	ret = pm_runtime_get_sync(vop2->dev);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to get pm runtime: %d\n", ret);
+		return;
+	}
+
+	ret = vop2_core_clks_prepare_enable(vop2);
+	if (ret) {
+		pm_runtime_put_sync(vop2->dev);
+		return;
+	}
+
+	if (vop2->data->soc_id == 3566)
+		vop2_writel(vop2, RK3568_OTP_WIN_EN, 1);
+
+	memcpy(vop2->regsbak, vop2->regs, vop2->len);
+	vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
+
+	/*
+	 * Disable auto gating, this is a workaround to
+	 * avoid display image shift when a window enabled.
+	 */
+	v = vop2_readl(vop2, RK3568_SYS_AUTO_GATING_CTRL);
+	v &= ~RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN;
+	vop2_writel(vop2, RK3568_SYS_AUTO_GATING_CTRL, v);
+
+	vop2_writel(vop2, RK3568_SYS0_INT_CLR,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+	vop2_writel(vop2, RK3568_SYS0_INT_EN,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+	vop2_writel(vop2, RK3568_SYS1_INT_CLR,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+	vop2_writel(vop2, RK3568_SYS1_INT_EN,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+}
+
+static void vop2_disable(struct vop2 *vop2)
+{
+	pm_runtime_put_sync(vop2->dev);
+
+	clk_disable_unprepare(vop2->aclk);
+	clk_disable_unprepare(vop2->hclk);
+}
+
+static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
+				     struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	int ret;
+
+	vop2_lock(vop2);
+
+	drm_crtc_vblank_off(crtc);
+
+	/*
+	 * Vop standby will take effect at end of current frame,
+	 * if dsp hold valid irq happen, it means standby complete.
+	 *
+	 * we must wait standby complete when we want to disable aclk,
+	 * if not, memory bus maybe dead.
+	 */
+	reinit_completion(&vp->dsp_hold_completion);
+
+	vop2_crtc_enable_irq(vp, VP_INT_DSP_HOLD_VALID);
+	spin_lock(&vop2->reg_lock);
+
+	vop2_writel(vop2, vp->data->regs->dsp_ctrl, 1);
+
+	spin_unlock(&vop2->reg_lock);
+
+	ret = wait_for_completion_timeout(&vp->dsp_hold_completion, msecs_to_jiffies(50));
+	if (!ret)
+		drm_info(vop2->drm, "wait for vp%d dsp_hold timeout\n", vp->id);
+
+	vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID);
+
+	clk_disable_unprepare(vp->dclk);
+
+	vop2->enable_count--;
+
+	if (!vop2->enable_count)
+		vop2_disable(vop2);
+
+	vop2_unlock(vop2);
+
+	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 int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *astate)
+{
+	struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(astate, plane);
+	struct vop2_win *win = to_vop2_win(plane);
+	struct drm_framebuffer *fb = pstate->fb;
+	struct drm_crtc *crtc = pstate->crtc;
+	struct drm_crtc_state *cstate;
+	struct vop2_video_port *vp;
+	struct vop2 *vop2;
+	const struct vop2_data *vop2_data;
+	struct drm_rect *dest = &pstate->dst;
+	struct drm_rect *src = &pstate->src;
+	int min_scale = win->regs->scl ? FRAC_16_16(1, 8) : DRM_PLANE_HELPER_NO_SCALING;
+	int max_scale = win->regs->scl ? FRAC_16_16(8, 1) : DRM_PLANE_HELPER_NO_SCALING;
+	int format;
+	int ret;
+
+	if (!crtc)
+		return 0;
+
+	vp = to_vop2_video_port(crtc);
+	vop2 = vp->vop2;
+	vop2_data = vop2->data;
+
+	cstate = drm_atomic_get_existing_crtc_state(pstate->state, crtc);
+	if (WARN_ON(!cstate))
+		return -EINVAL;
+
+	ret = drm_atomic_helper_check_plane_state(pstate, cstate,
+						  min_scale, max_scale,
+						  true, true);
+	if (ret)
+		return ret;
+
+	if (!pstate->visible)
+		return 0;
+
+	format = vop2_convert_format(fb->format->format);
+	if (format < 0)
+		return format;
+
+	if (drm_rect_width(src) >> 16 < 4 || drm_rect_height(src) >> 16 < 4 ||
+	    drm_rect_width(dest) < 4 || drm_rect_width(dest) < 4) {
+		drm_err(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n",
+			  drm_rect_width(src) >> 16, drm_rect_height(src) >> 16,
+			  drm_rect_width(dest), drm_rect_height(dest));
+		pstate->visible = false;
+		return 0;
+	}
+
+	if (drm_rect_width(src) >> 16 > vop2_data->max_input.width ||
+	    drm_rect_height(src) >> 16 > vop2_data->max_input.height) {
+		drm_err(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n",
+			  drm_rect_width(src) >> 16,
+			  drm_rect_height(src) >> 16,
+			  vop2_data->max_input.width,
+			  vop2_data->max_input.height);
+		return -EINVAL;
+	}
+
+	/*
+	 * Src.x1 can be odd when do clip, but yuv plane start point
+	 * need align with 2 pixel.
+	 */
+	if (fb->format->is_yuv && ((pstate->src.x1 >> 16) % 2)) {
+		drm_err(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void vop2_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+	struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state, plane);
+	struct vop2_win *win = to_vop2_win(plane);
+	struct vop2 *vop2 = win->vop2;
+
+	drm_dbg(vop2->drm, "%s disable\n", win->data->name);
+
+	if (!old_pstate->crtc)
+		return;
+
+	spin_lock(&vop2->reg_lock);
+
+	vop2_win_disable(win);
+	vop2_win_write(win, &win->regs->yuv_clip, 0);
+
+	spin_unlock(&vop2->reg_lock);
+}
+
+/*
+ * The color key is 10 bit, so all format should
+ * convert to 10 bit here.
+ */
+static void vop2_plane_setup_color_key(struct drm_plane *plane, uint32_t color_key)
+{
+	struct drm_plane_state *pstate = plane->state;
+	struct drm_framebuffer *fb = pstate->fb;
+	struct vop2_win *win = to_vop2_win(plane);
+	uint32_t color_key_en = 0;
+	uint32_t r = 0;
+	uint32_t g = 0;
+	uint32_t b = 0;
+
+	if (!(color_key & VOP2_COLOR_KEY_MASK) || fb->format->is_yuv) {
+		vop2_win_write(win, &win->regs->color_key_en, 0);
+		return;
+	}
+
+	switch (fb->format->format) {
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		r = (color_key & 0xf800) >> 11;
+		g = (color_key & 0x7e0) >> 5;
+		b = (color_key & 0x1f);
+		r <<= 5;
+		g <<= 4;
+		b <<= 5;
+		color_key_en = 1;
+		break;
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		r = (color_key & 0xff0000) >> 16;
+		g = (color_key & 0xff00) >> 8;
+		b = (color_key & 0xff);
+		r <<= 2;
+		g <<= 2;
+		b <<= 2;
+		color_key_en = 1;
+		break;
+	}
+
+	vop2_win_write(win, &win->regs->color_key_en, color_key_en);
+	vop2_win_write(win, &win->regs->color_key, (r << 20) | (g << 10) | b);
+}
+
+static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+	struct drm_plane_state *pstate = plane->state;
+	struct drm_crtc *crtc = pstate->crtc;
+	struct vop2_win *win = to_vop2_win(plane);
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
+	struct vop2 *vop2 = win->vop2;
+	struct drm_framebuffer *fb = pstate->fb;
+	uint32_t bpp = fb->format->cpp[0] * 8;
+	uint32_t actual_w, actual_h, dsp_w, dsp_h;
+	uint32_t act_info, dsp_info;
+	uint32_t format;
+	uint32_t afbc_format;
+	uint32_t rb_swap;
+	uint32_t uv_swap;
+	struct drm_rect *src = &pstate->src;
+	struct drm_rect *dest = &pstate->dst;
+	uint32_t afbc_tile_num;
+	uint32_t afbc_half_block_en;
+	uint32_t transform_offset;
+	bool dither_up;
+	bool xmirror = pstate->rotation & DRM_MODE_REFLECT_X;
+	bool ymirror = pstate->rotation & DRM_MODE_REFLECT_Y;
+	bool rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270;
+	bool rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90;
+	struct rockchip_gem_object *rk_obj;
+	unsigned long offset;
+	bool afbc_en;
+	dma_addr_t yrgb_mst;
+	dma_addr_t uv_mst;
+
+	/*
+	 * can't update plane when vop2 is disabled.
+	 */
+	if (WARN_ON(!crtc))
+		return;
+
+	if (!pstate->visible) {
+		vop2_plane_atomic_disable(plane, state);
+		return;
+	}
+
+	afbc_en = rockchip_afbc(plane, fb->modifier);
+
+	offset = (src->x1 >> 16) * fb->format->cpp[0];
+
+	/*
+	 * AFBC HDR_PTR must set to the zero offset of the framebuffer.
+	 */
+	if (afbc_en)
+		offset = 0;
+	else if (pstate->rotation & DRM_MODE_REFLECT_Y)
+		offset += ((src->y2 >> 16) - 1) * fb->pitches[0];
+	else
+		offset += (src->y1 >> 16) * fb->pitches[0];
+
+	rk_obj = to_rockchip_obj(fb->obj[0]);
+
+	yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];
+	if (fb->format->is_yuv) {
+		int hsub = fb->format->hsub;
+		int vsub = fb->format->vsub;
+
+		offset = (src->x1 >> 16) * fb->format->cpp[1] / hsub;
+		offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
+
+		if ((pstate->rotation & DRM_MODE_REFLECT_Y) && !afbc_en)
+			offset += fb->pitches[1] * ((pstate->src_h >> 16) - 2)  / vsub;
+
+		rk_obj = to_rockchip_obj(fb->obj[0]);
+		uv_mst = rk_obj->dma_addr + offset + fb->offsets[1];
+	}
+
+	actual_w = drm_rect_width(src) >> 16;
+	actual_h = drm_rect_height(src) >> 16;
+	dsp_w = drm_rect_width(dest);
+
+	if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
+		drm_err(vop2->drm, "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",
+			  vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay);
+		dsp_w = adjusted_mode->hdisplay - dest->x1;
+		if (dsp_w < 4)
+			dsp_w = 4;
+		actual_w = dsp_w * actual_w / drm_rect_width(dest);
+	}
+
+	dsp_h = drm_rect_height(dest);
+
+	if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
+		drm_err(vop2->drm, "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
+			  vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
+		dsp_h = adjusted_mode->vdisplay - dest->y1;
+		if (dsp_h < 4)
+			dsp_h = 4;
+		actual_h = dsp_h * actual_h / drm_rect_height(dest);
+	}
+
+	/*
+	 * This is workaround solution for IC design:
+	 * esmart can't support scale down when actual_w % 16 == 1.
+	 */
+	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
+		if (actual_w > dsp_w && (actual_w & 0xf) == 1) {
+			drm_err(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n", vp->id, win->data->name, actual_w);
+			actual_w -= 1;
+		}
+	}
+
+	if (afbc_en && actual_w % 4) {
+		drm_err(vop2->drm, "vp%d %s actual_w[%d] should align as 4 pixel when enable afbc\n",
+			  vp->id, win->data->name, actual_w);
+		actual_w = ALIGN_DOWN(actual_w, 4);
+	}
+
+	act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
+	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
+
+	format = vop2_convert_format(fb->format->format);
+
+	spin_lock(&vop2->reg_lock);
+	drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n",
+		      vp->id, win->data->name, actual_w, actual_h, dsp_w, dsp_h,
+		      dest->x1, dest->y1,
+		      &fb->format->format,
+		      afbc_en ? "AFBC" : "", &yrgb_mst);
+
+	if (afbc_en) {
+		uint32_t stride;
+
+		/* the afbc superblock is 16 x 16 */
+		afbc_format = vop2_convert_afbc_format(fb->format->format);
+
+		/* Enable color transform for YTR */
+		if (fb->modifier & AFBC_FORMAT_MOD_YTR)
+			afbc_format |= (1 << 4);
+
+		afbc_tile_num = ALIGN(actual_w, 16) >> 4;
+
+		/*
+		 * AFBC pic_vir_width is count by pixel, this is different
+		 * with WIN_VIR_STRIDE.
+		 */
+		stride = (fb->pitches[0] << 3) / bpp;
+		if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270))
+			drm_err(vop2->drm, "vp%d %s stride[%d] must align as 64 pixel when enable xmirror/rotate_90/rotate_270[0x%x]\n",
+				  vp->id, win->data->name, stride, pstate->rotation);
+
+		rb_swap = vop2_afbc_rb_swap(fb->format->format);
+		uv_swap = vop2_afbc_uv_swap(fb->format->format);
+		/*
+		 * This is a workaround for crazy IC design, Cluster
+		 * and Esmart/Smart use different format configuration map:
+		 * YUV420_10BIT: 0x10 for Cluster, 0x14 for Esmart/Smart.
+		 *
+		 * This is one thing we can make the convert simple:
+		 * AFBCD decode all the YUV data to YUV444. So we just
+		 * set all the yuv 10 bit to YUV444_10.
+		 */
+		if (fb->format->is_yuv && (bpp == 10))
+			format = VOP2_CLUSTER_YUV444_10;
+
+		afbc_half_block_en = vop2_afbc_half_block_enable(pstate);
+		transform_offset = vop2_afbc_transform_offset(pstate, afbc_half_block_en);
+		if (vop2_cluster_window(win))
+			vop2_win_write(win, &win->regs->cluster->afbc_enable, 1);
+		vop2_win_write(win, &win->regs->afbc->format, afbc_format);
+		vop2_win_write(win, &win->regs->afbc->rb_swap, rb_swap);
+		vop2_win_write(win, &win->regs->afbc->uv_swap, uv_swap);
+		vop2_win_write(win, &win->regs->afbc->auto_gating_en, 0);
+		vop2_win_write(win, &win->regs->afbc->block_split_en, 0);
+		vop2_win_write(win, &win->regs->afbc->half_block_en, afbc_half_block_en);
+		vop2_win_write(win, &win->regs->afbc->hdr_ptr, yrgb_mst);
+		vop2_win_write(win, &win->regs->afbc->pic_size, act_info);
+		vop2_win_write(win, &win->regs->afbc->transform_offset, transform_offset);
+		vop2_win_write(win, &win->regs->afbc->pic_offset, ((src->x1 >> 16) | src->y1));
+		vop2_win_write(win, &win->regs->afbc->dsp_offset, (dest->x1 | (dest->y1 << 16)));
+		vop2_win_write(win, &win->regs->afbc->pic_vir_width, stride);
+		vop2_win_write(win, &win->regs->afbc->tile_num, afbc_tile_num);
+		vop2_win_write(win, &win->regs->afbc->xmirror, xmirror);
+		vop2_win_write(win, &win->regs->afbc->ymirror, ymirror);
+		vop2_win_write(win, &win->regs->afbc->rotate_270, rotate_270);
+		vop2_win_write(win, &win->regs->afbc->rotate_90, rotate_90);
+	} else {
+		if (win->regs->afbc)
+			vop2_win_write(win, &win->regs->afbc->enable, 0);
+		vop2_win_write(win, &win->regs->ymirror, ymirror);
+		vop2_win_write(win, &win->regs->xmirror, xmirror);
+		vop2_win_write(win, &win->regs->yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
+	}
+
+	if (rotate_90 || rotate_270) {
+		act_info = swahw32(act_info);
+		actual_w = drm_rect_height(src) >> 16;
+		actual_h = drm_rect_width(src) >> 16;
+	}
+
+	vop2_win_write(win, &win->regs->format, format);
+	vop2_win_write(win, &win->regs->yrgb_mst, yrgb_mst);
+
+	rb_swap = vop2_win_rb_swap(fb->format->format);
+	uv_swap = vop2_win_uv_swap(fb->format->format);
+	vop2_win_write(win, &win->regs->rb_swap, rb_swap);
+	vop2_win_write(win, &win->regs->uv_swap, uv_swap);
+
+	if (fb->format->is_yuv) {
+		vop2_win_write(win, &win->regs->uv_vir, DIV_ROUND_UP(fb->pitches[1], 4));
+		vop2_win_write(win, &win->regs->uv_mst, uv_mst);
+	}
+
+	vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format);
+	vop2_plane_setup_color_key(plane, 0);
+	vop2_win_write(win, &win->regs->act_info, act_info);
+	vop2_win_write(win, &win->regs->dsp_info, dsp_info);
+	vop2_win_write(win, &win->regs->dsp_st, dest->y1 << 16 | (dest->x1 & 0xffff));
+
+	vop2_setup_csc_mode(vp, win, pstate);
+
+	dither_up = vop2_win_dither_up(fb->format->format);
+	vop2_win_write(win, &win->regs->dither_up, dither_up);
+
+	vop2_win_write(win, &win->regs->enable, 1);
+
+	if (vop2_cluster_window(win)) {
+		int lb_mode = vop2_get_cluster_lb_mode(win, pstate);
+
+		vop2_win_write(win, &win->regs->cluster->lb_mode, lb_mode);
+		vop2_win_write(win, &win->regs->cluster->enable, 1);
+	}
+
+	spin_unlock(&vop2->reg_lock);
+}
+
+static const struct drm_plane_helper_funcs vop2_plane_helper_funcs = {
+	.atomic_check = vop2_plane_atomic_check,
+	.atomic_update = vop2_plane_atomic_update,
+	.atomic_disable = vop2_plane_atomic_disable,
+};
+
+static const struct drm_plane_funcs vop2_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.destroy = drm_plane_cleanup,
+	.reset = drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+	.format_mod_supported = rockchip_vop2_mod_supported,
+};
+
+static int vop2_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+
+	vop2_crtc_enable_irq(vp, VP_INT_FS_FIELD);
+
+	return 0;
+}
+
+static void vop2_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+
+	vop2_crtc_disable_irq(vp, VP_INT_FS_FIELD);
+}
+
+static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc,
+				 const struct drm_display_mode *mode,
+				 struct drm_display_mode *adj_mode)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+
+	drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE);
+
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		adj_mode->crtc_clock *= 2;
+
+	adj_mode->crtc_clock = DIV_ROUND_UP(clk_round_rate(vp->dclk,
+							   adj_mode->crtc_clock * 1000), 1000);
+
+	return true;
+}
+
+static void vop2_dither_setup(struct drm_crtc *crtc, uint32_t *dsp_ctrl)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+
+	switch (vcstate->bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
+		*dsp_ctrl |= RGB888_TO_RGB666;
+		break;
+	case MEDIA_BUS_FMT_YUV8_1X24:
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
+		break;
+	default:
+		break;
+	}
+
+	if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA)
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
+
+	*dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
+				DITHER_DOWN_ALLEGRO);
+}
+
+static void vop2_post_config(struct drm_crtc *crtc)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	uint16_t vtotal = mode->crtc_vtotal;
+	uint16_t hdisplay = mode->crtc_hdisplay;
+	uint16_t hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
+	uint16_t vdisplay = mode->crtc_vdisplay;
+	uint16_t vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
+	uint32_t left_margin = 100, right_margin = 100, top_margin = 100, bottom_margin = 100;
+	uint16_t hsize = hdisplay * (left_margin + right_margin) / 200;
+	uint16_t vsize = vdisplay * (top_margin + bottom_margin) / 200;
+	uint16_t hact_end, vact_end;
+	uint32_t val;
+
+	vsize = rounddown(vsize, 2);
+	hsize = rounddown(hsize, 2);
+	hact_st += hdisplay * (100 - left_margin) / 200;
+	hact_end = hact_st + hsize;
+	val = hact_st << 16;
+	val |= hact_end;
+	vop2_writel(vop2, vp->regs->hpost_st_end, val);
+	vact_st += vdisplay * (100 - top_margin) / 200;
+	vact_end = vact_st + vsize;
+	val = vact_st << 16;
+	val |= vact_end;
+	vop2_writel(vop2, vp->regs->vpost_st_end, val);
+	val = scl_cal_scale2(vdisplay, vsize) << 16;
+	val |= scl_cal_scale2(hdisplay, hsize);
+	vop2_writel(vop2, vp->regs->post_scl_factor, val);
+
+	val = 0;
+	if (hdisplay != hsize)
+		val |= RK3568_VP_POST_SCL_CTRL__HSCALEDOWN;
+	if (vdisplay != vsize)
+		val |= RK3568_VP_POST_SCL_CTRL__VSCALEDOWN;
+	vop2_writel(vop2, RK3568_VP0_POST_SCL_CTRL, val);
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+		uint16_t vact_st_f1 = vtotal + vact_st + 1;
+		uint16_t vact_end_f1 = vact_st_f1 + vsize;
+
+		val = vact_st_f1 << 16 | vact_end_f1;
+		vop2_writel(vop2, vp->regs->vpost_st_end_f1, val);
+	}
+
+	vop2_writel(vop2, vp->regs->dsp_background, 0);
+}
+
+static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id,
+				uint32_t polflags)
+{
+	struct vop2 *vop2 = vp->vop2;
+	uint32_t die, dip;
+
+	die = vop2_readl(vop2, RK3568_DSP_IF_EN);
+	dip = vop2_readl(vop2, RK3568_DSP_IF_POL);
+
+	switch (id) {
+	case RK3568_VOP2_EP_RGB:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_RGB_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_RGB |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_RGB_MUX, vp->id);
+		if (polflags & POLFLAG_DCLK_INV)
+			vop2_grf_writel(vop2, &vop2->data->grf_ctrl->grf_dclk_inv, 1);
+		else
+			vop2_grf_writel(vop2, &vop2->data->grf_ctrl->grf_dclk_inv, 0);
+		break;
+	case RK3568_VOP2_EP_HDMI:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_HDMI_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_HDMI |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_HDMI_MUX, vp->id);
+		break;
+	case RK3568_VOP2_EP_EDP:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_EDP_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_EDP |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_EDP_MUX, vp->id);
+		break;
+	case RK3568_VOP2_EP_MIPI0:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_MIPI0 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags);
+		break;
+	case RK3568_VOP2_EP_MIPI1:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_MIPI1 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags);
+		break;
+	case RK3568_VOP2_EP_LVDS0:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_LVDS0 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);
+		break;
+	case RK3568_VOP2_EP_LVDS1:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_LVDS1 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);
+		break;
+	default:
+		return;
+	};
+
+	dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD;
+
+	vop2_writel(vop2, RK3568_DSP_IF_EN, die);
+	vop2_writel(vop2, RK3568_DSP_IF_POL, dip);
+}
+
+static int us_to_vertical_line(struct drm_display_mode *mode, int us)
+{
+	return us * mode->clock / mode->htotal / 1000;
+}
+
+static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	const struct vop2_data *vop2_data = vop2->data;
+	const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+	struct drm_display_mode *mode = &crtc->state->mode;
+	uint16_t hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+	uint16_t hdisplay = mode->crtc_hdisplay;
+	uint16_t htotal = mode->crtc_htotal;
+	uint16_t hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
+	uint16_t hact_end = hact_st + hdisplay;
+	uint16_t vdisplay = mode->crtc_vdisplay;
+	uint16_t vtotal = mode->crtc_vtotal;
+	uint16_t vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+	uint16_t vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
+	uint16_t vact_end = vact_st + vdisplay;
+	uint8_t out_mode;
+	uint32_t dsp_ctrl = 0;
+	int act_end;
+	uint32_t val, polflags;
+	int ret;
+	struct drm_encoder *encoder;
+
+	drm_dbg(vop2->drm, "Update mode to %dx%d%s%d, type: %d for vp%d\n",
+		hdisplay, vdisplay, mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p",
+		drm_mode_vrefresh(mode), vcstate->output_type, vp->id);
+
+	vop2_lock(vop2);
+
+	ret = clk_prepare_enable(vp->dclk);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to enable dclk for video port%d - %d\n",
+			      vp->id, ret);
+		return;
+	}
+
+	if (!vop2->enable_count)
+		vop2_enable(vop2);
+
+	vop2->enable_count++;
+
+	vop2_crtc_enable_irq(vp, VP_INT_POST_BUF_EMPTY);
+
+	polflags = 0;
+	if (vcstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
+		polflags |= POLFLAG_DCLK_INV;
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		polflags |= BIT(HSYNC_POSITIVE);
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		polflags |= BIT(VSYNC_POSITIVE);
+
+	drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) {
+		struct device_node *node, *parent;
+
+		parent = of_get_parent(encoder->port);
+
+		for_each_endpoint_of_node(parent, node) {
+			struct device_node *crtc_port = of_graph_get_remote_port(node);
+			struct device_node *epn;
+			struct of_endpoint endpoint;
+
+			if (crtc->port != crtc_port) {
+				of_node_put(crtc_port);
+				continue;
+			}
+
+			of_node_put(crtc_port);
+
+			epn = of_graph_get_remote_endpoint(node);
+			of_graph_parse_endpoint(epn, &endpoint);
+			of_node_put(epn);
+
+			drm_dbg(vop2->drm, "vp%d is connected to %s, id %d\n",
+					   vp->id, encoder->name, endpoint.id);
+			rk3568_set_intf_mux(vp, endpoint.id, polflags);
+		}
+		of_node_put(parent);
+	}
+
+	if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
+	     !(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT))
+		out_mode = ROCKCHIP_OUT_MODE_P888;
+	else
+		out_mode = vcstate->output_mode;
+
+	dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__OUT_MODE, out_mode);
+
+	if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode))
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RB_SWAP;
+
+	if (is_yuv_output(vcstate->bus_format))
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y;
+
+	vop2_dither_setup(crtc, &dsp_ctrl);
+
+	vop2_writel(vop2, vp->regs->htotal_pw, (htotal << 16) | hsync_len);
+	val = hact_st << 16;
+	val |= hact_end;
+	vop2_writel(vop2, vp->regs->hact_st_end, val);
+
+	val = vact_st << 16;
+	val |= vact_end;
+	vop2_writel(vop2, vp->regs->vact_st_end, val);
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+		uint16_t vact_st_f1 = vtotal + vact_st + 1;
+		uint16_t vact_end_f1 = vact_st_f1 + vdisplay;
+
+		val = vact_st_f1 << 16 | vact_end_f1;
+		vop2_writel(vop2, vp->regs->vact_st_end_f1, val);
+
+		val = vtotal << 16 | (vtotal + vsync_len);
+		vop2_writel(vop2, vp->regs->vs_st_end_f1, val);
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_INTERLACE;
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_FILED_POL;
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__P2I_EN;
+		vtotal += vtotal + 1;
+		act_end = vact_end_f1;
+	} else {
+		act_end = vact_end;
+	}
+
+	vop2_writel(vop2, vp->data->regs->line_flag,
+		    (act_end - us_to_vertical_line(mode, 0)) << 16 | act_end);
+
+	vop2_writel(vop2, vp->regs->vtotal_pw, vtotal << 16 | vsync_len);
+
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV;
+
+	vop2_writel(vop2, vp->regs->mipi_ctrl, 0);
+
+	clk_set_rate(vp->dclk, mode->crtc_clock * 1000);
+
+	vop2_post_config(crtc);
+
+	vop2_cfg_done(vp);
+
+	vop2_writel(vop2, vp->regs->dsp_ctrl, dsp_ctrl);
+
+	drm_crtc_vblank_on(crtc);
+
+	vop2_unlock(vop2);
+}
+
+static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
+				  struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct drm_plane *plane;
+	int nplanes = 0;
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+
+	drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
+		nplanes++;
+
+	if (nplanes > vp->nlayers)
+		return -EINVAL;
+
+	return 0;
+}
+
+static bool is_opaque(uint16_t alpha)
+{
+	return (alpha >> 8) == 0xff;
+}
+
+static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config,
+			     struct vop2_alpha *alpha)
+{
+	int src_glb_alpha_en = is_opaque(alpha_config->src_glb_alpha_value) ? 0 : 1;
+	int dst_glb_alpha_en = is_opaque(alpha_config->dst_glb_alpha_value) ? 0 : 1;
+	int src_color_mode = alpha_config->src_premulti_en ? ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL;
+	int dst_color_mode = alpha_config->dst_premulti_en ? ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL;
+
+	alpha->src_color_ctrl.val = 0;
+	alpha->dst_color_ctrl.val = 0;
+	alpha->src_alpha_ctrl.val = 0;
+	alpha->dst_alpha_ctrl.val = 0;
+
+	if (!alpha_config->src_pixel_alpha_en)
+		alpha->src_color_ctrl.bits.blend_mode = ALPHA_GLOBAL;
+	else if (alpha_config->src_pixel_alpha_en && !src_glb_alpha_en)
+		alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX;
+	else
+		alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL;
+
+	alpha->src_color_ctrl.bits.alpha_en = 1;
+
+	if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_GLOBAL) {
+		alpha->src_color_ctrl.bits.color_mode = src_color_mode;
+		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL;
+	} else if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_PER_PIX) {
+		alpha->src_color_ctrl.bits.color_mode = src_color_mode;
+		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_ONE;
+	} else {
+		alpha->src_color_ctrl.bits.color_mode = ALPHA_SRC_PRE_MUL;
+		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL;
+	}
+	alpha->src_color_ctrl.bits.glb_alpha = alpha_config->src_glb_alpha_value >> 8;
+	alpha->src_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	alpha->src_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
+
+	alpha->dst_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	alpha->dst_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
+	alpha->dst_color_ctrl.bits.blend_mode = ALPHA_GLOBAL;
+	alpha->dst_color_ctrl.bits.glb_alpha = alpha_config->dst_glb_alpha_value >> 8;
+	alpha->dst_color_ctrl.bits.color_mode = dst_color_mode;
+	alpha->dst_color_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
+
+	alpha->src_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	alpha->src_alpha_ctrl.bits.blend_mode = alpha->src_color_ctrl.bits.blend_mode;
+	alpha->src_alpha_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
+	alpha->src_alpha_ctrl.bits.factor_mode = ALPHA_ONE;
+
+	alpha->dst_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	if (alpha_config->dst_pixel_alpha_en && !dst_glb_alpha_en)
+		alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX;
+	else
+		alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL;
+	alpha->dst_alpha_ctrl.bits.alpha_cal_mode = ALPHA_NO_SATURATION;
+	alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
+}
+
+static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, uint8_t port_id)
+{
+	struct vop2_video_port *vp;
+	int used_layer = 0;
+	int i;
+
+	for (i = 0; i < port_id; i++) {
+		vp = &vop2->vps[i];
+		used_layer += hweight32(vp->win_mask);
+	}
+
+	return used_layer;
+}
+
+static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win)
+{
+	uint32_t offset = (main_win->data->phys_id * 0x10);
+	struct vop2_alpha_config alpha_config;
+	struct vop2_alpha alpha;
+	struct drm_plane_state *top_win_pstate;
+	struct drm_plane_state *bottom_win_pstate;
+	bool src_pixel_alpha_en = false;
+	uint16_t src_glb_alpha_val, dst_glb_alpha_val;
+	bool premulti_en = false;
+	bool swap = false;
+
+	/* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */
+	top_win_pstate = NULL;
+	bottom_win_pstate = main_win->base.state;
+	src_glb_alpha_val = 0;
+	dst_glb_alpha_val = main_win->base.state->alpha;
+
+	if (!bottom_win_pstate->fb)
+		return;
+
+	alpha_config.src_premulti_en = premulti_en;
+	alpha_config.dst_premulti_en = false;
+	alpha_config.src_pixel_alpha_en = src_pixel_alpha_en;
+	alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
+	alpha_config.src_glb_alpha_value = src_glb_alpha_val;
+	alpha_config.dst_glb_alpha_value = dst_glb_alpha_val;
+	vop2_parse_alpha(&alpha_config, &alpha);
+
+	alpha.src_color_ctrl.bits.src_dst_swap = swap;
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset,
+		    alpha.src_color_ctrl.val);
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset,
+		    alpha.dst_color_ctrl.val);
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset,
+		    alpha.src_alpha_ctrl.val);
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset,
+		    alpha.dst_alpha_ctrl.val);
+}
+
+static void vop2_setup_alpha(struct vop2_video_port *vp)
+{
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_framebuffer *fb;
+	struct vop2_alpha_config alpha_config;
+	struct vop2_alpha alpha;
+	struct drm_plane *plane;
+	int pixel_alpha_en;
+	int premulti_en, gpremulti_en = 0;
+	int mixer_id;
+	uint32_t offset;
+	bool bottom_layer_alpha_en = false;
+	uint32_t dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE;
+
+	mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id);
+	alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
+
+	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+
+		if (plane->state->normalized_zpos == 0 &&
+		    !is_opaque(plane->state->alpha) &&
+		    !vop2_cluster_window(win)) {
+			/*
+			 * If bottom layer have global alpha effect [except cluster layer,
+			 * because cluster have deal with bottom layer global alpha value
+			 * at cluster mix], bottom layer mix need deal with global alpha.
+			 */
+			bottom_layer_alpha_en = true;
+			dst_global_alpha = plane->state->alpha;
+		}
+	}
+
+	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+		int zpos = plane->state->normalized_zpos;
+
+		if (plane->state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
+			premulti_en = 1;
+		else
+			premulti_en = 0;
+
+		plane = &win->base;
+		fb = plane->state->fb;
+
+		pixel_alpha_en = fb->format->has_alpha;
+
+		alpha_config.src_premulti_en = premulti_en;
+
+		if (bottom_layer_alpha_en && zpos == 1) {
+			gpremulti_en = premulti_en;
+			/* Cd = Cs + (1 - As) * Cd * Agd */
+			alpha_config.dst_premulti_en = false;
+			alpha_config.src_pixel_alpha_en = pixel_alpha_en;
+			alpha_config.src_glb_alpha_value = plane->state->alpha;
+			alpha_config.dst_glb_alpha_value = dst_global_alpha;
+		} else if (vop2_cluster_window(win)) {
+			/* Mix output data only have pixel alpha */
+			alpha_config.dst_premulti_en = true;
+			alpha_config.src_pixel_alpha_en = true;
+			alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+		} else {
+			/* Cd = Cs + (1 - As) * Cd */
+			alpha_config.dst_premulti_en = true;
+			alpha_config.src_pixel_alpha_en = pixel_alpha_en;
+			alpha_config.src_glb_alpha_value = plane->state->alpha;
+			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+		}
+
+		vop2_parse_alpha(&alpha_config, &alpha);
+
+		offset = (mixer_id + zpos - 1) * 0x10;
+		vop2_writel(vop2, RK3568_MIX0_SRC_COLOR_CTRL + offset,
+			    alpha.src_color_ctrl.val);
+		vop2_writel(vop2, RK3568_MIX0_DST_COLOR_CTRL + offset,
+			    alpha.dst_color_ctrl.val);
+		vop2_writel(vop2, RK3568_MIX0_SRC_ALPHA_CTRL + offset,
+			    alpha.src_alpha_ctrl.val);
+		vop2_writel(vop2, RK3568_MIX0_DST_ALPHA_CTRL + offset,
+			    alpha.dst_alpha_ctrl.val);
+	}
+
+	if (vp->id == 0) {
+		if (bottom_layer_alpha_en) {
+			/* Transfer pixel alpha to hdr mix */
+			alpha_config.src_premulti_en = gpremulti_en;
+			alpha_config.dst_premulti_en = true;
+			alpha_config.src_pixel_alpha_en = true;
+			alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+			vop2_parse_alpha(&alpha_config, &alpha);
+
+			vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL,
+				alpha.src_color_ctrl.val);
+			vop2_writel(vop2, RK3568_HDR0_DST_COLOR_CTRL,
+				alpha.dst_color_ctrl.val);
+			vop2_writel(vop2, RK3568_HDR0_SRC_ALPHA_CTRL,
+				alpha.src_alpha_ctrl.val);
+			vop2_writel(vop2, RK3568_HDR0_DST_ALPHA_CTRL,
+				alpha.dst_alpha_ctrl.val);
+		} else {
+			vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, 0);
+		}
+	}
+}
+
+#define NR_VPS		3
+#define NR_MIXERS	6
+
+static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
+{
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_plane *plane;
+	uint32_t layer_sel = 0;
+	uint32_t port_sel;
+	int nlayer, ofs;
+	struct drm_display_mode *adjusted_mode;
+	uint16_t hsync_len;
+	uint16_t hdisplay;
+	uint32_t bg_dly;
+	uint32_t pre_scan_dly;
+	int i;
+	struct vop2_video_port *vp0 = &vop2->vps[0];
+	struct vop2_video_port *vp1 = &vop2->vps[1];
+	struct vop2_video_port *vp2 = &vop2->vps[2];
+
+	adjusted_mode = &vp->crtc.state->adjusted_mode;
+	hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
+	hdisplay = adjusted_mode->crtc_hdisplay;
+
+	bg_dly = vp->data->pre_scan_max_dly[3];
+	vop2_writel(vop2, vp->regs->bg_mix_ctrl,
+			    FIELD_PREP(RK3568_VP_BG_MIX_CTRL__BG_DLY, bg_dly));
+
+	pre_scan_dly = ((bg_dly + (hdisplay >> 1) - 1) << 16) | hsync_len;
+	vop2_writel(vop2, vp->regs->pre_scan_htiming, pre_scan_dly);
+
+	vop2_writel(vop2, RK3568_OVL_CTRL, 0);
+	port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
+	port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT;
+
+	if (vp0->nlayers)
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX,
+				     vp0->nlayers - 1);
+	else
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, 8);
+
+	if (vp1->nlayers)
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX,
+				     (vp0->nlayers + vp1->nlayers - 1));
+	else
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8);
+
+	if (vp2->nlayers)
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX,
+			(vp2->nlayers + vp1->nlayers + vp0->nlayers - 1));
+	else
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8);
+
+	layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
+
+	ofs = 0;
+	for (i = 0; i < vp->id; i++)
+		ofs += vop2->vps[i].nlayers;
+
+	nlayer = 0;
+	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+
+		switch (win->data->phys_id) {
+		case ROCKCHIP_VOP2_CLUSTER0:
+			port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER0;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER0, vp->id);
+			break;
+		case ROCKCHIP_VOP2_CLUSTER1:
+			port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER1;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER1, vp->id);
+			break;
+		case ROCKCHIP_VOP2_ESMART0:
+			port_sel &= ~RK3568_OVL_PORT_SEL__ESMART0;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART0, vp->id);
+			break;
+		case ROCKCHIP_VOP2_ESMART1:
+			port_sel &= ~RK3568_OVL_PORT_SEL__ESMART1;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART1, vp->id);
+			break;
+		case ROCKCHIP_VOP2_SMART0:
+			port_sel &= ~RK3568_OVL_PORT_SEL__SMART0;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART0, vp->id);
+			break;
+		case ROCKCHIP_VOP2_SMART1:
+			port_sel &= ~RK3568_OVL_PORT_SEL__SMART1;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART1, vp->id);
+			break;
+		}
+
+		layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7);
+		layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, win->data->layer_sel_id);
+		nlayer++;
+	}
+
+	/* configure unused layers to 0x5 (reserved) */
+	for (; nlayer < 3; nlayer++) {
+		layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7);
+		layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 5);
+	}
+
+	vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
+	vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
+	vop2_writel(vop2, RK3568_OVL_CTRL, RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD);
+}
+
+static void vop2_setup_dly_for_windows(struct vop2 *vop2)
+{
+	struct vop2_win *win;
+	int i = 0;
+	uint32_t cdly = 0, sdly = 0;
+
+	for (i = 0; i < vop2->data->win_size; i++) {
+		uint32_t dly;
+
+		win = &vop2->win[i];
+		dly = win->delay;
+
+		switch (win->data->phys_id) {
+		case ROCKCHIP_VOP2_CLUSTER0:
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_0, dly);
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_1, dly);
+			break;
+		case ROCKCHIP_VOP2_CLUSTER1:
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_0, dly);
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_1, dly);
+			break;
+		case ROCKCHIP_VOP2_ESMART0:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART0, dly);
+			break;
+		case ROCKCHIP_VOP2_ESMART1:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART1, dly);
+			break;
+		case ROCKCHIP_VOP2_SMART0:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly);
+			break;
+		case ROCKCHIP_VOP2_SMART1:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly);
+			break;
+		}
+	}
+
+	vop2_writel(vop2, RK3568_CLUSTER_DLY_NUM, cdly);
+	vop2_writel(vop2, RK3568_SMART_DLY_NUM, sdly);
+}
+
+static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_plane *plane;
+
+	vp->win_mask = 0;
+
+	drm_atomic_crtc_for_each_plane(plane, crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+
+		win->delay = win->data->dly[VOP2_DLY_MODE_DEFAULT];
+
+		vp->win_mask |= BIT(win->data->phys_id);
+
+		if (vop2_cluster_window(win))
+			vop2_setup_cluster_alpha(vop2, win);
+	}
+
+	if (!vp->win_mask)
+		return;
+
+	vop2_setup_layer_mixer(vp);
+	vop2_setup_alpha(vp);
+	vop2_setup_dly_for_windows(vop2);
+}
+
+static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+
+	spin_lock(&vop2->reg_lock);
+
+	vop2_post_config(crtc);
+
+	spin_unlock(&vop2->reg_lock);
+
+	vop2_cfg_done(vp);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+
+	if (crtc->state->event) {
+		WARN_ON(drm_crtc_vblank_get(crtc));
+		vp->event = crtc->state->event;
+		crtc->state->event = NULL;
+	}
+
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = {
+	.mode_fixup = vop2_crtc_mode_fixup,
+	.atomic_check = vop2_crtc_atomic_check,
+	.atomic_begin = vop2_crtc_atomic_begin,
+	.atomic_flush = vop2_crtc_atomic_flush,
+	.atomic_enable = vop2_crtc_atomic_enable,
+	.atomic_disable = vop2_crtc_atomic_disable,
+};
+
+static void vop2_crtc_reset(struct drm_crtc *crtc)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+
+	if (crtc->state) {
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
+		kfree(vcstate);
+	}
+
+	vcstate = kzalloc(sizeof(*vcstate), GFP_KERNEL);
+	if (!vcstate)
+		return;
+
+	crtc->state = &vcstate->base;
+	crtc->state->crtc = crtc;
+}
+
+static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct rockchip_crtc_state *vcstate, *old_vcstate;
+
+	old_vcstate = to_rockchip_crtc_state(crtc->state);
+
+	vcstate = kmemdup(old_vcstate, sizeof(*old_vcstate), GFP_KERNEL);
+	if (!vcstate)
+		return NULL;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base);
+
+	return &vcstate->base;
+}
+
+static void vop2_crtc_destroy_state(struct drm_crtc *crtc,
+				    struct drm_crtc_state *state)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state);
+
+	__drm_atomic_helper_crtc_destroy_state(&vcstate->base);
+	kfree(vcstate);
+}
+
+static const struct drm_crtc_funcs vop2_crtc_funcs = {
+	.set_config = drm_atomic_helper_set_config,
+	.page_flip = drm_atomic_helper_page_flip,
+	.destroy = drm_crtc_cleanup,
+	.reset = vop2_crtc_reset,
+	.atomic_duplicate_state = vop2_crtc_duplicate_state,
+	.atomic_destroy_state = vop2_crtc_destroy_state,
+	.enable_vblank = vop2_crtc_enable_vblank,
+	.disable_vblank = vop2_crtc_disable_vblank,
+};
+
+static irqreturn_t vop2_isr(int irq, void *data)
+{
+	struct vop2 *vop2 = data;
+	const struct vop2_data *vop2_data = vop2->data;
+	uint32_t axi_irqs[VOP2_SYS_AXI_BUS_NUM];
+	int ret = IRQ_NONE;
+	int i;
+
+	/*
+	 * The irq is shared with the iommu. If the runtime-pm state of the
+	 * vop2-device is disabled the irq has to be targeted at the iommu.
+	 */
+	if (!pm_runtime_get_if_in_use(vop2->dev))
+		return IRQ_NONE;
+
+	for (i = 0; i < vop2_data->nr_vps; i++) {
+		struct vop2_video_port *vp = &vop2->vps[i];
+		struct drm_crtc *crtc = &vp->crtc;
+		uint32_t irqs;
+
+		irqs = vop2_readl(vop2, vp->data->regs->irq_status);
+		vop2_writel(vop2, vp->data->regs->irq_clear, irqs << 16 | irqs);
+
+		if (irqs & VP_INT_DSP_HOLD_VALID) {
+			complete(&vp->dsp_hold_completion);
+			ret = IRQ_HANDLED;
+		}
+
+		if (irqs & VP_INT_FS_FIELD) {
+			unsigned long flags;
+
+			drm_crtc_handle_vblank(crtc);
+			spin_lock_irqsave(&crtc->dev->event_lock, flags);
+			if (vp->event) {
+				uint32_t val = vop2_readl(vop2, RK3568_REG_CFG_DONE);
+				if (!(val & BIT(vp->id))) {
+					drm_crtc_send_vblank_event(crtc, vp->event);
+					vp->event = NULL;
+					drm_crtc_vblank_put(crtc);
+				}
+			}
+			spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
+			ret = IRQ_HANDLED;
+		}
+
+		if (irqs & VP_INT_POST_BUF_EMPTY) {
+			drm_err_ratelimited(vop2->drm,
+					    "POST_BUF_EMPTY irq err at vp%d\n",
+					    vp->id);
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	axi_irqs[0] = vop2_readl(vop2, RK3568_SYS0_INT_STATUS);
+	vop2_writel(vop2, RK3568_SYS0_INT_CLR, axi_irqs[0] << 16 | axi_irqs[0]);
+	axi_irqs[1] = vop2_readl(vop2, RK3568_SYS1_INT_STATUS);
+	vop2_writel(vop2, RK3568_SYS1_INT_CLR, axi_irqs[1] << 16 | axi_irqs[1]);
+
+	for (i = 0; i < ARRAY_SIZE(axi_irqs); i++) {
+		if (axi_irqs[i] & VOP2_INT_BUS_ERRPR) {
+			drm_err_ratelimited(vop2->drm, "BUS_ERROR irq err\n");
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	pm_runtime_put(vop2->dev);
+
+	return ret;
+}
+
+static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned long possible_crtcs)
+{
+	const struct vop2_win_data *win_data = win->data;
+	unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) | BIT(DRM_MODE_BLEND_PREMULTI) |
+				  BIT(DRM_MODE_BLEND_COVERAGE);
+	int ret;
+
+	ret = drm_universal_plane_init(vop2->drm, &win->base, possible_crtcs,
+				       &vop2_plane_funcs, win_data->formats, win_data->nformats,
+				       win_data->format_modifiers, win->type, win_data->name);
+	if (ret) {
+		drm_err(vop2->drm, "failed to initialize plane %d\n", ret);
+		return ret;
+	}
+
+	drm_plane_helper_add(&win->base, &vop2_plane_helper_funcs);
+
+	if (win->data->supported_rotations)
+		drm_plane_create_rotation_property(&win->base, DRM_MODE_ROTATE_0,
+						   DRM_MODE_ROTATE_0 |
+						   win->data->supported_rotations);
+	drm_plane_create_alpha_property(&win->base);
+	drm_plane_create_blend_mode_property(&win->base, blend_caps);
+	drm_plane_create_zpos_property(&win->base, win->win_id, 0,
+				       vop2->registered_num_wins - 1);
+
+	return 0;
+}
+
+static struct vop2_video_port *get_activated_vp(struct vop2 *vop2, int n)
+{
+	int i, id = 0;
+
+	for (i = 0; i < vop2->data->nr_vps; i++) {
+		struct vop2_video_port *vp = &vop2->vps[i];
+
+		if (!vp->crtc.port)
+			continue;
+
+		if (n == id)
+			return vp;
+		id++;
+	}
+
+	return NULL;
+}
+
+static int vop2_create_crtc(struct vop2 *vop2)
+{
+	const struct vop2_data *vop2_data = vop2->data;
+	struct drm_device *drm = vop2->drm;
+	struct device *dev = vop2->dev;
+	struct drm_plane *plane;
+	struct device_node *port;
+	struct vop2_video_port *vp;
+	uint32_t possible_crtcs;
+	int i, nvp, nvps = 0;
+	int ret;
+
+	for (i = 0; i < vop2_data->nr_vps; i++) {
+		const struct vop2_video_port_data *vp_data;
+		struct device_node *np;
+		char dclk_name[9];
+
+		vp_data = &vop2_data->vp[i];
+		vp = &vop2->vps[i];
+		vp->vop2 = vop2;
+		vp->id = vp_data->id;
+		vp->regs = vp_data->regs;
+		vp->data = vp_data;
+
+		snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id);
+		vp->dclk = devm_clk_get(vop2->dev, dclk_name);
+		if (IS_ERR(vp->dclk)) {
+			drm_err(vop2->drm, "failed to get %s\n", dclk_name);
+			return PTR_ERR(vp->dclk);
+		}
+
+		np = of_graph_get_remote_node(dev->of_node, i, -1);
+		if (!np) {
+			printk("%s: No remote for vp%d\n", __func__, i);
+			continue;
+		}
+		of_node_put(np);
+
+		port = of_graph_get_port_by_id(dev->of_node, i);
+		if (!port) {
+			drm_err(vop2->drm, "no port node found for video_port%d\n", i);
+			return -ENOENT;
+		}
+
+		vp->crtc.port = port;
+		nvps++;
+	}
+
+	nvp = 0;
+	for (i = 0; i < vop2->registered_num_wins; i++) {
+		struct vop2_win *win = &vop2->win[i];
+
+		if (win->type == DRM_PLANE_TYPE_PRIMARY) {
+			vp = get_activated_vp(vop2, nvp);
+
+			if (vp) {
+				possible_crtcs = BIT(nvp);
+				vp->primary_plane = win;
+
+				nvp++;
+			} else {
+				/* change the unused primary window to overlay window */
+				win->type = DRM_PLANE_TYPE_OVERLAY;
+			}
+		}
+
+		if (win->type == DRM_PLANE_TYPE_OVERLAY)
+			possible_crtcs = (1 << vop2_data->nr_vps) - 1;
+
+		ret = vop2_plane_init(vop2, win, possible_crtcs);
+
+		if (ret) {
+			drm_err(vop2->drm, "failed to init plane %s: %d\n", win->data->name, ret);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < vop2_data->nr_vps; i++) {
+		vp = &vop2->vps[i];
+
+		if (!vp->crtc.port)
+			continue;
+
+		plane = &vp->primary_plane->base;
+
+		ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL, &vop2_crtc_funcs,
+						"video_port%d", vp->id);
+		if (ret) {
+			drm_err(vop2->drm, "crtc init for video_port%d failed\n", i);
+			return ret;
+		}
+
+		drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);
+
+		init_completion(&vp->dsp_hold_completion);
+	}
+
+	for (i = 0; i < vop2->data->nr_vps; i++) {
+		struct vop2_video_port *vp = &vop2->vps[i];
+		if (vp->crtc.port)
+			vp->nlayers = NR_MIXERS / nvps;
+	}
+
+	return 0;
+}
+
+static void vop2_destroy_crtc(struct drm_crtc *crtc)
+{
+	of_node_put(crtc->port);
+
+	/*
+	 * Destroy CRTC after vop2_plane_destroy() since vop2_disable_plane()
+	 * references the CRTC.
+	 */
+	drm_crtc_cleanup(crtc);
+}
+
+static int vop2_win_init(struct vop2 *vop2)
+{
+	const struct vop2_data *vop2_data = vop2->data;
+	struct vop2_win *win;
+	unsigned int i;
+
+	for (i = 0; i < vop2_data->win_size; i++) {
+		const struct vop2_win_data *win_data = &vop2_data->win[i];
+
+		win = &vop2->win[i];
+		win->data = win_data;
+		win->type = win_data->type;
+		win->regs = win_data->regs;
+		win->offset = win_data->base;
+		win->win_id = i;
+		win->vop2 = vop2;
+	}
+
+	vop2->registered_num_wins = vop2_data->win_size;
+
+	return 0;
+}
+
+static int vop2_bind(struct device *dev, struct device *master, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct vop2_data *vop2_data;
+	struct drm_device *drm = data;
+	struct vop2 *vop2;
+	struct resource *res;
+	size_t alloc_size;
+	int ret;
+
+	vop2_data = of_device_get_match_data(dev);
+	if (!vop2_data)
+		return -ENODEV;
+
+	/* Allocate vop2 struct and its vop2_win array */
+	alloc_size = sizeof(*vop2) + sizeof(*vop2->win) * vop2_data->win_size;
+	vop2 = devm_kzalloc(dev, alloc_size, GFP_KERNEL);
+	if (!vop2)
+		return -ENOMEM;
+
+	vop2->dev = dev;
+	vop2->data = vop2_data;
+	vop2->drm = drm;
+
+	dev_set_drvdata(dev, vop2);
+
+	ret = vop2_win_init(vop2);
+	if (ret)
+		return ret;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	if (!res) {
+		drm_err(vop2->drm, "failed to get vop2 register byname\n");
+		return -EINVAL;
+	}
+	vop2->regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(vop2->regs))
+		return PTR_ERR(vop2->regs);
+	vop2->len = resource_size(res);
+
+	vop2->regsbak = devm_kzalloc(dev, vop2->len, GFP_KERNEL);
+	if (!vop2->regsbak)
+		return -ENOMEM;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gamma_lut");
+	if (res) {
+		vop2->lut_regs = devm_ioremap_resource(dev, res);
+		if (IS_ERR(vop2->lut_regs))
+			return PTR_ERR(vop2->lut_regs);
+	}
+
+	vop2->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
+
+	vop2->hclk = devm_clk_get(vop2->dev, "hclk_vop");
+	if (IS_ERR(vop2->hclk)) {
+		drm_err(vop2->drm, "failed to get hclk source\n");
+		return PTR_ERR(vop2->hclk);
+	}
+
+	vop2->aclk = devm_clk_get(vop2->dev, "aclk_vop");
+	if (IS_ERR(vop2->aclk)) {
+		drm_err(vop2->drm, "failed to get aclk source\n");
+		return PTR_ERR(vop2->aclk);
+	}
+
+	vop2->irq = platform_get_irq(pdev, 0);
+	if (vop2->irq < 0) {
+		drm_err(vop2->drm, "cannot find irq for vop2\n");
+		return vop2->irq;
+	}
+
+	spin_lock_init(&vop2->reg_lock);
+	mutex_init(&vop2->vop2_lock);
+
+	ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2);
+	if (ret)
+		return ret;
+
+	ret = rockchip_drm_dma_attach_device(vop2->drm, vop2->dev);
+	if (ret) {
+		drm_err(vop2->drm, "failed to attach dma mapping, %d\n", ret);
+		return ret;
+	}
+
+	ret = vop2_create_crtc(vop2);
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+}
+
+static void vop2_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct vop2 *vop2 = dev_get_drvdata(dev);
+	struct drm_device *drm = vop2->drm;
+	struct list_head *plane_list = &drm->mode_config.plane_list;
+	struct list_head *crtc_list = &drm->mode_config.crtc_list;
+	struct drm_crtc *crtc, *tmpc;
+	struct drm_plane *plane, *tmpp;
+
+	rockchip_drm_dma_detach_device(vop2->drm, vop2->dev);
+
+	pm_runtime_disable(dev);
+
+	list_for_each_entry_safe(plane, tmpp, plane_list, head)
+		drm_plane_cleanup(plane);
+
+	list_for_each_entry_safe(crtc, tmpc, crtc_list, head)
+		vop2_destroy_crtc(crtc);
+}
+
+const struct component_ops vop2_component_ops = {
+	.bind = vop2_bind,
+	.unbind = vop2_unbind,
+};
+EXPORT_SYMBOL_GPL(vop2_component_ops);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
new file mode 100644
index 0000000000000..b18871a5d85a7
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
@@ -0,0 +1,625 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:Mark Yao <mark.yao@rock-chips.com>
+ */
+
+#ifndef _ROCKCHIP_DRM_VOP2_H
+#define _ROCKCHIP_DRM_VOP2_H
+
+#include "rockchip_drm_vop.h"
+
+#include <drm/drm_modes.h>
+
+#define VOP_FEATURE_OUTPUT_10BIT        BIT(0)
+
+#define WIN_FEATURE_AFBDC		BIT(0)
+#define WIN_FEATURE_CLUSTER		BIT(1)
+
+/*
+ *  the delay number of a window in different mode.
+ */
+enum win_dly_mode {
+	VOP2_DLY_MODE_DEFAULT,   /**< default mode */
+	VOP2_DLY_MODE_HISO_S,    /** HDR in SDR out mode, as a SDR window */
+	VOP2_DLY_MODE_HIHO_H,    /** HDR in HDR out mode, as a HDR window */
+	VOP2_DLY_MODE_MAX,
+};
+
+struct vop_rect {
+	int width;
+	int height;
+};
+
+struct vop_grf_ctrl {
+	struct vop_reg grf_dclk_inv;
+	struct vop_reg grf_bt1120_clk_inv;
+	struct vop_reg grf_bt656_clk_inv;
+};
+
+struct vop2_afbc {
+	struct vop_reg enable;
+	struct vop_reg format;
+	struct vop_reg rb_swap;
+	struct vop_reg uv_swap;
+	struct vop_reg auto_gating_en;
+	struct vop_reg block_split_en;
+	struct vop_reg pic_vir_width;
+	struct vop_reg tile_num;
+	struct vop_reg pic_offset;
+	struct vop_reg pic_size;
+	struct vop_reg dsp_offset;
+	struct vop_reg transform_offset;
+	struct vop_reg hdr_ptr;
+	struct vop_reg half_block_en;
+	struct vop_reg xmirror;
+	struct vop_reg ymirror;
+	struct vop_reg rotate_270;
+	struct vop_reg rotate_90;
+};
+
+enum vop2_scale_up_mode {
+	VOP2_SCALE_UP_NRST_NBOR,
+	VOP2_SCALE_UP_BIL,
+	VOP2_SCALE_UP_BIC,
+};
+
+enum vop2_scale_down_mode {
+	VOP2_SCALE_DOWN_NRST_NBOR,
+	VOP2_SCALE_DOWN_BIL,
+	VOP2_SCALE_DOWN_AVG,
+};
+
+struct vop2_cluster_regs {
+	struct vop_reg enable;
+	struct vop_reg afbc_enable;
+	struct vop_reg lb_mode;
+};
+
+struct vop2_scl_regs {
+	struct vop_reg scale_yrgb_x;
+	struct vop_reg scale_yrgb_y;
+	struct vop_reg scale_cbcr_x;
+	struct vop_reg scale_cbcr_y;
+	struct vop_reg yrgb_hor_scl_mode;
+	struct vop_reg yrgb_hscl_filter_mode;
+	struct vop_reg yrgb_ver_scl_mode;
+	struct vop_reg yrgb_vscl_filter_mode;
+	struct vop_reg cbcr_ver_scl_mode;
+	struct vop_reg cbcr_hscl_filter_mode;
+	struct vop_reg cbcr_hor_scl_mode;
+	struct vop_reg cbcr_vscl_filter_mode;
+	struct vop_reg vsd_cbcr_gt2;
+	struct vop_reg vsd_cbcr_gt4;
+	struct vop_reg vsd_yrgb_gt2;
+	struct vop_reg vsd_yrgb_gt4;
+	struct vop_reg bic_coe_sel;
+};
+
+struct vop2_win_regs {
+	const struct vop2_scl_regs *scl;
+	const struct vop2_cluster_regs *cluster;
+	const struct vop2_afbc *afbc;
+
+	struct vop_reg gate;
+	struct vop_reg enable;
+	struct vop_reg format;
+	struct vop_reg csc_mode;
+	struct vop_reg xmirror;
+	struct vop_reg ymirror;
+	struct vop_reg rb_swap;
+	struct vop_reg uv_swap;
+	struct vop_reg act_info;
+	struct vop_reg dsp_info;
+	struct vop_reg dsp_st;
+	struct vop_reg yrgb_mst;
+	struct vop_reg uv_mst;
+	struct vop_reg yrgb_vir;
+	struct vop_reg uv_vir;
+	struct vop_reg yuv_clip;
+	struct vop_reg lb_mode;
+	struct vop_reg y2r_en;
+	struct vop_reg r2y_en;
+	struct vop_reg channel;
+	struct vop_reg dst_alpha_ctl;
+	struct vop_reg src_alpha_ctl;
+	struct vop_reg alpha_mode;
+	struct vop_reg alpha_en;
+	struct vop_reg global_alpha_val;
+	struct vop_reg color_key;
+	struct vop_reg color_key_en;
+	struct vop_reg dither_up;
+};
+
+struct vop2_video_port_regs {
+	int dsp_background;
+	int pre_scan_htiming;
+	int htotal_pw;
+	int hact_st_end;
+	int vtotal_pw;
+	int vact_st_end;
+	int vact_st_end_f1;
+	int vs_st_end_f1;
+	int hpost_st_end;
+	int vpost_st_end;
+	int vpost_st_end_f1;
+	int post_scl_factor;
+	int dsp_ctrl;
+	int mipi_ctrl;
+	int bg_mix_ctrl;
+	int hdr2sdr_eetf_oetf_y0_offset;
+	int hdr2sdr_sat_y0_offset;
+	int sdr2hdr_eotf_oetf_y0_offset;
+	int sdr2hdr_oetf_dx_pow1_offset;
+	int sdr2hdr_oetf_xn1_offset;
+	int irq_enable;
+	int irq_status;
+	int irq_clear;
+	int line_flag;
+};
+
+struct vop2_wb_regs {
+	struct vop_reg enable;
+	struct vop_reg format;
+	struct vop_reg dither_en;
+	struct vop_reg r2y_en;
+	struct vop_reg yrgb_mst;
+	struct vop_reg uv_mst;
+	struct vop_reg vp_id;
+	struct vop_reg fifo_throd;
+	struct vop_reg scale_x_factor;
+	struct vop_reg scale_x_en;
+	struct vop_reg scale_y_en;
+	struct vop_reg axi_yrgb_id;
+	struct vop_reg axi_uv_id;
+};
+
+struct vop2_win_data {
+	const char *name;
+	uint8_t phys_id;
+
+	uint32_t base;
+	enum drm_plane_type type;
+
+	uint32_t nformats;
+	const uint32_t *formats;
+	const uint64_t *format_modifiers;
+	const unsigned int supported_rotations;
+
+	const struct vop2_win_regs *regs;
+
+	/*
+	 * vertical/horizontal scale up/down filter mode
+	 */
+	const u8 hsu_filter_mode;
+	const u8 hsd_filter_mode;
+	const u8 vsu_filter_mode;
+	const u8 vsd_filter_mode;
+	/**
+	 * @layer_sel_id: defined by register OVERLAY_LAYER_SEL of VOP2
+	 */
+	int layer_sel_id;
+	uint64_t feature;
+
+	unsigned int max_upscale_factor;
+	unsigned int max_downscale_factor;
+	const uint8_t dly[VOP2_DLY_MODE_MAX];
+};
+
+struct vop2_wb_data {
+	uint32_t nformats;
+	const uint32_t *formats;
+	struct vop_rect max_output;
+	const struct vop2_wb_regs *regs;
+};
+
+struct vop2_video_port_data {
+	char id;
+	uint32_t feature;
+	uint16_t gamma_lut_len;
+	uint16_t cubic_lut_len;
+	struct vop_rect max_output;
+	const u8 pre_scan_max_dly[4];
+	const struct vop2_video_port_regs *regs;
+};
+
+/**
+ * VOP2 data struct
+ *
+ * @version: VOP IP version
+ * @win_size: hardware win number
+ */
+struct vop2_data {
+	uint8_t nr_vps;
+	uint8_t nr_mixers;
+	uint8_t nr_layers;
+	uint8_t nr_gammas;
+	const struct vop2_ctrl *ctrl;
+	const struct vop2_win_data *win;
+	const struct vop2_video_port_data *vp;
+	const struct vop_csc_table *csc_table;
+	const struct vop_grf_ctrl *grf_ctrl;
+	struct vop_rect max_input;
+	struct vop_rect max_output;
+
+	unsigned int win_size;
+	unsigned int soc_id;
+};
+
+/* interrupt define */
+#define FS_NEW_INTR			BIT(4)
+#define ADDR_SAME_INTR			BIT(5)
+#define LINE_FLAG1_INTR			BIT(6)
+#define WIN0_EMPTY_INTR			BIT(7)
+#define WIN1_EMPTY_INTR			BIT(8)
+#define WIN2_EMPTY_INTR			BIT(9)
+#define WIN3_EMPTY_INTR			BIT(10)
+#define HWC_EMPTY_INTR			BIT(11)
+#define POST_BUF_EMPTY_INTR		BIT(12)
+#define PWM_GEN_INTR			BIT(13)
+#define DMA_FINISH_INTR			BIT(14)
+#define FS_FIELD_INTR			BIT(15)
+#define FE_INTR				BIT(16)
+#define WB_UV_FIFO_FULL_INTR		BIT(17)
+#define WB_YRGB_FIFO_FULL_INTR		BIT(18)
+#define WB_COMPLETE_INTR		BIT(19)
+
+/*
+ * display output interface supported by rockchip lcdc
+ */
+#define ROCKCHIP_OUT_MODE_P888		0
+#define ROCKCHIP_OUT_MODE_BT1120	0
+#define ROCKCHIP_OUT_MODE_P666		1
+#define ROCKCHIP_OUT_MODE_P565		2
+#define ROCKCHIP_OUT_MODE_BT656		5
+#define ROCKCHIP_OUT_MODE_S888		8
+#define ROCKCHIP_OUT_MODE_S888_DUMMY	12
+#define ROCKCHIP_OUT_MODE_YUV420	14
+/* for use special outface */
+#define ROCKCHIP_OUT_MODE_AAAA		15
+
+enum vop_csc_format {
+	CSC_BT601L,
+	CSC_BT709L,
+	CSC_BT601F,
+	CSC_BT2020,
+};
+
+enum src_factor_mode {
+	SRC_FAC_ALPHA_ZERO,
+	SRC_FAC_ALPHA_ONE,
+	SRC_FAC_ALPHA_DST,
+	SRC_FAC_ALPHA_DST_INVERSE,
+	SRC_FAC_ALPHA_SRC,
+	SRC_FAC_ALPHA_SRC_GLOBAL,
+};
+
+enum dst_factor_mode {
+	DST_FAC_ALPHA_ZERO,
+	DST_FAC_ALPHA_ONE,
+	DST_FAC_ALPHA_SRC,
+	DST_FAC_ALPHA_SRC_INVERSE,
+	DST_FAC_ALPHA_DST,
+	DST_FAC_ALPHA_DST_GLOBAL,
+};
+
+#define RK3568_GRF_VO_CON1			0x0364
+/* System registers definition */
+#define RK3568_REG_CFG_DONE			0x000
+#define RK3568_VERSION_INFO			0x004
+#define RK3568_SYS_AUTO_GATING_CTRL		0x008
+#define RK3568_SYS_AXI_LUT_CTRL			0x024
+#define RK3568_DSP_IF_EN			0x028
+#define RK3568_DSP_IF_CTRL			0x02c
+#define RK3568_DSP_IF_POL			0x030
+#define RK3568_WB_CTRL				0x40
+#define RK3568_WB_XSCAL_FACTOR			0x44
+#define RK3568_WB_YRGB_MST			0x48
+#define RK3568_WB_CBR_MST			0x4C
+#define RK3568_OTP_WIN_EN			0x050
+#define RK3568_LUT_PORT_SEL			0x058
+#define RK3568_SYS_STATUS0			0x060
+#define RK3568_VP0_LINE_FLAG			0x70
+#define RK3568_VP1_LINE_FLAG			0x74
+#define RK3568_VP2_LINE_FLAG			0x78
+#define RK3568_SYS0_INT_EN			0x80
+#define RK3568_SYS0_INT_CLR			0x84
+#define RK3568_SYS0_INT_STATUS			0x88
+#define RK3568_SYS1_INT_EN			0x90
+#define RK3568_SYS1_INT_CLR			0x94
+#define RK3568_SYS1_INT_STATUS			0x98
+#define RK3568_VP0_INT_EN			0xA0
+#define RK3568_VP0_INT_CLR			0xA4
+#define RK3568_VP0_INT_STATUS			0xA8
+#define RK3568_VP0_INT_RAW_STATUS		0xAC
+#define RK3568_VP1_INT_EN			0xB0
+#define RK3568_VP1_INT_CLR			0xB4
+#define RK3568_VP1_INT_STATUS			0xB8
+#define RK3568_VP1_INT_RAW_STATUS		0xBC
+#define RK3568_VP2_INT_EN			0xC0
+#define RK3568_VP2_INT_CLR			0xC4
+#define RK3568_VP2_INT_STATUS			0xC8
+#define RK3568_VP2_INT_RAW_STATUS		0xCC
+
+/* Video Port registers definition */
+#define RK3568_VP0_DSP_CTRL			0xC00
+#define RK3568_VP0_MIPI_CTRL			0xC04
+#define RK3568_VP0_COLOR_BAR_CTRL		0xC08
+#define RK3568_VP0_3D_LUT_CTRL			0xC10
+#define RK3568_VP0_3D_LUT_MST			0xC20
+#define RK3568_VP0_DSP_BG			0xC2C
+#define RK3568_VP0_PRE_SCAN_HTIMING		0xC30
+#define RK3568_VP0_POST_DSP_HACT_INFO		0xC34
+#define RK3568_VP0_POST_DSP_VACT_INFO		0xC38
+#define RK3568_VP0_POST_SCL_FACTOR_YRGB		0xC3C
+#define RK3568_VP0_POST_SCL_CTRL		0xC40
+#define RK3568_VP0_POST_DSP_VACT_INFO_F1	0xC44
+#define RK3568_VP0_DSP_HTOTAL_HS_END		0xC48
+#define RK3568_VP0_DSP_HACT_ST_END		0xC4C
+#define RK3568_VP0_DSP_VTOTAL_VS_END		0xC50
+#define RK3568_VP0_DSP_VACT_ST_END		0xC54
+#define RK3568_VP0_DSP_VS_ST_END_F1		0xC58
+#define RK3568_VP0_DSP_VACT_ST_END_F1		0xC5C
+#define RK3568_VP0_BCSH_CTRL			0xC60
+#define RK3568_VP0_BCSH_BCS			0xC64
+#define RK3568_VP0_BCSH_H			0xC68
+#define RK3568_VP0_BCSH_COLOR_BAR		0xC6C
+
+#define RK3568_VP1_DSP_CTRL			0xD00
+#define RK3568_VP1_MIPI_CTRL			0xD04
+#define RK3568_VP1_COLOR_BAR_CTRL		0xD08
+#define RK3568_VP1_DSP_BG			0xD2C
+#define RK3568_VP1_PRE_SCAN_HTIMING		0xD30
+#define RK3568_VP1_POST_DSP_HACT_INFO		0xD34
+#define RK3568_VP1_POST_DSP_VACT_INFO		0xD38
+#define RK3568_VP1_POST_SCL_FACTOR_YRGB		0xD3C
+#define RK3568_VP1_POST_SCL_CTRL		0xD40
+#define RK3568_VP1_DSP_HACT_INFO		0xD34
+#define RK3568_VP1_DSP_VACT_INFO		0xD38
+#define RK3568_VP1_POST_DSP_VACT_INFO_F1	0xD44
+#define RK3568_VP1_DSP_HTOTAL_HS_END		0xD48
+#define RK3568_VP1_DSP_HACT_ST_END		0xD4C
+#define RK3568_VP1_DSP_VTOTAL_VS_END		0xD50
+#define RK3568_VP1_DSP_VACT_ST_END		0xD54
+#define RK3568_VP1_DSP_VS_ST_END_F1		0xD58
+#define RK3568_VP1_DSP_VACT_ST_END_F1		0xD5C
+#define RK3568_VP1_BCSH_CTRL			0xD60
+#define RK3568_VP1_BCSH_BCS			0xD64
+#define RK3568_VP1_BCSH_H			0xD68
+#define RK3568_VP1_BCSH_COLOR_BAR		0xD6C
+
+#define RK3568_VP2_DSP_CTRL			0xE00
+#define RK3568_VP2_MIPI_CTRL			0xE04
+#define RK3568_VP2_COLOR_BAR_CTRL		0xE08
+#define RK3568_VP2_DSP_BG			0xE2C
+#define RK3568_VP2_PRE_SCAN_HTIMING		0xE30
+#define RK3568_VP2_POST_DSP_HACT_INFO		0xE34
+#define RK3568_VP2_POST_DSP_VACT_INFO		0xE38
+#define RK3568_VP2_POST_SCL_FACTOR_YRGB		0xE3C
+#define RK3568_VP2_POST_SCL_CTRL		0xE40
+#define RK3568_VP2_DSP_HACT_INFO		0xE34
+#define RK3568_VP2_DSP_VACT_INFO		0xE38
+#define RK3568_VP2_POST_DSP_VACT_INFO_F1	0xE44
+#define RK3568_VP2_DSP_HTOTAL_HS_END		0xE48
+#define RK3568_VP2_DSP_HACT_ST_END		0xE4C
+#define RK3568_VP2_DSP_VTOTAL_VS_END		0xE50
+#define RK3568_VP2_DSP_VACT_ST_END		0xE54
+#define RK3568_VP2_DSP_VS_ST_END_F1		0xE58
+#define RK3568_VP2_DSP_VACT_ST_END_F1		0xE5C
+#define RK3568_VP2_BCSH_CTRL			0xE60
+#define RK3568_VP2_BCSH_BCS			0xE64
+#define RK3568_VP2_BCSH_H			0xE68
+#define RK3568_VP2_BCSH_COLOR_BAR		0xE6C
+
+/* Overlay registers definition    */
+#define RK3568_OVL_CTRL				0x600
+#define RK3568_OVL_LAYER_SEL			0x604
+#define RK3568_OVL_PORT_SEL			0x608
+#define RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL	0x610
+#define RK3568_CLUSTER0_MIX_DST_COLOR_CTRL	0x614
+#define RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL	0x618
+#define RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL	0x61C
+#define RK3568_MIX0_SRC_COLOR_CTRL		0x650
+#define RK3568_MIX0_DST_COLOR_CTRL		0x654
+#define RK3568_MIX0_SRC_ALPHA_CTRL		0x658
+#define RK3568_MIX0_DST_ALPHA_CTRL		0x65C
+#define RK3568_HDR0_SRC_COLOR_CTRL		0x6C0
+#define RK3568_HDR0_DST_COLOR_CTRL		0x6C4
+#define RK3568_HDR0_SRC_ALPHA_CTRL		0x6C8
+#define RK3568_HDR0_DST_ALPHA_CTRL		0x6CC
+#define RK3568_VP0_BG_MIX_CTRL			0x6E0
+#define RK3568_VP1_BG_MIX_CTRL			0x6E4
+#define RK3568_VP2_BG_MIX_CTRL			0x6E8
+#define RK3568_CLUSTER_DLY_NUM			0x6F0
+#define RK3568_SMART_DLY_NUM			0x6F8
+
+/* Cluster register definition, offset relative to window base */
+#define RK3568_CLUSTER_WIN_CTRL0		0x00
+#define RK3568_CLUSTER_WIN_CTRL1		0x04
+#define RK3568_CLUSTER_WIN_YRGB_MST		0x10
+#define RK3568_CLUSTER_WIN_CBR_MST		0x14
+#define RK3568_CLUSTER_WIN_VIR			0x18
+#define RK3568_CLUSTER_WIN_ACT_INFO		0x20
+#define RK3568_CLUSTER_WIN_DSP_INFO		0x24
+#define RK3568_CLUSTER_WIN_DSP_ST		0x28
+#define RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB	0x30
+#define RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET	0x3C
+#define RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL	0x50
+#define RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE	0x54
+#define RK3568_CLUSTER_WIN_AFBCD_HDR_PTR	0x58
+#define RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH	0x5C
+#define RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE	0x60
+#define RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET	0x64
+#define RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET	0x68
+#define RK3568_CLUSTER_WIN_AFBCD_CTRL		0x6C
+
+#define RK3568_CLUSTER_CTRL			0x100
+
+/* (E)smart register definition, offset relative to window base */
+#define RK3568_SMART_CTRL0			0x00
+#define RK3568_SMART_CTRL1			0x04
+#define RK3568_SMART_REGION0_CTRL		0x10
+#define RK3568_SMART_REGION0_YRGB_MST		0x14
+#define RK3568_SMART_REGION0_CBR_MST		0x18
+#define RK3568_SMART_REGION0_VIR		0x1C
+#define RK3568_SMART_REGION0_ACT_INFO		0x20
+#define RK3568_SMART_REGION0_DSP_INFO		0x24
+#define RK3568_SMART_REGION0_DSP_ST		0x28
+#define RK3568_SMART_REGION0_SCL_CTRL		0x30
+#define RK3568_SMART_REGION0_SCL_FACTOR_YRGB	0x34
+#define RK3568_SMART_REGION0_SCL_FACTOR_CBR	0x38
+#define RK3568_SMART_REGION0_SCL_OFFSET		0x3C
+#define RK3568_SMART_REGION1_CTRL		0x40
+#define RK3568_SMART_REGION1_YRGB_MST		0x44
+#define RK3568_SMART_REGION1_CBR_MST		0x48
+#define RK3568_SMART_REGION1_VIR		0x4C
+#define RK3568_SMART_REGION1_ACT_INFO		0x50
+#define RK3568_SMART_REGION1_DSP_INFO		0x54
+#define RK3568_SMART_REGION1_DSP_ST		0x58
+#define RK3568_SMART_REGION1_SCL_CTRL		0x60
+#define RK3568_SMART_REGION1_SCL_FACTOR_YRGB	0x64
+#define RK3568_SMART_REGION1_SCL_FACTOR_CBR	0x68
+#define RK3568_SMART_REGION1_SCL_OFFSET		0x6C
+#define RK3568_SMART_REGION2_CTRL		0x70
+#define RK3568_SMART_REGION2_YRGB_MST		0x74
+#define RK3568_SMART_REGION2_CBR_MST		0x78
+#define RK3568_SMART_REGION2_VIR		0x7C
+#define RK3568_SMART_REGION2_ACT_INFO		0x80
+#define RK3568_SMART_REGION2_DSP_INFO		0x84
+#define RK3568_SMART_REGION2_DSP_ST		0x88
+#define RK3568_SMART_REGION2_SCL_CTRL		0x90
+#define RK3568_SMART_REGION2_SCL_FACTOR_YRGB	0x94
+#define RK3568_SMART_REGION2_SCL_FACTOR_CBR	0x98
+#define RK3568_SMART_REGION2_SCL_OFFSET		0x9C
+#define RK3568_SMART_REGION3_CTRL		0xA0
+#define RK3568_SMART_REGION3_YRGB_MST		0xA4
+#define RK3568_SMART_REGION3_CBR_MST		0xA8
+#define RK3568_SMART_REGION3_VIR		0xAC
+#define RK3568_SMART_REGION3_ACT_INFO		0xB0
+#define RK3568_SMART_REGION3_DSP_INFO		0xB4
+#define RK3568_SMART_REGION3_DSP_ST		0xB8
+#define RK3568_SMART_REGION3_SCL_CTRL		0xC0
+#define RK3568_SMART_REGION3_SCL_FACTOR_YRGB	0xC4
+#define RK3568_SMART_REGION3_SCL_FACTOR_CBR	0xC8
+#define RK3568_SMART_REGION3_SCL_OFFSET		0xCC
+#define RK3568_SMART_COLOR_KEY_CTRL		0xD0
+
+/* HDR register definition */
+#define RK3568_HDR_LUT_CTRL			0x2000
+#define RK3568_HDR_LUT_MST			0x2004
+#define RK3568_SDR2HDR_CTRL			0x2010
+#define RK3568_HDR2SDR_CTRL			0x2020
+#define RK3568_HDR2SDR_SRC_RANGE		0x2024
+#define RK3568_HDR2SDR_NORMFACEETF		0x2028
+#define RK3568_HDR2SDR_DST_RANGE		0x202C
+#define RK3568_HDR2SDR_NORMFACCGAMMA		0x2030
+#define RK3568_HDR_EETF_OETF_Y0			0x203C
+#define RK3568_HDR_SAT_Y0			0x20C0
+#define RK3568_HDR_EOTF_OETF_Y0			0x20F0
+#define RK3568_HDR_OETF_DX_POW1			0x2200
+#define RK3568_HDR_OETF_XN1			0x2300
+
+#define RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN		BIT(15)
+
+#define RK3568_VP_DSP_CTRL__STANDBY			BIT(31)
+#define RK3568_VP_DSP_CTRL__DITHER_DOWN_MODE		BIT(20)
+#define RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL		GENMASK(19, 18)
+#define RK3568_VP_DSP_CTRL__DITHER_DOWN_EN		BIT(17)
+#define RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN		BIT(16)
+#define RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y		BIT(15)
+#define RK3568_VP_DSP_CTRL__DSP_RB_SWAP			BIT(9)
+#define RK3568_VP_DSP_CTRL__DSP_INTERLACE		BIT(7)
+#define RK3568_VP_DSP_CTRL__DSP_FILED_POL		BIT(6)
+#define RK3568_VP_DSP_CTRL__P2I_EN			BIT(5)
+#define RK3568_VP_DSP_CTRL__CORE_DCLK_DIV		BIT(4)
+#define RK3568_VP_DSP_CTRL__OUT_MODE			GENMASK(3, 0)
+
+#define RK3568_VP_POST_SCL_CTRL__VSCALEDOWN		BIT(1)
+#define RK3568_VP_POST_SCL_CTRL__HSCALEDOWN		BIT(0)
+
+#define RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX		GENMASK(26, 25)
+#define RK3568_SYS_DSP_INFACE_EN_LVDS1			BIT(24)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX		GENMASK(22, 21)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI1			BIT(20)
+#define RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX		GENMASK(19, 18)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX		GENMASK(17, 16)
+#define RK3568_SYS_DSP_INFACE_EN_EDP_MUX		GENMASK(15, 14)
+#define RK3568_SYS_DSP_INFACE_EN_HDMI_MUX		GENMASK(11, 10)
+#define RK3568_SYS_DSP_INFACE_EN_RGB_MUX		GENMASK(9, 8)
+#define RK3568_SYS_DSP_INFACE_EN_LVDS0			BIT(5)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI0			BIT(4)
+#define RK3568_SYS_DSP_INFACE_EN_EDP			BIT(3)
+#define RK3568_SYS_DSP_INFACE_EN_HDMI			BIT(1)
+#define RK3568_SYS_DSP_INFACE_EN_RGB			BIT(0)
+
+#define RK3568_DSP_IF_POL__MIPI_PIN_POL			GENMASK(19, 16)
+#define RK3568_DSP_IF_POL__EDP_PIN_POL			GENMASK(15, 12)
+#define RK3568_DSP_IF_POL__HDMI_PIN_POL			GENMASK(7, 4)
+#define RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL		GENMASK(3, 0)
+
+#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2_PHASE_LOCK	BIT(5)
+#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2			BIT(4)
+
+#define RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN	BIT(31)
+
+#define RK3568_DSP_IF_POL__CFG_DONE_IMD			BIT(28)
+
+#define VOP2_SYS_AXI_BUS_NUM				2
+
+#define VOP2_CLUSTER_YUV444_10				0x12
+
+#define VOP2_COLOR_KEY_MASK				BIT(31)
+
+#define RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD		BIT(28)
+
+#define RK3568_VP_BG_MIX_CTRL__BG_DLY			GENMASK(31, 24)
+
+#define RK3568_OVL_PORT_SEL__SEL_PORT			GENMASK(31, 16)
+#define RK3568_OVL_PORT_SEL__SMART1			GENMASK(31, 30)
+#define RK3568_OVL_PORT_SEL__SMART0			GENMASK(29, 28)
+#define RK3568_OVL_PORT_SEL__ESMART1			GENMASK(27, 26)
+#define RK3568_OVL_PORT_SEL__ESMART0			GENMASK(25, 24)
+#define RK3568_OVL_PORT_SEL__CLUSTER1			GENMASK(19, 18)
+#define RK3568_OVL_PORT_SEL__CLUSTER0			GENMASK(17, 16)
+#define RK3568_OVL_PORT_SET__PORT2_MUX			GENMASK(11, 8)
+#define RK3568_OVL_PORT_SET__PORT1_MUX			GENMASK(7, 4)
+#define RK3568_OVL_PORT_SET__PORT0_MUX			GENMASK(3, 0)
+#define RK3568_OVL_LAYER_SEL__LAYER(layer, x)		((x) << ((layer) * 4))
+
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER1_1		GENMASK(31, 24)
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER1_0		GENMASK(23, 16)
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_1		GENMASK(15, 8)
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_0		GENMASK(7, 0)
+
+#define RK3568_SMART_DLY_NUM__SMART1			GENMASK(31, 24)
+#define RK3568_SMART_DLY_NUM__SMART0			GENMASK(23, 16)
+#define RK3568_SMART_DLY_NUM__ESMART1			GENMASK(15, 8)
+#define RK3568_SMART_DLY_NUM__ESMART0			GENMASK(7, 0)
+
+#define VP_INT_DSP_HOLD_VALID	BIT(6)
+#define VP_INT_FS_FIELD		BIT(5)
+#define VP_INT_POST_BUF_EMPTY	BIT(4)
+#define VP_INT_LINE_FLAG1	BIT(3)
+#define VP_INT_LINE_FLAG0	BIT(2)
+#define VOP2_INT_BUS_ERRPR	BIT(1)
+#define VP_INT_FS		BIT(0)
+
+#define POLFLAG_DCLK_INV	BIT(3)
+
+enum vop2_layer_phy_id {
+	ROCKCHIP_VOP2_CLUSTER0 = 0,
+	ROCKCHIP_VOP2_CLUSTER1,
+	ROCKCHIP_VOP2_ESMART0,
+	ROCKCHIP_VOP2_ESMART1,
+	ROCKCHIP_VOP2_SMART0,
+	ROCKCHIP_VOP2_SMART1,
+	ROCKCHIP_VOP2_CLUSTER2,
+	ROCKCHIP_VOP2_CLUSTER3,
+	ROCKCHIP_VOP2_ESMART2,
+	ROCKCHIP_VOP2_ESMART3,
+	ROCKCHIP_VOP2_PHY_ID_INVALID = -1,
+};
+
+extern const struct component_ops vop2_component_ops;
+
+#endif /* _ROCKCHIP_DRM_VOP2_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
new file mode 100644
index 0000000000000..683cd53c10158
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) Rockchip Electronics Co.Ltd
+ * Author: Andy Yan <andy.yan@rock-chips.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/component.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_print.h>
+
+#include "rockchip_drm_vop2.h"
+#include "rockchip_vop_reg.h"
+
+#define _VOP_REG(off, _mask, _shift, _write_mask) \
+	{ \
+		.offset = off, \
+		.mask = _mask, \
+		.shift = _shift, \
+		.write_mask = _write_mask, \
+	}
+
+#define VOP_REG(off, _mask, _shift) \
+		_VOP_REG(off, _mask, _shift, false)
+
+#define VOP_REG_MASK(off, _mask, s) \
+		_VOP_REG(off, _mask, s, true)
+
+static const uint32_t formats_win_full_10bit[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV16,
+	DRM_FORMAT_NV24,
+};
+
+static const uint32_t formats_win_full_10bit_yuyv[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV16,
+	DRM_FORMAT_NV24,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_VYUY,
+};
+
+static const uint32_t formats_win_lite[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+};
+
+static const uint64_t format_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static const uint64_t format_modifiers_afbc[] = {
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_CBR),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_CBR |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_CBR),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_CBR |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	/* SPLIT mandates SPARSE, RGB modes mandates YTR */
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_SPARSE |
+				AFBC_FORMAT_MOD_SPLIT),
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static const struct vop2_video_port_regs rk3568_vop_vp0_regs = {
+	.dsp_background = RK3568_VP0_DSP_BG,
+	.pre_scan_htiming = RK3568_VP0_PRE_SCAN_HTIMING,
+	.hpost_st_end = RK3568_VP0_POST_DSP_HACT_INFO,
+	.vpost_st_end = RK3568_VP0_POST_DSP_VACT_INFO,
+	.htotal_pw = RK3568_VP0_DSP_HTOTAL_HS_END,
+	.post_scl_factor = RK3568_VP0_POST_SCL_FACTOR_YRGB,
+	.hact_st_end = RK3568_VP0_DSP_HACT_ST_END,
+	.vtotal_pw = RK3568_VP0_DSP_VTOTAL_VS_END,
+	.vact_st_end = RK3568_VP0_DSP_VACT_ST_END,
+	.vact_st_end_f1 = RK3568_VP0_DSP_VACT_ST_END_F1,
+	.vs_st_end_f1 = RK3568_VP0_DSP_VS_ST_END_F1,
+	.vpost_st_end_f1 = RK3568_VP0_POST_DSP_VACT_INFO_F1,
+
+	.dsp_ctrl = RK3568_VP0_DSP_CTRL,
+	.mipi_ctrl = RK3568_VP0_MIPI_CTRL,
+	.bg_mix_ctrl = RK3568_VP0_BG_MIX_CTRL,
+	.irq_status = RK3568_VP0_INT_STATUS,
+	.irq_enable = RK3568_VP0_INT_EN,
+	.irq_clear = RK3568_VP0_INT_CLR,
+	.line_flag = RK3568_VP0_LINE_FLAG,
+};
+
+static const struct vop2_video_port_regs rk3568_vop_vp1_regs = {
+	.dsp_background = RK3568_VP1_DSP_BG,
+	.pre_scan_htiming = RK3568_VP1_PRE_SCAN_HTIMING,
+	.hpost_st_end = RK3568_VP1_POST_DSP_HACT_INFO,
+	.vpost_st_end = RK3568_VP1_POST_DSP_VACT_INFO,
+	.htotal_pw = RK3568_VP1_DSP_HTOTAL_HS_END,
+	.post_scl_factor = RK3568_VP1_POST_SCL_FACTOR_YRGB,
+	.hact_st_end = RK3568_VP1_DSP_HACT_ST_END,
+	.vtotal_pw = RK3568_VP1_DSP_VTOTAL_VS_END,
+	.vact_st_end = RK3568_VP1_DSP_VACT_ST_END,
+	.vact_st_end_f1 = RK3568_VP1_DSP_VACT_ST_END_F1,
+	.vs_st_end_f1 = RK3568_VP1_DSP_VS_ST_END_F1,
+	.vpost_st_end_f1 = RK3568_VP1_POST_DSP_VACT_INFO_F1,
+	.dsp_ctrl = RK3568_VP1_DSP_CTRL,
+	.mipi_ctrl = RK3568_VP1_MIPI_CTRL,
+	.bg_mix_ctrl = RK3568_VP1_BG_MIX_CTRL,
+	.irq_status = RK3568_VP1_INT_STATUS,
+	.irq_enable = RK3568_VP1_INT_EN,
+	.irq_clear = RK3568_VP1_INT_CLR,
+	.line_flag = RK3568_VP1_LINE_FLAG,
+};
+
+static const struct vop2_video_port_regs rk3568_vop_vp2_regs = {
+	.dsp_background = RK3568_VP2_DSP_BG,
+	.pre_scan_htiming = RK3568_VP2_PRE_SCAN_HTIMING,
+	.hpost_st_end = RK3568_VP2_POST_DSP_HACT_INFO,
+	.vpost_st_end = RK3568_VP2_POST_DSP_VACT_INFO,
+	.post_scl_factor = RK3568_VP2_POST_SCL_FACTOR_YRGB,
+	.htotal_pw = RK3568_VP2_DSP_HTOTAL_HS_END,
+	.hact_st_end = RK3568_VP2_DSP_HACT_ST_END,
+	.vtotal_pw = RK3568_VP2_DSP_VTOTAL_VS_END,
+	.vact_st_end = RK3568_VP2_DSP_VACT_ST_END,
+	.vact_st_end_f1 = RK3568_VP2_DSP_VACT_ST_END_F1,
+	.vs_st_end_f1 = RK3568_VP2_DSP_VS_ST_END_F1,
+	.vpost_st_end_f1 = RK3568_VP2_POST_DSP_VACT_INFO_F1,
+	.dsp_ctrl = RK3568_VP2_DSP_CTRL,
+	.mipi_ctrl = RK3568_VP2_MIPI_CTRL,
+	.bg_mix_ctrl = RK3568_VP2_BG_MIX_CTRL,
+	.irq_status = RK3568_VP2_INT_STATUS,
+	.irq_enable = RK3568_VP2_INT_EN,
+	.irq_clear = RK3568_VP2_INT_CLR,
+	.line_flag = RK3568_VP2_LINE_FLAG,
+};
+
+static const struct vop2_video_port_data rk3568_vop_video_ports[] = {
+	{
+		.id = 0,
+		.feature = VOP_FEATURE_OUTPUT_10BIT,
+		.gamma_lut_len = 1024,
+		.cubic_lut_len = 9 * 9 * 9,
+		.max_output = { 4096, 2304 },
+		.pre_scan_max_dly = { 69, 53, 53, 42 },
+		.regs = &rk3568_vop_vp0_regs,
+	}, {
+		.id = 1,
+		.gamma_lut_len = 1024,
+		.max_output = { 2048, 1536 },
+		.pre_scan_max_dly = { 40, 40, 40, 40 },
+		.regs = &rk3568_vop_vp1_regs,
+	}, {
+		.id = 2,
+		.gamma_lut_len = 1024,
+		.max_output = { 1920, 1080 },
+		.pre_scan_max_dly = { 40, 40, 40, 40 },
+		.regs = &rk3568_vop_vp2_regs,
+	},
+};
+
+static const struct vop2_cluster_regs rk3568_vop_cluster0 =  {
+	.afbc_enable = VOP_REG(RK3568_CLUSTER_CTRL, 0x1, 1),
+	.enable = VOP_REG(RK3568_CLUSTER_CTRL, 1, 0),
+	.lb_mode = VOP_REG(RK3568_CLUSTER_CTRL, 0xf, 4),
+};
+
+static const struct vop2_afbc rk3568_cluster_afbc = {
+	.format = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1f, 2),
+	.rb_swap = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 9),
+	.uv_swap = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 10),
+	.auto_gating_en = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL, 0x1, 4),
+	.half_block_en = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 7),
+	.block_split_en = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 8),
+	.hdr_ptr = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_HDR_PTR, 0xffffffff, 0),
+	.pic_size = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE, 0xffffffff, 0),
+	.pic_vir_width = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0xffff, 0),
+	.tile_num = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0xffff, 16),
+	.pic_offset = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET, 0xffffffff, 0),
+	.dsp_offset = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET, 0xffffffff, 0),
+	.transform_offset = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET, 0xffffffff, 0),
+	.rotate_90 = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 0),
+	.rotate_270 = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 1),
+	.xmirror = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 2),
+	.ymirror = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 3),
+};
+
+static const struct vop2_scl_regs rk3568_cluster_win_scl = {
+	.scale_yrgb_x = VOP_REG(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0xffff, 0x0),
+	.scale_yrgb_y = VOP_REG(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0xffff, 16),
+	.yrgb_ver_scl_mode = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x3, 14),
+	.yrgb_hor_scl_mode = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x3, 12),
+	.bic_coe_sel = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x3, 2),
+	.vsd_yrgb_gt2 = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x1, 28),
+	.vsd_yrgb_gt4 = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x1, 29),
+};
+
+static const struct vop2_scl_regs rk3568_esmart_win_scl = {
+	.scale_yrgb_x = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0xffff, 0x0),
+	.scale_yrgb_y = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0xffff, 16),
+	.scale_cbcr_x = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0xffff, 0x0),
+	.scale_cbcr_y = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0xffff, 16),
+	.yrgb_hor_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 0),
+	.yrgb_hscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 2),
+	.yrgb_ver_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 4),
+	.yrgb_vscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 6),
+	.cbcr_hor_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 8),
+	.cbcr_hscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 10),
+	.cbcr_ver_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 12),
+	.cbcr_vscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 14),
+	.bic_coe_sel = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 16),
+	.vsd_yrgb_gt2 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 8),
+	.vsd_yrgb_gt4 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 9),
+	.vsd_cbcr_gt2 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 10),
+	.vsd_cbcr_gt4 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 11),
+};
+
+static const struct vop2_win_regs rk3568_cluster_win_data = {
+	.scl = &rk3568_cluster_win_scl,
+	.afbc = &rk3568_cluster_afbc,
+	.cluster = &rk3568_vop_cluster0,
+	.enable = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 0),
+	.format = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1f, 1),
+	.rb_swap = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 14),
+	.dither_up = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 18),
+	.act_info = VOP_REG(RK3568_CLUSTER_WIN_ACT_INFO, 0x1fff1fff, 0),
+	.dsp_info = VOP_REG(RK3568_CLUSTER_WIN_DSP_INFO, 0x0fff0fff, 0),
+	.dsp_st = VOP_REG(RK3568_CLUSTER_WIN_DSP_ST, 0x1fff1fff, 0),
+	.yrgb_mst = VOP_REG(RK3568_CLUSTER_WIN_YRGB_MST, 0xffffffff, 0),
+	.uv_mst = VOP_REG(RK3568_CLUSTER_WIN_CBR_MST, 0xffffffff, 0),
+	.yuv_clip = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 19),
+	.yrgb_vir = VOP_REG(RK3568_CLUSTER_WIN_VIR, 0xffff, 0),
+	.uv_vir = VOP_REG(RK3568_CLUSTER_WIN_VIR, 0xffff, 16),
+	.y2r_en = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 8),
+	.r2y_en = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 9),
+	.csc_mode = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x3, 10),
+};
+
+static const struct vop2_win_regs rk3568_esmart_win_data = {
+	.scl = &rk3568_esmart_win_scl,
+	.enable = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 0),
+	.format = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1f, 1),
+	.dither_up = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 12),
+	.rb_swap = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 14),
+	.uv_swap = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 16),
+	.act_info = VOP_REG(RK3568_SMART_REGION0_ACT_INFO, 0x1fff1fff, 0),
+	.dsp_info = VOP_REG(RK3568_SMART_REGION0_DSP_INFO, 0x0fff0fff, 0),
+	.dsp_st = VOP_REG(RK3568_SMART_REGION0_DSP_ST, 0x1fff1fff, 0),
+	.yrgb_mst = VOP_REG(RK3568_SMART_REGION0_YRGB_MST, 0xffffffff, 0),
+	.uv_mst = VOP_REG(RK3568_SMART_REGION0_CBR_MST, 0xffffffff, 0),
+	.yuv_clip = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 17),
+	.yrgb_vir = VOP_REG(RK3568_SMART_REGION0_VIR, 0xffff, 0),
+	.uv_vir = VOP_REG(RK3568_SMART_REGION0_VIR, 0xffff, 16),
+	.y2r_en = VOP_REG(RK3568_SMART_CTRL0, 0x1, 0),
+	.r2y_en = VOP_REG(RK3568_SMART_CTRL0, 0x1, 1),
+	.csc_mode = VOP_REG(RK3568_SMART_CTRL0, 0x3, 2),
+	.ymirror = VOP_REG(RK3568_SMART_CTRL1, 0x1, 31),
+	.color_key = VOP_REG(RK3568_SMART_COLOR_KEY_CTRL, 0x3fffffff, 0),
+	.color_key_en = VOP_REG(RK3568_SMART_COLOR_KEY_CTRL, 0x1, 31),
+};
+
+/*
+ * rk3568 vop with 2 cluster, 2 esmart win, 2 smart win.
+ * Every cluster can work as 4K win or split into two win.
+ * All win in cluster support AFBCD.
+ *
+ * Every esmart win and smart win support 4 Multi-region.
+ *
+ * Scale filter mode:
+ *
+ * * Cluster:  bicubic for horizontal scale up, others use bilinear
+ * * ESmart:
+ *    * nearest-neighbor/bilinear/bicubic for scale up
+ *    * nearest-neighbor/bilinear/average for scale down
+ *
+ *
+ * @TODO describe the wind like cpu-map dt nodes;
+ */
+static const struct vop2_win_data rk3568_vop_win_data[] = {
+	{
+		.name = "Smart0-win0",
+		.phys_id = ROCKCHIP_VOP2_SMART0,
+		.base = 0x1c00,
+		.formats = formats_win_lite,
+		.nformats = ARRAY_SIZE(formats_win_lite),
+		.format_modifiers = format_modifiers,
+		.layer_sel_id = 3,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_PRIMARY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Smart1-win0",
+		.phys_id = ROCKCHIP_VOP2_SMART1,
+		.formats = formats_win_lite,
+		.nformats = ARRAY_SIZE(formats_win_lite),
+		.format_modifiers = format_modifiers,
+		.base = 0x1e00,
+		.layer_sel_id = 7,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_PRIMARY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Esmart1-win0",
+		.phys_id = ROCKCHIP_VOP2_ESMART1,
+		.formats = formats_win_full_10bit_yuyv,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
+		.format_modifiers = format_modifiers,
+		.base = 0x1a00,
+		.layer_sel_id = 6,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_PRIMARY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Esmart0-win0",
+		.phys_id = ROCKCHIP_VOP2_ESMART0,
+		.formats = formats_win_full_10bit_yuyv,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
+		.format_modifiers = format_modifiers,
+		.base = 0x1800,
+		.layer_sel_id = 2,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_OVERLAY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Cluster0-win0",
+		.phys_id = ROCKCHIP_VOP2_CLUSTER0,
+		.base = 0x1000,
+		.formats = formats_win_full_10bit,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit),
+		.format_modifiers = format_modifiers_afbc,
+		.layer_sel_id = 0,
+		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
+					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_cluster_win_data,
+		.max_upscale_factor = 4,
+		.max_downscale_factor = 4,
+		.dly = { 0, 27, 21 },
+		.type = DRM_PLANE_TYPE_OVERLAY,
+		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
+	}, {
+		.name = "Cluster1-win0",
+		.phys_id = ROCKCHIP_VOP2_CLUSTER1,
+		.base = 0x1200,
+		.formats = formats_win_full_10bit,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit),
+		.format_modifiers = format_modifiers_afbc,
+		.layer_sel_id = 1,
+		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
+					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_cluster_win_data,
+		.type = DRM_PLANE_TYPE_OVERLAY,
+		.max_upscale_factor = 4,
+		.max_downscale_factor = 4,
+		.dly = { 0, 27, 21 },
+		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
+	},
+};
+
+static const struct vop_grf_ctrl rk3568_grf_ctrl = {
+	.grf_bt656_clk_inv = VOP_REG(RK3568_GRF_VO_CON1, 0x1, 1),
+	.grf_bt1120_clk_inv = VOP_REG(RK3568_GRF_VO_CON1, 0x1, 2),
+	.grf_dclk_inv = VOP_REG(RK3568_GRF_VO_CON1, 0x1, 3),
+};
+
+static const struct vop2_data rk3566_vop = {
+	.nr_vps = 3,
+	.nr_mixers = 5,
+	.nr_gammas = 1,
+	.max_input = { 4096, 2304 },
+	.max_output = { 4096, 2304 },
+	.grf_ctrl = &rk3568_grf_ctrl,
+	.vp = rk3568_vop_video_ports,
+	.win = rk3568_vop_win_data,
+	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
+	.soc_id = 3566,
+};
+
+static const struct vop2_data rk3568_vop = {
+	.nr_vps = 3,
+	.nr_mixers = 5,
+	.nr_gammas = 1,
+	.max_input = { 4096, 2304 },
+	.max_output = { 4096, 2304 },
+	.grf_ctrl = &rk3568_grf_ctrl,
+	.vp = rk3568_vop_video_ports,
+	.win = rk3568_vop_win_data,
+	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
+	.soc_id = 3568,
+};
+
+static const struct of_device_id vop2_dt_match[] = {
+	{
+		.compatible = "rockchip,rk3568-vop",
+		.data = &rk3568_vop
+	}, {
+		.compatible = "rockchip,rk3568-vop",
+		.data = &rk3566_vop
+	}, {
+	},
+};
+MODULE_DEVICE_TABLE(of, vop2_dt_match);
+
+static int vop2_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	return component_add(dev, &vop2_component_ops);
+}
+
+static int vop2_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &vop2_component_ops);
+
+	return 0;
+}
+
+struct platform_driver vop2_platform_driver = {
+	.probe = vop2_probe,
+	.remove = vop2_remove,
+	.driver = {
+		.name = "rockchip-vop2",
+		.of_match_table = of_match_ptr(vop2_dt_match),
+	},
+};
-- 
2.30.2


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

* [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

From: Andy Yan <andy.yan@rock-chips.com>

The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
It replaces the VOP unit found in the older Rockchip SoCs.

This driver has been derived from the downstream Rockchip Kernel and
heavily modified:

- All nonstandard DRM properties have been removed
- dropped struct vop2_plane_state and pass around less data between
  functions
- Dropped all DRM_FORMAT_* not known on upstream
- rework register access to get rid of excessively used macros
- Drop all waiting for framesyncs

The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
board. Overlay support is tested with the modetest utility. AFBC support
on the cluster windows is tested with weston-simple-dmabuf-egl on
weston using the (yet to be upstreamed) panfrost driver support.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/Kconfig             |    6 +
 drivers/gpu/drm/rockchip/Makefile            |    1 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c  |    1 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h  |    7 +-
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c   |    2 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h  |   15 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2636 ++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |  625 +++++
 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c |  505 ++++
 9 files changed, 3797 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index b9b156308460a..4ff0043f0ee70 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -28,6 +28,12 @@ config ROCKCHIP_VOP
 	  This selects support for the VOP driver. You should enable it
 	  on all older SoCs up to RK3399.
 
+config ROCKCHIP_VOP2
+	bool "Rockchip VOP2 driver"
+	help
+	  This selects support for the VOP2 driver. You should enable it
+	  on all newer SoCs beginning form RK3568.
+
 config ROCKCHIP_ANALOGIX_DP
 	bool "Rockchip specific extensions for Analogix DP driver"
 	depends on ROCKCHIP_VOP
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index cd6e7bb5ce9c5..29848caef5c21 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -7,6 +7,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
 		rockchip_drm_gem.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
+rockchipdrm-$(CONFIG_ROCKCHIP_VOP2) += rockchip_drm_vop2.o rockchip_vop2_reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 64fa5fd62c01a..2bd9acb265e5a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -474,6 +474,7 @@ static int __init rockchip_drm_init(void)
 
 	num_rockchip_sub_drivers = 0;
 	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP);
+	ADD_ROCKCHIP_SUB_DRIVER(vop2_platform_driver, CONFIG_ROCKCHIP_VOP2);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver,
 				CONFIG_ROCKCHIP_LVDS);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index aa0909e8edf93..fd6994f21817e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -18,7 +18,7 @@
 
 #define ROCKCHIP_MAX_FB_BUFFER	3
 #define ROCKCHIP_MAX_CONNECTOR	2
-#define ROCKCHIP_MAX_CRTC	2
+#define ROCKCHIP_MAX_CRTC	4
 
 struct drm_device;
 struct drm_connector;
@@ -31,6 +31,9 @@ struct rockchip_crtc_state {
 	int output_bpc;
 	int output_flags;
 	bool enable_afbc;
+	uint32_t bus_format;
+	u32 bus_flags;
+	int color_space;
 };
 #define to_rockchip_crtc_state(s) \
 		container_of(s, struct rockchip_crtc_state, base)
@@ -65,4 +68,6 @@ extern struct platform_driver rockchip_dp_driver;
 extern struct platform_driver rockchip_lvds_driver;
 extern struct platform_driver vop_platform_driver;
 extern struct platform_driver rk3066_hdmi_driver;
+extern struct platform_driver vop2_platform_driver;
+
 #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 3aa37e177667e..0d2cb4f3922b8 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -134,4 +134,6 @@ void rockchip_drm_mode_config_init(struct drm_device *dev)
 
 	dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
 	dev->mode_config.helper_private = &rockchip_mode_config_helpers;
+
+	dev->mode_config.normalize_zpos = true;
 }
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 857d97cdc67c6..1e364d7b50e69 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -54,9 +54,23 @@ struct vop_afbc {
 	struct vop_reg enable;
 	struct vop_reg win_sel;
 	struct vop_reg format;
+	struct vop_reg rb_swap;
+	struct vop_reg uv_swap;
+	struct vop_reg auto_gating_en;
+	struct vop_reg block_split_en;
+	struct vop_reg pic_vir_width;
+	struct vop_reg tile_num;
 	struct vop_reg hreg_block_split;
+	struct vop_reg pic_offset;
 	struct vop_reg pic_size;
+	struct vop_reg dsp_offset;
+	struct vop_reg transform_offset;
 	struct vop_reg hdr_ptr;
+	struct vop_reg half_block_en;
+	struct vop_reg xmirror;
+	struct vop_reg ymirror;
+	struct vop_reg rotate_270;
+	struct vop_reg rotate_90;
 	struct vop_reg rstn;
 };
 
@@ -410,4 +424,5 @@ static inline int scl_vop_cal_lb_mode(int width, bool is_yuv)
 }
 
 extern const struct component_ops vop_component_ops;
+
 #endif /* _ROCKCHIP_DRM_VOP_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
new file mode 100644
index 0000000000000..411440d898ab0
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -0,0 +1,2636 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Rockchip Electronics Co., Ltd.
+ * Author: Andy Yan <andy.yan@rock-chips.com>
+ */
+#include <drm/drm.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_flip_work.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_writeback.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_atomic_uapi.h>
+
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <linux/component.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/delay.h>
+#include <linux/swab.h>
+#include <drm/drm_debugfs.h>
+#include <uapi/linux/videodev2.h>
+#include <drm/drm_vblank.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_vop2.h"
+#include "rockchip_vop_reg.h"
+
+/*
+ * VOP2 architecture
+ *
+ +----------+   +-------------+                                                        +-----------+
+ |  Cluster |   | Sel 1 from 6|                                                        | 1 from 3  |
+ |  window0 |   |    Layer0   |                                                        |    RGB    |
+ +----------+   +-------------+              +---------------+    +-------------+      +-----------+
+ +----------+   +-------------+              |N from 6 layers|    |             |
+ |  Cluster |   | Sel 1 from 6|              |   Overlay0    +--->| Video Port0 |      +-----------+
+ |  window1 |   |    Layer1   |              |               |    |             |      | 1 from 3  |
+ +----------+   +-------------+              +---------------+    +-------------+      |   LVDS    |
+ +----------+   +-------------+                                                        +-----------+
+ |  Esmart  |   | Sel 1 from 6|
+ |  window0 |   |   Layer2    |              +---------------+    +-------------+      +-----------+
+ +----------+   +-------------+              |N from 6 Layers|    |             | +--> | 1 from 3  |
+ +----------+   +-------------+   -------->  |   Overlay1    +--->| Video Port1 |      |   MIPI    |
+ |  Esmart  |   | Sel 1 from 6|   -------->  |               |    |             |      +-----------+
+ |  Window1 |   |   Layer3    |              +---------------+    +-------------+
+ +----------+   +-------------+                                                        +-----------+
+ +----------+   +-------------+                                                        | 1 from 3  |
+ |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |   HDMI    |
+ |  Window0 |   |    Layer4   |              |N from 6 Layers|    |             |      +-----------+
+ +----------+   +-------------+              |   Overlay2    +--->| Video Port2 |
+ +----------+   +-------------+              |               |    |             |      +-----------+
+ |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |  1 from 3 |
+ |  Window1 |   |    Layer5   |                                                        |    eDP    |
+ +----------+   +-------------+                                                        +-----------+
+ *
+ */
+
+enum vop2_data_format {
+	VOP2_FMT_ARGB8888 = 0,
+	VOP2_FMT_RGB888,
+	VOP2_FMT_RGB565,
+	VOP2_FMT_XRGB101010,
+	VOP2_FMT_YUV420SP,
+	VOP2_FMT_YUV422SP,
+	VOP2_FMT_YUV444SP,
+	VOP2_FMT_YUYV422 = 8,
+	VOP2_FMT_YUYV420,
+	VOP2_FMT_VYUY422,
+	VOP2_FMT_VYUY420,
+	VOP2_FMT_YUV420SP_TILE_8x4 = 0x10,
+	VOP2_FMT_YUV420SP_TILE_16x2,
+	VOP2_FMT_YUV422SP_TILE_8x4,
+	VOP2_FMT_YUV422SP_TILE_16x2,
+	VOP2_FMT_YUV420SP_10,
+	VOP2_FMT_YUV422SP_10,
+	VOP2_FMT_YUV444SP_10,
+};
+
+enum vop2_afbc_format {
+	VOP2_AFBC_FMT_RGB565,
+	VOP2_AFBC_FMT_ARGB2101010 = 2,
+	VOP2_AFBC_FMT_YUV420_10BIT,
+	VOP2_AFBC_FMT_RGB888,
+	VOP2_AFBC_FMT_ARGB8888,
+	VOP2_AFBC_FMT_YUV420 = 9,
+	VOP2_AFBC_FMT_YUV422 = 0xb,
+	VOP2_AFBC_FMT_YUV422_10BIT = 0xe,
+	VOP2_AFBC_FMT_INVALID = -1,
+};
+
+union vop2_alpha_ctrl {
+	uint32_t val;
+	struct {
+		/* [0:1] */
+		uint32_t color_mode:1;
+		uint32_t alpha_mode:1;
+		/* [2:3] */
+		uint32_t blend_mode:2;
+		uint32_t alpha_cal_mode:1;
+		/* [5:7] */
+		uint32_t factor_mode:3;
+		/* [8:9] */
+		uint32_t alpha_en:1;
+		uint32_t src_dst_swap:1;
+		uint32_t reserved:6;
+		/* [16:23] */
+		uint32_t glb_alpha:8;
+	} bits;
+};
+
+struct vop2_alpha {
+	union vop2_alpha_ctrl src_color_ctrl;
+	union vop2_alpha_ctrl dst_color_ctrl;
+	union vop2_alpha_ctrl src_alpha_ctrl;
+	union vop2_alpha_ctrl dst_alpha_ctrl;
+};
+
+struct vop2_alpha_config {
+	bool src_premulti_en;
+	bool dst_premulti_en;
+	bool src_pixel_alpha_en;
+	bool dst_pixel_alpha_en;
+	uint16_t src_glb_alpha_value;
+	uint16_t dst_glb_alpha_value;
+};
+
+struct vop2_win {
+	struct vop2 *vop2;
+	struct drm_plane base;
+	const struct vop2_win_data *data;
+
+	/**
+	 * @win_id: graphic window id, a cluster maybe split into two
+	 * graphics windows.
+	 */
+	uint8_t win_id;
+
+	uint32_t offset;
+
+	uint8_t delay;
+	enum drm_plane_type type;
+
+	const struct vop2_win_regs *regs;
+};
+
+struct vop2_video_port {
+	struct drm_crtc crtc;
+	struct vop2 *vop2;
+	struct clk *dclk;
+	uint8_t id;
+	const struct vop2_video_port_regs *regs;
+	const struct vop2_video_port_data *data;
+
+	struct completion dsp_hold_completion;
+
+	/**
+	 * @win_mask: Bitmask of wins attached to the video port;
+	 */
+	uint32_t win_mask;
+
+	struct vop2_win *primary_plane;
+	struct drm_pending_vblank_event *event;
+
+	int nlayers;
+};
+
+struct vop2 {
+	struct device *dev;
+	struct drm_device *drm;
+	struct vop2_video_port vps[ROCKCHIP_MAX_CRTC];
+
+	const struct vop2_data *data;
+	/* Number of win that registered as plane,
+	 * maybe less than the total number of hardware
+	 * win.
+	 */
+	uint32_t registered_num_wins;
+
+	uint32_t *regsbak;
+	void __iomem *regs;
+	struct regmap *grf;
+
+	/* physical map length of vop2 register */
+	uint32_t len;
+
+	void __iomem *lut_regs;
+	/* one time only one process allowed to config the register */
+	spinlock_t reg_lock;
+
+	/* protects crtc enable/disable */
+	struct mutex vop2_lock;
+
+	int irq;
+
+	/*
+	 * Some globle resource are shared between all
+	 * the vidoe ports(crtcs), so we need a ref counter here.
+	 */
+	unsigned int enable_count;
+	struct clk *hclk;
+	struct clk *aclk;
+
+	/* must put at the end of the struct */
+	struct vop2_win win[];
+};
+
+static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct vop2_video_port, crtc);
+}
+
+static struct vop2_win *to_vop2_win(struct drm_plane *p)
+{
+	return container_of(p, struct vop2_win, base);
+}
+
+static void vop2_lock(struct vop2 *vop2)
+{
+	mutex_lock(&vop2->vop2_lock);
+}
+
+static void vop2_unlock(struct vop2 *vop2)
+{
+	mutex_unlock(&vop2->vop2_lock);
+}
+
+static void vop2_grf_writel(struct vop2 *vop2, const struct vop_reg *reg,
+				   uint32_t v)
+{
+	uint32_t val = 0;
+
+	if (IS_ERR_OR_NULL(vop2->grf))
+		return;
+
+	if (reg->mask) {
+		val = (v << reg->shift) | (reg->mask << (reg->shift + 16));
+		regmap_write(vop2->grf, reg->offset, val);
+	}
+}
+
+static void vop2_writel(struct vop2 *vop2, uint32_t offset, uint32_t v)
+{
+	writel(v, vop2->regs + offset);
+	vop2->regsbak[offset >> 2] = v;
+}
+
+static uint32_t vop2_readl(struct vop2 *vop2, uint32_t offset)
+{
+	return readl(vop2->regs + offset);
+}
+
+static void vop2_write_reg(struct vop2 *vop2, uint32_t offset,
+			   const struct vop_reg *reg, uint32_t v, bool relaxed)
+{
+	uint32_t mask = reg->mask;
+	uint32_t shift = reg->shift;
+
+	if (!mask)
+		return;
+
+	offset += reg->offset;
+
+	if (reg->write_mask) {
+		v = ((v & mask) << shift) | (mask << (shift + 16));
+	} else {
+		/*
+		 * Several registers in the VOP2 are double buffered and read back
+		 * the new values only after config_done bits have been set. As we
+		 * read-modify-write the hardware registers we need to cache the values
+		 * in memory to make sure we do not overwrite previous values when a
+		 * hardware register is modified multiple times before config_done is
+		 * set.
+		 */
+		uint32_t cached_val = vop2->regsbak[offset >> 2];
+
+		v = (cached_val & ~(mask << shift)) | ((v & mask) << shift);
+		vop2->regsbak[offset >> 2] = v;
+	}
+
+	if (relaxed)
+		writel_relaxed(v, vop2->regs + offset);
+	else
+		writel(v, vop2->regs + offset);
+}
+
+static void vop2_win_write(const struct vop2_win *win, const struct vop_reg *reg,
+			   uint32_t v)
+{
+	vop2_write_reg(win->vop2, win->offset, reg, v, true);
+}
+
+static bool vop2_cluster_window(struct vop2_win *win)
+{
+	return win->data->feature & WIN_FEATURE_CLUSTER;
+}
+
+static void vop2_cfg_done(struct vop2_video_port *vp)
+{
+	struct vop2 *vop2 = vp->vop2;
+	uint32_t val;
+
+	val = vop2_readl(vop2, RK3568_REG_CFG_DONE);
+
+	val &= 0x7;
+
+	vop2_writel(vop2, RK3568_REG_CFG_DONE,
+		    val | BIT(vp->id) | RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
+}
+
+static void vop2_win_disable(struct vop2_win *win)
+{
+	vop2_win_write(win, &win->regs->enable, 0);
+
+	if (vop2_cluster_window(win))
+		vop2_win_write(win, &win->regs->cluster->enable, 0);
+}
+
+static enum vop2_data_format vop2_convert_format(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		return VOP2_FMT_ARGB8888;
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		return VOP2_FMT_RGB888;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		return VOP2_FMT_RGB565;
+	case DRM_FORMAT_NV12:
+		return VOP2_FMT_YUV420SP;
+	case DRM_FORMAT_NV16:
+		return VOP2_FMT_YUV422SP;
+	case DRM_FORMAT_NV24:
+		return VOP2_FMT_YUV444SP;
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_YVYU:
+		return VOP2_FMT_VYUY422;
+	case DRM_FORMAT_VYUY:
+	case DRM_FORMAT_UYVY:
+		return VOP2_FMT_YUYV422;
+	default:
+		DRM_ERROR("unsupported format[%08x]\n", format);
+		return -EINVAL;
+	}
+}
+
+static enum vop2_afbc_format vop2_convert_afbc_format(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		return VOP2_AFBC_FMT_ARGB8888;
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		return VOP2_AFBC_FMT_RGB888;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		return VOP2_AFBC_FMT_RGB565;
+	case DRM_FORMAT_NV12:
+		return VOP2_AFBC_FMT_YUV420;
+	case DRM_FORMAT_NV16:
+		return VOP2_AFBC_FMT_YUV422;
+	default:
+		return VOP2_AFBC_FMT_INVALID;
+	}
+
+	return VOP2_AFBC_FMT_INVALID;
+}
+
+static bool vop2_win_rb_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_BGR888:
+	case DRM_FORMAT_BGR565:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_afbc_rb_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV24:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_afbc_uv_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV16:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_win_uv_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV24:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_win_dither_up(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_BGR565:
+	case DRM_FORMAT_RGB565:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_output_uv_swap(uint32_t bus_format, uint32_t output_mode)
+{
+	/*
+	 * FIXME:
+	 *
+	 * There is no media type for YUV444 output,
+	 * so when out_mode is AAAA or P888, assume output is YUV444 on
+	 * yuv format.
+	 *
+	 * From H/W testing, YUV444 mode need a rb swap.
+	 */
+	if (bus_format == MEDIA_BUS_FMT_YVYU8_1X16 ||
+	    bus_format == MEDIA_BUS_FMT_VYUY8_1X16 ||
+	    bus_format == MEDIA_BUS_FMT_YVYU8_2X8 ||
+	    bus_format == MEDIA_BUS_FMT_VYUY8_2X8 ||
+	    ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||
+	      bus_format == MEDIA_BUS_FMT_YUV10_1X30) &&
+	     (output_mode == ROCKCHIP_OUT_MODE_AAAA ||
+	      output_mode == ROCKCHIP_OUT_MODE_P888)))
+		return true;
+	else
+		return false;
+}
+
+static bool is_yuv_output(uint32_t bus_format)
+{
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_YUV8_1X24:
+	case MEDIA_BUS_FMT_YUV10_1X30:
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+	case MEDIA_BUS_FMT_YUYV8_2X8:
+	case MEDIA_BUS_FMT_YVYU8_2X8:
+	case MEDIA_BUS_FMT_UYVY8_2X8:
+	case MEDIA_BUS_FMT_VYUY8_2X8:
+	case MEDIA_BUS_FMT_YUYV8_1X16:
+	case MEDIA_BUS_FMT_YVYU8_1X16:
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+	case MEDIA_BUS_FMT_VYUY8_1X16:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rockchip_afbc(struct drm_plane *plane, u64 modifier)
+{
+	int i;
+
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return false;
+
+	for (i = 0 ; i < plane->modifier_count; i++)
+		if (plane->modifiers[i] == modifier)
+			break;
+
+	return (i < plane->modifier_count) ? true : false;
+
+}
+
+static bool rockchip_vop2_mod_supported(struct drm_plane *plane, uint32_t format, u64 modifier)
+{
+	struct vop2_win *win = to_vop2_win(plane);
+	struct vop2 *vop2 = win->vop2;
+
+	if (modifier == DRM_FORMAT_MOD_INVALID)
+		return false;
+
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return true;
+
+	if (!rockchip_afbc(plane, modifier)) {
+		drm_err(vop2->drm, "Unsupported format modifier 0x%llx\n", modifier);
+
+		return false;
+	}
+
+	return vop2_convert_afbc_format(format) >= 0;
+}
+
+static int vop2_afbc_half_block_enable(struct drm_plane_state *pstate)
+{
+	if ((pstate->rotation & DRM_MODE_ROTATE_270) || (pstate->rotation & DRM_MODE_ROTATE_90))
+		return 0;
+	else
+		return 1;
+}
+
+static uint32_t vop2_afbc_transform_offset(struct drm_plane_state *pstate,
+					   bool afbc_half_block_en)
+{
+	struct drm_rect *src = &pstate->src;
+	struct drm_framebuffer *fb = pstate->fb;
+	uint32_t bpp = fb->format->cpp[0] * 8;
+	uint32_t vir_width = (fb->pitches[0] << 3) / bpp;
+	uint32_t width = drm_rect_width(src) >> 16;
+	uint32_t height = drm_rect_height(src) >> 16;
+	uint32_t act_xoffset = src->x1 >> 16;
+	uint32_t act_yoffset = src->y1 >> 16;
+	uint32_t align16_crop = 0;
+	uint32_t align64_crop = 0;
+	uint32_t height_tmp = 0;
+	uint32_t transform_tmp = 0;
+	uint8_t transform_xoffset = 0;
+	uint8_t transform_yoffset = 0;
+	uint8_t top_crop = 0;
+	uint8_t top_crop_line_num = 0;
+	uint8_t bottom_crop_line_num = 0;
+
+	/* 16 pixel align */
+	if (height & 0xf)
+		align16_crop = 16 - (height & 0xf);
+
+	height_tmp = height + align16_crop;
+
+	/* 64 pixel align */
+	if (height_tmp & 0x3f)
+		align64_crop = 64 - (height_tmp & 0x3f);
+
+	top_crop_line_num = top_crop << 2;
+	if (top_crop == 0)
+		bottom_crop_line_num = align16_crop + align64_crop;
+	else if (top_crop == 1)
+		bottom_crop_line_num = align16_crop + align64_crop + 12;
+	else if (top_crop == 2)
+		bottom_crop_line_num = align16_crop + align64_crop + 8;
+
+	switch (pstate->rotation &
+		(DRM_MODE_REFLECT_X |
+		 DRM_MODE_REFLECT_Y |
+		 DRM_MODE_ROTATE_90 |
+		 DRM_MODE_ROTATE_270)) {
+	case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
+		transform_tmp = act_xoffset + width;
+		transform_xoffset = 16 - (transform_tmp & 0xf);
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = (transform_tmp & 0xf);
+
+		break;
+	case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90:
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = vir_width - width - act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270:
+		transform_tmp = top_crop_line_num + act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case DRM_MODE_REFLECT_X:
+		transform_tmp = act_xoffset + width;
+		transform_xoffset = 16 - (transform_tmp & 0xf);
+		transform_tmp = top_crop_line_num + act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = transform_tmp & 0xf;
+
+		break;
+	case DRM_MODE_REFLECT_Y:
+		transform_tmp = act_xoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = transform_tmp & 0xf;
+
+		break;
+	case DRM_MODE_ROTATE_90:
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case DRM_MODE_ROTATE_270:
+		transform_tmp = top_crop_line_num + act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = vir_width - width - act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case 0:
+		transform_tmp = act_xoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = top_crop_line_num + act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = transform_tmp & 0xf;
+
+		break;
+	}
+
+	return (transform_xoffset & 0xf) | ((transform_yoffset & 0xf) << 16);
+}
+
+/*
+ * A Cluster window has 2048 x 16 line buffer, which can
+ * works at 2048 x 16(Full) or 4096 x 8 (Half) mode.
+ * for Cluster_lb_mode register:
+ * 0: half mode, for plane input width range 2048 ~ 4096
+ * 1: half mode, for cluster work at 2 * 2048 plane mode
+ * 2: half mode, for rotate_90/270 mode
+ *
+ */
+static int vop2_get_cluster_lb_mode(struct vop2_win *win, struct drm_plane_state *pstate)
+{
+	if ((pstate->rotation & DRM_MODE_ROTATE_270) || (pstate->rotation & DRM_MODE_ROTATE_90))
+		return 2;
+	else
+		return 0;
+}
+
+/*
+ * bli_sd_factor = (src - 1) / (dst - 1) << 12;
+ * avg_sd_factor:
+ * bli_su_factor:
+ * bic_su_factor:
+ * = (src - 1) / (dst - 1) << 16;
+ *
+ * gt2 enable: dst get one line from two line of the src
+ * gt4 enable: dst get one line from four line of the src.
+ *
+ */
+static uint16_t vop2_scale_factor(enum scale_mode mode,
+				  int32_t filter_mode,
+				  uint32_t src, uint32_t dst)
+{
+	uint32_t fac;
+	int i;
+
+	if (mode == SCALE_NONE)
+		return 0;
+
+	/*
+	 * A workaround to avoid zero div.
+	 */
+	if (dst == 1 || src == 1) {
+		dst++;
+		src++;
+	}
+
+	if ((mode == SCALE_DOWN) && (filter_mode == VOP2_SCALE_DOWN_BIL)) {
+		fac = ((src - 1) << 12) / (dst - 1);
+		for (i = 0; i < 100; i++) {
+			if (fac * (dst - 1) >> 12 < (src - 1))
+				break;
+			fac -= 1;
+			DRM_DEBUG("down fac cali: src:%d, dst:%d, fac:0x%x\n", src, dst, fac);
+		}
+	} else {
+		fac = ((src - 1) << 16) / (dst - 1);
+		for (i = 0; i < 100; i++) {
+			if (fac * (dst - 1) >> 16 < (src - 1))
+				break;
+			fac -= 1;
+			DRM_DEBUG("up fac cali:  src:%d, dst:%d, fac:0x%x\n", src, dst, fac);
+		}
+	}
+
+	return fac;
+}
+
+static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win,
+			     uint32_t src_w, uint32_t src_h, uint32_t dst_w,
+			     uint32_t dst_h, uint32_t pixel_format)
+{
+	const struct vop2_win_data *win_data = win->data;
+	const struct drm_format_info *info;
+	uint16_t cbcr_src_w;
+	uint16_t cbcr_src_h;
+	uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode;
+	uint16_t cbcr_hor_scl_mode, cbcr_ver_scl_mode;
+	uint16_t hscl_filter_mode, vscl_filter_mode;
+	uint8_t gt2 = 0;
+	uint8_t gt4 = 0;
+	uint32_t val;
+
+	info = drm_format_info(pixel_format);
+
+	cbcr_src_w = src_w / info->hsub;
+	cbcr_src_h = src_h / info->vsub;
+
+	if (src_h >= (4 * dst_h)) {
+		gt4 = 1;
+		src_h >>= 2;
+	} else if (src_h >= (2 * dst_h)) {
+		gt2 = 1;
+		src_h >>= 1;
+	}
+
+	yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
+	yrgb_ver_scl_mode = scl_get_scl_mode(src_h, dst_h);
+
+	if (yrgb_hor_scl_mode == SCALE_UP)
+		hscl_filter_mode = win_data->hsu_filter_mode;
+	else
+		hscl_filter_mode = win_data->hsd_filter_mode;
+
+	if (yrgb_ver_scl_mode == SCALE_UP)
+		vscl_filter_mode = win_data->vsu_filter_mode;
+	else
+		vscl_filter_mode = win_data->vsd_filter_mode;
+
+	/*
+	 * RK3568 VOP Esmart/Smart dsp_w should be even pixel
+	 * at scale down mode
+	 */
+	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
+		if ((yrgb_hor_scl_mode == SCALE_DOWN) && (dst_w & 0x1)) {
+			drm_dbg(vop2->drm, "%s dst_w[%d] should align as 2 pixel\n",
+				win->data->name, dst_w);
+			dst_w += 1;
+		}
+	}
+
+	val = vop2_scale_factor(yrgb_hor_scl_mode, hscl_filter_mode,
+				src_w, dst_w);
+	vop2_win_write(win, &win->regs->scl->scale_yrgb_x, val);
+	val = vop2_scale_factor(yrgb_ver_scl_mode, vscl_filter_mode,
+				src_h, dst_h);
+	vop2_win_write(win, &win->regs->scl->scale_yrgb_y, val);
+
+	vop2_win_write(win, &win->regs->scl->vsd_yrgb_gt4, gt4);
+	vop2_win_write(win, &win->regs->scl->vsd_yrgb_gt2, gt2);
+
+	vop2_win_write(win, &win->regs->scl->yrgb_hor_scl_mode, yrgb_hor_scl_mode);
+	vop2_win_write(win, &win->regs->scl->yrgb_ver_scl_mode, yrgb_ver_scl_mode);
+
+	vop2_win_write(win, &win->regs->scl->yrgb_hscl_filter_mode, hscl_filter_mode);
+	vop2_win_write(win, &win->regs->scl->yrgb_vscl_filter_mode, vscl_filter_mode);
+
+	if (info->is_yuv) {
+		gt4 = gt2 = 0;
+
+		if (cbcr_src_h >= (4 * dst_h))
+			gt4 = 1;
+		else if (cbcr_src_h >= (2 * dst_h))
+			gt2 = 1;
+
+		if (gt4)
+			cbcr_src_h >>= 2;
+		else if (gt2)
+			cbcr_src_h >>= 1;
+
+		cbcr_hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w);
+		cbcr_ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h);
+
+		val = vop2_scale_factor(cbcr_hor_scl_mode, hscl_filter_mode,
+					cbcr_src_w, dst_w);
+		vop2_win_write(win, &win->regs->scl->scale_cbcr_x, val);
+		val = vop2_scale_factor(cbcr_ver_scl_mode, vscl_filter_mode,
+					cbcr_src_h, dst_h);
+		vop2_win_write(win, &win->regs->scl->scale_cbcr_y, val);
+
+		vop2_win_write(win, &win->regs->scl->vsd_cbcr_gt4, gt4);
+		vop2_win_write(win, &win->regs->scl->vsd_cbcr_gt2, gt2);
+		vop2_win_write(win, &win->regs->scl->cbcr_hor_scl_mode, cbcr_hor_scl_mode);
+		vop2_win_write(win, &win->regs->scl->cbcr_ver_scl_mode, cbcr_ver_scl_mode);
+		vop2_win_write(win, &win->regs->scl->cbcr_hscl_filter_mode, hscl_filter_mode);
+		vop2_win_write(win, &win->regs->scl->cbcr_vscl_filter_mode, vscl_filter_mode);
+	}
+}
+
+static int vop2_convert_csc_mode(int csc_mode)
+{
+	switch (csc_mode) {
+	case V4L2_COLORSPACE_SMPTE170M:
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+		return CSC_BT601L;
+	case V4L2_COLORSPACE_REC709:
+	case V4L2_COLORSPACE_SMPTE240M:
+	case V4L2_COLORSPACE_DEFAULT:
+		return CSC_BT709L;
+	case V4L2_COLORSPACE_JPEG:
+		return CSC_BT601F;
+	case V4L2_COLORSPACE_BT2020:
+		return CSC_BT2020;
+	default:
+		return CSC_BT709L;
+	}
+}
+
+/*
+ * colorspace path:
+ *      Input        Win csc                     Output
+ * 1. YUV(2020)  --> Y2R->2020To709->R2Y   --> YUV_OUTPUT(601/709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 2. YUV(2020)  --> bypasss               --> YUV_OUTPUT(2020)
+ *    RGB        --> 709To2020->R2Y       __/
+ *
+ * 3. YUV(2020)  --> Y2R->2020To709        --> RGB_OUTPUT(709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 4. YUV(601/709)-> Y2R->709To2020->R2Y   --> YUV_OUTPUT(2020)
+ *    RGB        --> 709To2020->R2Y       __/
+ *
+ * 5. YUV(601/709)-> bypass                --> YUV_OUTPUT(709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 6. YUV(601/709)-> bypass                --> YUV_OUTPUT(601)
+ *    RGB        --> R2Y(601)             __/
+ *
+ * 7. YUV        --> Y2R(709)              --> RGB_OUTPUT(709)
+ *    RGB        --> bypass               __/
+ *
+ * 8. RGB        --> 709To2020->R2Y        --> YUV_OUTPUT(2020)
+ *
+ * 9. RGB        --> R2Y(709)              --> YUV_OUTPUT(709)
+ *
+ * 10. RGB       --> R2Y(601)              --> YUV_OUTPUT(601)
+ *
+ * 11. RGB       --> bypass                --> RGB_OUTPUT(709)
+ */
+
+static void vop2_setup_csc_mode(struct vop2_video_port *vp,
+				struct vop2_win *win,
+				struct drm_plane_state *pstate)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);
+	int is_input_yuv = pstate->fb->format->is_yuv;
+	int is_output_yuv = is_yuv_output(vcstate->bus_format);
+	int input_csc = V4L2_COLORSPACE_DEFAULT;
+	int output_csc = vcstate->color_space;
+	bool r2y_en, y2r_en;
+	int csc_mode;
+
+	if (is_input_yuv && !is_output_yuv) {
+		y2r_en = 1;
+		r2y_en = 0;
+		csc_mode = vop2_convert_csc_mode(input_csc);
+	} else if (!is_input_yuv && is_output_yuv) {
+		y2r_en = 0;
+		r2y_en = 1;
+		csc_mode = vop2_convert_csc_mode(output_csc);
+	} else {
+		y2r_en = 0;
+		r2y_en = 0;
+		csc_mode = 0;
+	}
+
+	vop2_win_write(win, &win->regs->y2r_en, y2r_en);
+	vop2_win_write(win, &win->regs->r2y_en, r2y_en);
+	vop2_win_write(win, &win->regs->csc_mode, csc_mode);
+}
+
+static void vop2_crtc_enable_irq(struct vop2_video_port *vp, uint32_t irq)
+{
+	struct vop2 *vop2 = vp->vop2;
+
+	vop2_writel(vop2, vp->data->regs->irq_clear, irq << 16 | irq);
+	vop2_writel(vop2, vp->data->regs->irq_enable, irq << 16 | irq);
+}
+
+static void vop2_crtc_disable_irq(struct vop2_video_port *vp, uint32_t irq)
+{
+	struct vop2 *vop2 = vp->vop2;
+
+	vop2_writel(vop2, vp->data->regs->irq_enable, irq << 16);
+}
+
+static int vop2_core_clks_prepare_enable(struct vop2 *vop2)
+{
+	int ret;
+
+	ret = clk_prepare_enable(vop2->hclk);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to enable hclk - %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(vop2->aclk);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to enable aclk - %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+err:
+	clk_disable_unprepare(vop2->hclk);
+
+	return ret;
+}
+
+static void vop2_enable(struct vop2 *vop2)
+{
+	int ret;
+	uint32_t v;
+
+	ret = pm_runtime_get_sync(vop2->dev);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to get pm runtime: %d\n", ret);
+		return;
+	}
+
+	ret = vop2_core_clks_prepare_enable(vop2);
+	if (ret) {
+		pm_runtime_put_sync(vop2->dev);
+		return;
+	}
+
+	if (vop2->data->soc_id == 3566)
+		vop2_writel(vop2, RK3568_OTP_WIN_EN, 1);
+
+	memcpy(vop2->regsbak, vop2->regs, vop2->len);
+	vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
+
+	/*
+	 * Disable auto gating, this is a workaround to
+	 * avoid display image shift when a window enabled.
+	 */
+	v = vop2_readl(vop2, RK3568_SYS_AUTO_GATING_CTRL);
+	v &= ~RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN;
+	vop2_writel(vop2, RK3568_SYS_AUTO_GATING_CTRL, v);
+
+	vop2_writel(vop2, RK3568_SYS0_INT_CLR,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+	vop2_writel(vop2, RK3568_SYS0_INT_EN,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+	vop2_writel(vop2, RK3568_SYS1_INT_CLR,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+	vop2_writel(vop2, RK3568_SYS1_INT_EN,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+}
+
+static void vop2_disable(struct vop2 *vop2)
+{
+	pm_runtime_put_sync(vop2->dev);
+
+	clk_disable_unprepare(vop2->aclk);
+	clk_disable_unprepare(vop2->hclk);
+}
+
+static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
+				     struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	int ret;
+
+	vop2_lock(vop2);
+
+	drm_crtc_vblank_off(crtc);
+
+	/*
+	 * Vop standby will take effect at end of current frame,
+	 * if dsp hold valid irq happen, it means standby complete.
+	 *
+	 * we must wait standby complete when we want to disable aclk,
+	 * if not, memory bus maybe dead.
+	 */
+	reinit_completion(&vp->dsp_hold_completion);
+
+	vop2_crtc_enable_irq(vp, VP_INT_DSP_HOLD_VALID);
+	spin_lock(&vop2->reg_lock);
+
+	vop2_writel(vop2, vp->data->regs->dsp_ctrl, 1);
+
+	spin_unlock(&vop2->reg_lock);
+
+	ret = wait_for_completion_timeout(&vp->dsp_hold_completion, msecs_to_jiffies(50));
+	if (!ret)
+		drm_info(vop2->drm, "wait for vp%d dsp_hold timeout\n", vp->id);
+
+	vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID);
+
+	clk_disable_unprepare(vp->dclk);
+
+	vop2->enable_count--;
+
+	if (!vop2->enable_count)
+		vop2_disable(vop2);
+
+	vop2_unlock(vop2);
+
+	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 int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *astate)
+{
+	struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(astate, plane);
+	struct vop2_win *win = to_vop2_win(plane);
+	struct drm_framebuffer *fb = pstate->fb;
+	struct drm_crtc *crtc = pstate->crtc;
+	struct drm_crtc_state *cstate;
+	struct vop2_video_port *vp;
+	struct vop2 *vop2;
+	const struct vop2_data *vop2_data;
+	struct drm_rect *dest = &pstate->dst;
+	struct drm_rect *src = &pstate->src;
+	int min_scale = win->regs->scl ? FRAC_16_16(1, 8) : DRM_PLANE_HELPER_NO_SCALING;
+	int max_scale = win->regs->scl ? FRAC_16_16(8, 1) : DRM_PLANE_HELPER_NO_SCALING;
+	int format;
+	int ret;
+
+	if (!crtc)
+		return 0;
+
+	vp = to_vop2_video_port(crtc);
+	vop2 = vp->vop2;
+	vop2_data = vop2->data;
+
+	cstate = drm_atomic_get_existing_crtc_state(pstate->state, crtc);
+	if (WARN_ON(!cstate))
+		return -EINVAL;
+
+	ret = drm_atomic_helper_check_plane_state(pstate, cstate,
+						  min_scale, max_scale,
+						  true, true);
+	if (ret)
+		return ret;
+
+	if (!pstate->visible)
+		return 0;
+
+	format = vop2_convert_format(fb->format->format);
+	if (format < 0)
+		return format;
+
+	if (drm_rect_width(src) >> 16 < 4 || drm_rect_height(src) >> 16 < 4 ||
+	    drm_rect_width(dest) < 4 || drm_rect_width(dest) < 4) {
+		drm_err(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n",
+			  drm_rect_width(src) >> 16, drm_rect_height(src) >> 16,
+			  drm_rect_width(dest), drm_rect_height(dest));
+		pstate->visible = false;
+		return 0;
+	}
+
+	if (drm_rect_width(src) >> 16 > vop2_data->max_input.width ||
+	    drm_rect_height(src) >> 16 > vop2_data->max_input.height) {
+		drm_err(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n",
+			  drm_rect_width(src) >> 16,
+			  drm_rect_height(src) >> 16,
+			  vop2_data->max_input.width,
+			  vop2_data->max_input.height);
+		return -EINVAL;
+	}
+
+	/*
+	 * Src.x1 can be odd when do clip, but yuv plane start point
+	 * need align with 2 pixel.
+	 */
+	if (fb->format->is_yuv && ((pstate->src.x1 >> 16) % 2)) {
+		drm_err(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void vop2_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+	struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state, plane);
+	struct vop2_win *win = to_vop2_win(plane);
+	struct vop2 *vop2 = win->vop2;
+
+	drm_dbg(vop2->drm, "%s disable\n", win->data->name);
+
+	if (!old_pstate->crtc)
+		return;
+
+	spin_lock(&vop2->reg_lock);
+
+	vop2_win_disable(win);
+	vop2_win_write(win, &win->regs->yuv_clip, 0);
+
+	spin_unlock(&vop2->reg_lock);
+}
+
+/*
+ * The color key is 10 bit, so all format should
+ * convert to 10 bit here.
+ */
+static void vop2_plane_setup_color_key(struct drm_plane *plane, uint32_t color_key)
+{
+	struct drm_plane_state *pstate = plane->state;
+	struct drm_framebuffer *fb = pstate->fb;
+	struct vop2_win *win = to_vop2_win(plane);
+	uint32_t color_key_en = 0;
+	uint32_t r = 0;
+	uint32_t g = 0;
+	uint32_t b = 0;
+
+	if (!(color_key & VOP2_COLOR_KEY_MASK) || fb->format->is_yuv) {
+		vop2_win_write(win, &win->regs->color_key_en, 0);
+		return;
+	}
+
+	switch (fb->format->format) {
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		r = (color_key & 0xf800) >> 11;
+		g = (color_key & 0x7e0) >> 5;
+		b = (color_key & 0x1f);
+		r <<= 5;
+		g <<= 4;
+		b <<= 5;
+		color_key_en = 1;
+		break;
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		r = (color_key & 0xff0000) >> 16;
+		g = (color_key & 0xff00) >> 8;
+		b = (color_key & 0xff);
+		r <<= 2;
+		g <<= 2;
+		b <<= 2;
+		color_key_en = 1;
+		break;
+	}
+
+	vop2_win_write(win, &win->regs->color_key_en, color_key_en);
+	vop2_win_write(win, &win->regs->color_key, (r << 20) | (g << 10) | b);
+}
+
+static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+	struct drm_plane_state *pstate = plane->state;
+	struct drm_crtc *crtc = pstate->crtc;
+	struct vop2_win *win = to_vop2_win(plane);
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
+	struct vop2 *vop2 = win->vop2;
+	struct drm_framebuffer *fb = pstate->fb;
+	uint32_t bpp = fb->format->cpp[0] * 8;
+	uint32_t actual_w, actual_h, dsp_w, dsp_h;
+	uint32_t act_info, dsp_info;
+	uint32_t format;
+	uint32_t afbc_format;
+	uint32_t rb_swap;
+	uint32_t uv_swap;
+	struct drm_rect *src = &pstate->src;
+	struct drm_rect *dest = &pstate->dst;
+	uint32_t afbc_tile_num;
+	uint32_t afbc_half_block_en;
+	uint32_t transform_offset;
+	bool dither_up;
+	bool xmirror = pstate->rotation & DRM_MODE_REFLECT_X;
+	bool ymirror = pstate->rotation & DRM_MODE_REFLECT_Y;
+	bool rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270;
+	bool rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90;
+	struct rockchip_gem_object *rk_obj;
+	unsigned long offset;
+	bool afbc_en;
+	dma_addr_t yrgb_mst;
+	dma_addr_t uv_mst;
+
+	/*
+	 * can't update plane when vop2 is disabled.
+	 */
+	if (WARN_ON(!crtc))
+		return;
+
+	if (!pstate->visible) {
+		vop2_plane_atomic_disable(plane, state);
+		return;
+	}
+
+	afbc_en = rockchip_afbc(plane, fb->modifier);
+
+	offset = (src->x1 >> 16) * fb->format->cpp[0];
+
+	/*
+	 * AFBC HDR_PTR must set to the zero offset of the framebuffer.
+	 */
+	if (afbc_en)
+		offset = 0;
+	else if (pstate->rotation & DRM_MODE_REFLECT_Y)
+		offset += ((src->y2 >> 16) - 1) * fb->pitches[0];
+	else
+		offset += (src->y1 >> 16) * fb->pitches[0];
+
+	rk_obj = to_rockchip_obj(fb->obj[0]);
+
+	yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];
+	if (fb->format->is_yuv) {
+		int hsub = fb->format->hsub;
+		int vsub = fb->format->vsub;
+
+		offset = (src->x1 >> 16) * fb->format->cpp[1] / hsub;
+		offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
+
+		if ((pstate->rotation & DRM_MODE_REFLECT_Y) && !afbc_en)
+			offset += fb->pitches[1] * ((pstate->src_h >> 16) - 2)  / vsub;
+
+		rk_obj = to_rockchip_obj(fb->obj[0]);
+		uv_mst = rk_obj->dma_addr + offset + fb->offsets[1];
+	}
+
+	actual_w = drm_rect_width(src) >> 16;
+	actual_h = drm_rect_height(src) >> 16;
+	dsp_w = drm_rect_width(dest);
+
+	if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
+		drm_err(vop2->drm, "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",
+			  vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay);
+		dsp_w = adjusted_mode->hdisplay - dest->x1;
+		if (dsp_w < 4)
+			dsp_w = 4;
+		actual_w = dsp_w * actual_w / drm_rect_width(dest);
+	}
+
+	dsp_h = drm_rect_height(dest);
+
+	if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
+		drm_err(vop2->drm, "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
+			  vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
+		dsp_h = adjusted_mode->vdisplay - dest->y1;
+		if (dsp_h < 4)
+			dsp_h = 4;
+		actual_h = dsp_h * actual_h / drm_rect_height(dest);
+	}
+
+	/*
+	 * This is workaround solution for IC design:
+	 * esmart can't support scale down when actual_w % 16 == 1.
+	 */
+	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
+		if (actual_w > dsp_w && (actual_w & 0xf) == 1) {
+			drm_err(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n", vp->id, win->data->name, actual_w);
+			actual_w -= 1;
+		}
+	}
+
+	if (afbc_en && actual_w % 4) {
+		drm_err(vop2->drm, "vp%d %s actual_w[%d] should align as 4 pixel when enable afbc\n",
+			  vp->id, win->data->name, actual_w);
+		actual_w = ALIGN_DOWN(actual_w, 4);
+	}
+
+	act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
+	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
+
+	format = vop2_convert_format(fb->format->format);
+
+	spin_lock(&vop2->reg_lock);
+	drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n",
+		      vp->id, win->data->name, actual_w, actual_h, dsp_w, dsp_h,
+		      dest->x1, dest->y1,
+		      &fb->format->format,
+		      afbc_en ? "AFBC" : "", &yrgb_mst);
+
+	if (afbc_en) {
+		uint32_t stride;
+
+		/* the afbc superblock is 16 x 16 */
+		afbc_format = vop2_convert_afbc_format(fb->format->format);
+
+		/* Enable color transform for YTR */
+		if (fb->modifier & AFBC_FORMAT_MOD_YTR)
+			afbc_format |= (1 << 4);
+
+		afbc_tile_num = ALIGN(actual_w, 16) >> 4;
+
+		/*
+		 * AFBC pic_vir_width is count by pixel, this is different
+		 * with WIN_VIR_STRIDE.
+		 */
+		stride = (fb->pitches[0] << 3) / bpp;
+		if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270))
+			drm_err(vop2->drm, "vp%d %s stride[%d] must align as 64 pixel when enable xmirror/rotate_90/rotate_270[0x%x]\n",
+				  vp->id, win->data->name, stride, pstate->rotation);
+
+		rb_swap = vop2_afbc_rb_swap(fb->format->format);
+		uv_swap = vop2_afbc_uv_swap(fb->format->format);
+		/*
+		 * This is a workaround for crazy IC design, Cluster
+		 * and Esmart/Smart use different format configuration map:
+		 * YUV420_10BIT: 0x10 for Cluster, 0x14 for Esmart/Smart.
+		 *
+		 * This is one thing we can make the convert simple:
+		 * AFBCD decode all the YUV data to YUV444. So we just
+		 * set all the yuv 10 bit to YUV444_10.
+		 */
+		if (fb->format->is_yuv && (bpp == 10))
+			format = VOP2_CLUSTER_YUV444_10;
+
+		afbc_half_block_en = vop2_afbc_half_block_enable(pstate);
+		transform_offset = vop2_afbc_transform_offset(pstate, afbc_half_block_en);
+		if (vop2_cluster_window(win))
+			vop2_win_write(win, &win->regs->cluster->afbc_enable, 1);
+		vop2_win_write(win, &win->regs->afbc->format, afbc_format);
+		vop2_win_write(win, &win->regs->afbc->rb_swap, rb_swap);
+		vop2_win_write(win, &win->regs->afbc->uv_swap, uv_swap);
+		vop2_win_write(win, &win->regs->afbc->auto_gating_en, 0);
+		vop2_win_write(win, &win->regs->afbc->block_split_en, 0);
+		vop2_win_write(win, &win->regs->afbc->half_block_en, afbc_half_block_en);
+		vop2_win_write(win, &win->regs->afbc->hdr_ptr, yrgb_mst);
+		vop2_win_write(win, &win->regs->afbc->pic_size, act_info);
+		vop2_win_write(win, &win->regs->afbc->transform_offset, transform_offset);
+		vop2_win_write(win, &win->regs->afbc->pic_offset, ((src->x1 >> 16) | src->y1));
+		vop2_win_write(win, &win->regs->afbc->dsp_offset, (dest->x1 | (dest->y1 << 16)));
+		vop2_win_write(win, &win->regs->afbc->pic_vir_width, stride);
+		vop2_win_write(win, &win->regs->afbc->tile_num, afbc_tile_num);
+		vop2_win_write(win, &win->regs->afbc->xmirror, xmirror);
+		vop2_win_write(win, &win->regs->afbc->ymirror, ymirror);
+		vop2_win_write(win, &win->regs->afbc->rotate_270, rotate_270);
+		vop2_win_write(win, &win->regs->afbc->rotate_90, rotate_90);
+	} else {
+		if (win->regs->afbc)
+			vop2_win_write(win, &win->regs->afbc->enable, 0);
+		vop2_win_write(win, &win->regs->ymirror, ymirror);
+		vop2_win_write(win, &win->regs->xmirror, xmirror);
+		vop2_win_write(win, &win->regs->yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
+	}
+
+	if (rotate_90 || rotate_270) {
+		act_info = swahw32(act_info);
+		actual_w = drm_rect_height(src) >> 16;
+		actual_h = drm_rect_width(src) >> 16;
+	}
+
+	vop2_win_write(win, &win->regs->format, format);
+	vop2_win_write(win, &win->regs->yrgb_mst, yrgb_mst);
+
+	rb_swap = vop2_win_rb_swap(fb->format->format);
+	uv_swap = vop2_win_uv_swap(fb->format->format);
+	vop2_win_write(win, &win->regs->rb_swap, rb_swap);
+	vop2_win_write(win, &win->regs->uv_swap, uv_swap);
+
+	if (fb->format->is_yuv) {
+		vop2_win_write(win, &win->regs->uv_vir, DIV_ROUND_UP(fb->pitches[1], 4));
+		vop2_win_write(win, &win->regs->uv_mst, uv_mst);
+	}
+
+	vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format);
+	vop2_plane_setup_color_key(plane, 0);
+	vop2_win_write(win, &win->regs->act_info, act_info);
+	vop2_win_write(win, &win->regs->dsp_info, dsp_info);
+	vop2_win_write(win, &win->regs->dsp_st, dest->y1 << 16 | (dest->x1 & 0xffff));
+
+	vop2_setup_csc_mode(vp, win, pstate);
+
+	dither_up = vop2_win_dither_up(fb->format->format);
+	vop2_win_write(win, &win->regs->dither_up, dither_up);
+
+	vop2_win_write(win, &win->regs->enable, 1);
+
+	if (vop2_cluster_window(win)) {
+		int lb_mode = vop2_get_cluster_lb_mode(win, pstate);
+
+		vop2_win_write(win, &win->regs->cluster->lb_mode, lb_mode);
+		vop2_win_write(win, &win->regs->cluster->enable, 1);
+	}
+
+	spin_unlock(&vop2->reg_lock);
+}
+
+static const struct drm_plane_helper_funcs vop2_plane_helper_funcs = {
+	.atomic_check = vop2_plane_atomic_check,
+	.atomic_update = vop2_plane_atomic_update,
+	.atomic_disable = vop2_plane_atomic_disable,
+};
+
+static const struct drm_plane_funcs vop2_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.destroy = drm_plane_cleanup,
+	.reset = drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+	.format_mod_supported = rockchip_vop2_mod_supported,
+};
+
+static int vop2_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+
+	vop2_crtc_enable_irq(vp, VP_INT_FS_FIELD);
+
+	return 0;
+}
+
+static void vop2_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+
+	vop2_crtc_disable_irq(vp, VP_INT_FS_FIELD);
+}
+
+static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc,
+				 const struct drm_display_mode *mode,
+				 struct drm_display_mode *adj_mode)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+
+	drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE);
+
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		adj_mode->crtc_clock *= 2;
+
+	adj_mode->crtc_clock = DIV_ROUND_UP(clk_round_rate(vp->dclk,
+							   adj_mode->crtc_clock * 1000), 1000);
+
+	return true;
+}
+
+static void vop2_dither_setup(struct drm_crtc *crtc, uint32_t *dsp_ctrl)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+
+	switch (vcstate->bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
+		*dsp_ctrl |= RGB888_TO_RGB666;
+		break;
+	case MEDIA_BUS_FMT_YUV8_1X24:
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
+		break;
+	default:
+		break;
+	}
+
+	if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA)
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
+
+	*dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
+				DITHER_DOWN_ALLEGRO);
+}
+
+static void vop2_post_config(struct drm_crtc *crtc)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	uint16_t vtotal = mode->crtc_vtotal;
+	uint16_t hdisplay = mode->crtc_hdisplay;
+	uint16_t hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
+	uint16_t vdisplay = mode->crtc_vdisplay;
+	uint16_t vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
+	uint32_t left_margin = 100, right_margin = 100, top_margin = 100, bottom_margin = 100;
+	uint16_t hsize = hdisplay * (left_margin + right_margin) / 200;
+	uint16_t vsize = vdisplay * (top_margin + bottom_margin) / 200;
+	uint16_t hact_end, vact_end;
+	uint32_t val;
+
+	vsize = rounddown(vsize, 2);
+	hsize = rounddown(hsize, 2);
+	hact_st += hdisplay * (100 - left_margin) / 200;
+	hact_end = hact_st + hsize;
+	val = hact_st << 16;
+	val |= hact_end;
+	vop2_writel(vop2, vp->regs->hpost_st_end, val);
+	vact_st += vdisplay * (100 - top_margin) / 200;
+	vact_end = vact_st + vsize;
+	val = vact_st << 16;
+	val |= vact_end;
+	vop2_writel(vop2, vp->regs->vpost_st_end, val);
+	val = scl_cal_scale2(vdisplay, vsize) << 16;
+	val |= scl_cal_scale2(hdisplay, hsize);
+	vop2_writel(vop2, vp->regs->post_scl_factor, val);
+
+	val = 0;
+	if (hdisplay != hsize)
+		val |= RK3568_VP_POST_SCL_CTRL__HSCALEDOWN;
+	if (vdisplay != vsize)
+		val |= RK3568_VP_POST_SCL_CTRL__VSCALEDOWN;
+	vop2_writel(vop2, RK3568_VP0_POST_SCL_CTRL, val);
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+		uint16_t vact_st_f1 = vtotal + vact_st + 1;
+		uint16_t vact_end_f1 = vact_st_f1 + vsize;
+
+		val = vact_st_f1 << 16 | vact_end_f1;
+		vop2_writel(vop2, vp->regs->vpost_st_end_f1, val);
+	}
+
+	vop2_writel(vop2, vp->regs->dsp_background, 0);
+}
+
+static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id,
+				uint32_t polflags)
+{
+	struct vop2 *vop2 = vp->vop2;
+	uint32_t die, dip;
+
+	die = vop2_readl(vop2, RK3568_DSP_IF_EN);
+	dip = vop2_readl(vop2, RK3568_DSP_IF_POL);
+
+	switch (id) {
+	case RK3568_VOP2_EP_RGB:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_RGB_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_RGB |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_RGB_MUX, vp->id);
+		if (polflags & POLFLAG_DCLK_INV)
+			vop2_grf_writel(vop2, &vop2->data->grf_ctrl->grf_dclk_inv, 1);
+		else
+			vop2_grf_writel(vop2, &vop2->data->grf_ctrl->grf_dclk_inv, 0);
+		break;
+	case RK3568_VOP2_EP_HDMI:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_HDMI_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_HDMI |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_HDMI_MUX, vp->id);
+		break;
+	case RK3568_VOP2_EP_EDP:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_EDP_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_EDP |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_EDP_MUX, vp->id);
+		break;
+	case RK3568_VOP2_EP_MIPI0:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_MIPI0 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags);
+		break;
+	case RK3568_VOP2_EP_MIPI1:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_MIPI1 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags);
+		break;
+	case RK3568_VOP2_EP_LVDS0:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_LVDS0 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);
+		break;
+	case RK3568_VOP2_EP_LVDS1:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_LVDS1 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);
+		break;
+	default:
+		return;
+	};
+
+	dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD;
+
+	vop2_writel(vop2, RK3568_DSP_IF_EN, die);
+	vop2_writel(vop2, RK3568_DSP_IF_POL, dip);
+}
+
+static int us_to_vertical_line(struct drm_display_mode *mode, int us)
+{
+	return us * mode->clock / mode->htotal / 1000;
+}
+
+static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	const struct vop2_data *vop2_data = vop2->data;
+	const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+	struct drm_display_mode *mode = &crtc->state->mode;
+	uint16_t hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+	uint16_t hdisplay = mode->crtc_hdisplay;
+	uint16_t htotal = mode->crtc_htotal;
+	uint16_t hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
+	uint16_t hact_end = hact_st + hdisplay;
+	uint16_t vdisplay = mode->crtc_vdisplay;
+	uint16_t vtotal = mode->crtc_vtotal;
+	uint16_t vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+	uint16_t vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
+	uint16_t vact_end = vact_st + vdisplay;
+	uint8_t out_mode;
+	uint32_t dsp_ctrl = 0;
+	int act_end;
+	uint32_t val, polflags;
+	int ret;
+	struct drm_encoder *encoder;
+
+	drm_dbg(vop2->drm, "Update mode to %dx%d%s%d, type: %d for vp%d\n",
+		hdisplay, vdisplay, mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p",
+		drm_mode_vrefresh(mode), vcstate->output_type, vp->id);
+
+	vop2_lock(vop2);
+
+	ret = clk_prepare_enable(vp->dclk);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to enable dclk for video port%d - %d\n",
+			      vp->id, ret);
+		return;
+	}
+
+	if (!vop2->enable_count)
+		vop2_enable(vop2);
+
+	vop2->enable_count++;
+
+	vop2_crtc_enable_irq(vp, VP_INT_POST_BUF_EMPTY);
+
+	polflags = 0;
+	if (vcstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
+		polflags |= POLFLAG_DCLK_INV;
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		polflags |= BIT(HSYNC_POSITIVE);
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		polflags |= BIT(VSYNC_POSITIVE);
+
+	drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) {
+		struct device_node *node, *parent;
+
+		parent = of_get_parent(encoder->port);
+
+		for_each_endpoint_of_node(parent, node) {
+			struct device_node *crtc_port = of_graph_get_remote_port(node);
+			struct device_node *epn;
+			struct of_endpoint endpoint;
+
+			if (crtc->port != crtc_port) {
+				of_node_put(crtc_port);
+				continue;
+			}
+
+			of_node_put(crtc_port);
+
+			epn = of_graph_get_remote_endpoint(node);
+			of_graph_parse_endpoint(epn, &endpoint);
+			of_node_put(epn);
+
+			drm_dbg(vop2->drm, "vp%d is connected to %s, id %d\n",
+					   vp->id, encoder->name, endpoint.id);
+			rk3568_set_intf_mux(vp, endpoint.id, polflags);
+		}
+		of_node_put(parent);
+	}
+
+	if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
+	     !(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT))
+		out_mode = ROCKCHIP_OUT_MODE_P888;
+	else
+		out_mode = vcstate->output_mode;
+
+	dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__OUT_MODE, out_mode);
+
+	if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode))
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RB_SWAP;
+
+	if (is_yuv_output(vcstate->bus_format))
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y;
+
+	vop2_dither_setup(crtc, &dsp_ctrl);
+
+	vop2_writel(vop2, vp->regs->htotal_pw, (htotal << 16) | hsync_len);
+	val = hact_st << 16;
+	val |= hact_end;
+	vop2_writel(vop2, vp->regs->hact_st_end, val);
+
+	val = vact_st << 16;
+	val |= vact_end;
+	vop2_writel(vop2, vp->regs->vact_st_end, val);
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+		uint16_t vact_st_f1 = vtotal + vact_st + 1;
+		uint16_t vact_end_f1 = vact_st_f1 + vdisplay;
+
+		val = vact_st_f1 << 16 | vact_end_f1;
+		vop2_writel(vop2, vp->regs->vact_st_end_f1, val);
+
+		val = vtotal << 16 | (vtotal + vsync_len);
+		vop2_writel(vop2, vp->regs->vs_st_end_f1, val);
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_INTERLACE;
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_FILED_POL;
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__P2I_EN;
+		vtotal += vtotal + 1;
+		act_end = vact_end_f1;
+	} else {
+		act_end = vact_end;
+	}
+
+	vop2_writel(vop2, vp->data->regs->line_flag,
+		    (act_end - us_to_vertical_line(mode, 0)) << 16 | act_end);
+
+	vop2_writel(vop2, vp->regs->vtotal_pw, vtotal << 16 | vsync_len);
+
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV;
+
+	vop2_writel(vop2, vp->regs->mipi_ctrl, 0);
+
+	clk_set_rate(vp->dclk, mode->crtc_clock * 1000);
+
+	vop2_post_config(crtc);
+
+	vop2_cfg_done(vp);
+
+	vop2_writel(vop2, vp->regs->dsp_ctrl, dsp_ctrl);
+
+	drm_crtc_vblank_on(crtc);
+
+	vop2_unlock(vop2);
+}
+
+static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
+				  struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct drm_plane *plane;
+	int nplanes = 0;
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+
+	drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
+		nplanes++;
+
+	if (nplanes > vp->nlayers)
+		return -EINVAL;
+
+	return 0;
+}
+
+static bool is_opaque(uint16_t alpha)
+{
+	return (alpha >> 8) == 0xff;
+}
+
+static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config,
+			     struct vop2_alpha *alpha)
+{
+	int src_glb_alpha_en = is_opaque(alpha_config->src_glb_alpha_value) ? 0 : 1;
+	int dst_glb_alpha_en = is_opaque(alpha_config->dst_glb_alpha_value) ? 0 : 1;
+	int src_color_mode = alpha_config->src_premulti_en ? ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL;
+	int dst_color_mode = alpha_config->dst_premulti_en ? ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL;
+
+	alpha->src_color_ctrl.val = 0;
+	alpha->dst_color_ctrl.val = 0;
+	alpha->src_alpha_ctrl.val = 0;
+	alpha->dst_alpha_ctrl.val = 0;
+
+	if (!alpha_config->src_pixel_alpha_en)
+		alpha->src_color_ctrl.bits.blend_mode = ALPHA_GLOBAL;
+	else if (alpha_config->src_pixel_alpha_en && !src_glb_alpha_en)
+		alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX;
+	else
+		alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL;
+
+	alpha->src_color_ctrl.bits.alpha_en = 1;
+
+	if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_GLOBAL) {
+		alpha->src_color_ctrl.bits.color_mode = src_color_mode;
+		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL;
+	} else if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_PER_PIX) {
+		alpha->src_color_ctrl.bits.color_mode = src_color_mode;
+		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_ONE;
+	} else {
+		alpha->src_color_ctrl.bits.color_mode = ALPHA_SRC_PRE_MUL;
+		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL;
+	}
+	alpha->src_color_ctrl.bits.glb_alpha = alpha_config->src_glb_alpha_value >> 8;
+	alpha->src_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	alpha->src_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
+
+	alpha->dst_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	alpha->dst_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
+	alpha->dst_color_ctrl.bits.blend_mode = ALPHA_GLOBAL;
+	alpha->dst_color_ctrl.bits.glb_alpha = alpha_config->dst_glb_alpha_value >> 8;
+	alpha->dst_color_ctrl.bits.color_mode = dst_color_mode;
+	alpha->dst_color_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
+
+	alpha->src_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	alpha->src_alpha_ctrl.bits.blend_mode = alpha->src_color_ctrl.bits.blend_mode;
+	alpha->src_alpha_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
+	alpha->src_alpha_ctrl.bits.factor_mode = ALPHA_ONE;
+
+	alpha->dst_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	if (alpha_config->dst_pixel_alpha_en && !dst_glb_alpha_en)
+		alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX;
+	else
+		alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL;
+	alpha->dst_alpha_ctrl.bits.alpha_cal_mode = ALPHA_NO_SATURATION;
+	alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
+}
+
+static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, uint8_t port_id)
+{
+	struct vop2_video_port *vp;
+	int used_layer = 0;
+	int i;
+
+	for (i = 0; i < port_id; i++) {
+		vp = &vop2->vps[i];
+		used_layer += hweight32(vp->win_mask);
+	}
+
+	return used_layer;
+}
+
+static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win)
+{
+	uint32_t offset = (main_win->data->phys_id * 0x10);
+	struct vop2_alpha_config alpha_config;
+	struct vop2_alpha alpha;
+	struct drm_plane_state *top_win_pstate;
+	struct drm_plane_state *bottom_win_pstate;
+	bool src_pixel_alpha_en = false;
+	uint16_t src_glb_alpha_val, dst_glb_alpha_val;
+	bool premulti_en = false;
+	bool swap = false;
+
+	/* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */
+	top_win_pstate = NULL;
+	bottom_win_pstate = main_win->base.state;
+	src_glb_alpha_val = 0;
+	dst_glb_alpha_val = main_win->base.state->alpha;
+
+	if (!bottom_win_pstate->fb)
+		return;
+
+	alpha_config.src_premulti_en = premulti_en;
+	alpha_config.dst_premulti_en = false;
+	alpha_config.src_pixel_alpha_en = src_pixel_alpha_en;
+	alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
+	alpha_config.src_glb_alpha_value = src_glb_alpha_val;
+	alpha_config.dst_glb_alpha_value = dst_glb_alpha_val;
+	vop2_parse_alpha(&alpha_config, &alpha);
+
+	alpha.src_color_ctrl.bits.src_dst_swap = swap;
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset,
+		    alpha.src_color_ctrl.val);
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset,
+		    alpha.dst_color_ctrl.val);
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset,
+		    alpha.src_alpha_ctrl.val);
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset,
+		    alpha.dst_alpha_ctrl.val);
+}
+
+static void vop2_setup_alpha(struct vop2_video_port *vp)
+{
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_framebuffer *fb;
+	struct vop2_alpha_config alpha_config;
+	struct vop2_alpha alpha;
+	struct drm_plane *plane;
+	int pixel_alpha_en;
+	int premulti_en, gpremulti_en = 0;
+	int mixer_id;
+	uint32_t offset;
+	bool bottom_layer_alpha_en = false;
+	uint32_t dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE;
+
+	mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id);
+	alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
+
+	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+
+		if (plane->state->normalized_zpos == 0 &&
+		    !is_opaque(plane->state->alpha) &&
+		    !vop2_cluster_window(win)) {
+			/*
+			 * If bottom layer have global alpha effect [except cluster layer,
+			 * because cluster have deal with bottom layer global alpha value
+			 * at cluster mix], bottom layer mix need deal with global alpha.
+			 */
+			bottom_layer_alpha_en = true;
+			dst_global_alpha = plane->state->alpha;
+		}
+	}
+
+	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+		int zpos = plane->state->normalized_zpos;
+
+		if (plane->state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
+			premulti_en = 1;
+		else
+			premulti_en = 0;
+
+		plane = &win->base;
+		fb = plane->state->fb;
+
+		pixel_alpha_en = fb->format->has_alpha;
+
+		alpha_config.src_premulti_en = premulti_en;
+
+		if (bottom_layer_alpha_en && zpos == 1) {
+			gpremulti_en = premulti_en;
+			/* Cd = Cs + (1 - As) * Cd * Agd */
+			alpha_config.dst_premulti_en = false;
+			alpha_config.src_pixel_alpha_en = pixel_alpha_en;
+			alpha_config.src_glb_alpha_value = plane->state->alpha;
+			alpha_config.dst_glb_alpha_value = dst_global_alpha;
+		} else if (vop2_cluster_window(win)) {
+			/* Mix output data only have pixel alpha */
+			alpha_config.dst_premulti_en = true;
+			alpha_config.src_pixel_alpha_en = true;
+			alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+		} else {
+			/* Cd = Cs + (1 - As) * Cd */
+			alpha_config.dst_premulti_en = true;
+			alpha_config.src_pixel_alpha_en = pixel_alpha_en;
+			alpha_config.src_glb_alpha_value = plane->state->alpha;
+			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+		}
+
+		vop2_parse_alpha(&alpha_config, &alpha);
+
+		offset = (mixer_id + zpos - 1) * 0x10;
+		vop2_writel(vop2, RK3568_MIX0_SRC_COLOR_CTRL + offset,
+			    alpha.src_color_ctrl.val);
+		vop2_writel(vop2, RK3568_MIX0_DST_COLOR_CTRL + offset,
+			    alpha.dst_color_ctrl.val);
+		vop2_writel(vop2, RK3568_MIX0_SRC_ALPHA_CTRL + offset,
+			    alpha.src_alpha_ctrl.val);
+		vop2_writel(vop2, RK3568_MIX0_DST_ALPHA_CTRL + offset,
+			    alpha.dst_alpha_ctrl.val);
+	}
+
+	if (vp->id == 0) {
+		if (bottom_layer_alpha_en) {
+			/* Transfer pixel alpha to hdr mix */
+			alpha_config.src_premulti_en = gpremulti_en;
+			alpha_config.dst_premulti_en = true;
+			alpha_config.src_pixel_alpha_en = true;
+			alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+			vop2_parse_alpha(&alpha_config, &alpha);
+
+			vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL,
+				alpha.src_color_ctrl.val);
+			vop2_writel(vop2, RK3568_HDR0_DST_COLOR_CTRL,
+				alpha.dst_color_ctrl.val);
+			vop2_writel(vop2, RK3568_HDR0_SRC_ALPHA_CTRL,
+				alpha.src_alpha_ctrl.val);
+			vop2_writel(vop2, RK3568_HDR0_DST_ALPHA_CTRL,
+				alpha.dst_alpha_ctrl.val);
+		} else {
+			vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, 0);
+		}
+	}
+}
+
+#define NR_VPS		3
+#define NR_MIXERS	6
+
+static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
+{
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_plane *plane;
+	uint32_t layer_sel = 0;
+	uint32_t port_sel;
+	int nlayer, ofs;
+	struct drm_display_mode *adjusted_mode;
+	uint16_t hsync_len;
+	uint16_t hdisplay;
+	uint32_t bg_dly;
+	uint32_t pre_scan_dly;
+	int i;
+	struct vop2_video_port *vp0 = &vop2->vps[0];
+	struct vop2_video_port *vp1 = &vop2->vps[1];
+	struct vop2_video_port *vp2 = &vop2->vps[2];
+
+	adjusted_mode = &vp->crtc.state->adjusted_mode;
+	hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
+	hdisplay = adjusted_mode->crtc_hdisplay;
+
+	bg_dly = vp->data->pre_scan_max_dly[3];
+	vop2_writel(vop2, vp->regs->bg_mix_ctrl,
+			    FIELD_PREP(RK3568_VP_BG_MIX_CTRL__BG_DLY, bg_dly));
+
+	pre_scan_dly = ((bg_dly + (hdisplay >> 1) - 1) << 16) | hsync_len;
+	vop2_writel(vop2, vp->regs->pre_scan_htiming, pre_scan_dly);
+
+	vop2_writel(vop2, RK3568_OVL_CTRL, 0);
+	port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
+	port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT;
+
+	if (vp0->nlayers)
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX,
+				     vp0->nlayers - 1);
+	else
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, 8);
+
+	if (vp1->nlayers)
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX,
+				     (vp0->nlayers + vp1->nlayers - 1));
+	else
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8);
+
+	if (vp2->nlayers)
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX,
+			(vp2->nlayers + vp1->nlayers + vp0->nlayers - 1));
+	else
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8);
+
+	layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
+
+	ofs = 0;
+	for (i = 0; i < vp->id; i++)
+		ofs += vop2->vps[i].nlayers;
+
+	nlayer = 0;
+	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+
+		switch (win->data->phys_id) {
+		case ROCKCHIP_VOP2_CLUSTER0:
+			port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER0;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER0, vp->id);
+			break;
+		case ROCKCHIP_VOP2_CLUSTER1:
+			port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER1;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER1, vp->id);
+			break;
+		case ROCKCHIP_VOP2_ESMART0:
+			port_sel &= ~RK3568_OVL_PORT_SEL__ESMART0;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART0, vp->id);
+			break;
+		case ROCKCHIP_VOP2_ESMART1:
+			port_sel &= ~RK3568_OVL_PORT_SEL__ESMART1;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART1, vp->id);
+			break;
+		case ROCKCHIP_VOP2_SMART0:
+			port_sel &= ~RK3568_OVL_PORT_SEL__SMART0;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART0, vp->id);
+			break;
+		case ROCKCHIP_VOP2_SMART1:
+			port_sel &= ~RK3568_OVL_PORT_SEL__SMART1;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART1, vp->id);
+			break;
+		}
+
+		layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7);
+		layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, win->data->layer_sel_id);
+		nlayer++;
+	}
+
+	/* configure unused layers to 0x5 (reserved) */
+	for (; nlayer < 3; nlayer++) {
+		layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7);
+		layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 5);
+	}
+
+	vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
+	vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
+	vop2_writel(vop2, RK3568_OVL_CTRL, RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD);
+}
+
+static void vop2_setup_dly_for_windows(struct vop2 *vop2)
+{
+	struct vop2_win *win;
+	int i = 0;
+	uint32_t cdly = 0, sdly = 0;
+
+	for (i = 0; i < vop2->data->win_size; i++) {
+		uint32_t dly;
+
+		win = &vop2->win[i];
+		dly = win->delay;
+
+		switch (win->data->phys_id) {
+		case ROCKCHIP_VOP2_CLUSTER0:
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_0, dly);
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_1, dly);
+			break;
+		case ROCKCHIP_VOP2_CLUSTER1:
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_0, dly);
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_1, dly);
+			break;
+		case ROCKCHIP_VOP2_ESMART0:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART0, dly);
+			break;
+		case ROCKCHIP_VOP2_ESMART1:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART1, dly);
+			break;
+		case ROCKCHIP_VOP2_SMART0:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly);
+			break;
+		case ROCKCHIP_VOP2_SMART1:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly);
+			break;
+		}
+	}
+
+	vop2_writel(vop2, RK3568_CLUSTER_DLY_NUM, cdly);
+	vop2_writel(vop2, RK3568_SMART_DLY_NUM, sdly);
+}
+
+static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_plane *plane;
+
+	vp->win_mask = 0;
+
+	drm_atomic_crtc_for_each_plane(plane, crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+
+		win->delay = win->data->dly[VOP2_DLY_MODE_DEFAULT];
+
+		vp->win_mask |= BIT(win->data->phys_id);
+
+		if (vop2_cluster_window(win))
+			vop2_setup_cluster_alpha(vop2, win);
+	}
+
+	if (!vp->win_mask)
+		return;
+
+	vop2_setup_layer_mixer(vp);
+	vop2_setup_alpha(vp);
+	vop2_setup_dly_for_windows(vop2);
+}
+
+static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+
+	spin_lock(&vop2->reg_lock);
+
+	vop2_post_config(crtc);
+
+	spin_unlock(&vop2->reg_lock);
+
+	vop2_cfg_done(vp);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+
+	if (crtc->state->event) {
+		WARN_ON(drm_crtc_vblank_get(crtc));
+		vp->event = crtc->state->event;
+		crtc->state->event = NULL;
+	}
+
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = {
+	.mode_fixup = vop2_crtc_mode_fixup,
+	.atomic_check = vop2_crtc_atomic_check,
+	.atomic_begin = vop2_crtc_atomic_begin,
+	.atomic_flush = vop2_crtc_atomic_flush,
+	.atomic_enable = vop2_crtc_atomic_enable,
+	.atomic_disable = vop2_crtc_atomic_disable,
+};
+
+static void vop2_crtc_reset(struct drm_crtc *crtc)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+
+	if (crtc->state) {
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
+		kfree(vcstate);
+	}
+
+	vcstate = kzalloc(sizeof(*vcstate), GFP_KERNEL);
+	if (!vcstate)
+		return;
+
+	crtc->state = &vcstate->base;
+	crtc->state->crtc = crtc;
+}
+
+static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct rockchip_crtc_state *vcstate, *old_vcstate;
+
+	old_vcstate = to_rockchip_crtc_state(crtc->state);
+
+	vcstate = kmemdup(old_vcstate, sizeof(*old_vcstate), GFP_KERNEL);
+	if (!vcstate)
+		return NULL;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base);
+
+	return &vcstate->base;
+}
+
+static void vop2_crtc_destroy_state(struct drm_crtc *crtc,
+				    struct drm_crtc_state *state)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state);
+
+	__drm_atomic_helper_crtc_destroy_state(&vcstate->base);
+	kfree(vcstate);
+}
+
+static const struct drm_crtc_funcs vop2_crtc_funcs = {
+	.set_config = drm_atomic_helper_set_config,
+	.page_flip = drm_atomic_helper_page_flip,
+	.destroy = drm_crtc_cleanup,
+	.reset = vop2_crtc_reset,
+	.atomic_duplicate_state = vop2_crtc_duplicate_state,
+	.atomic_destroy_state = vop2_crtc_destroy_state,
+	.enable_vblank = vop2_crtc_enable_vblank,
+	.disable_vblank = vop2_crtc_disable_vblank,
+};
+
+static irqreturn_t vop2_isr(int irq, void *data)
+{
+	struct vop2 *vop2 = data;
+	const struct vop2_data *vop2_data = vop2->data;
+	uint32_t axi_irqs[VOP2_SYS_AXI_BUS_NUM];
+	int ret = IRQ_NONE;
+	int i;
+
+	/*
+	 * The irq is shared with the iommu. If the runtime-pm state of the
+	 * vop2-device is disabled the irq has to be targeted at the iommu.
+	 */
+	if (!pm_runtime_get_if_in_use(vop2->dev))
+		return IRQ_NONE;
+
+	for (i = 0; i < vop2_data->nr_vps; i++) {
+		struct vop2_video_port *vp = &vop2->vps[i];
+		struct drm_crtc *crtc = &vp->crtc;
+		uint32_t irqs;
+
+		irqs = vop2_readl(vop2, vp->data->regs->irq_status);
+		vop2_writel(vop2, vp->data->regs->irq_clear, irqs << 16 | irqs);
+
+		if (irqs & VP_INT_DSP_HOLD_VALID) {
+			complete(&vp->dsp_hold_completion);
+			ret = IRQ_HANDLED;
+		}
+
+		if (irqs & VP_INT_FS_FIELD) {
+			unsigned long flags;
+
+			drm_crtc_handle_vblank(crtc);
+			spin_lock_irqsave(&crtc->dev->event_lock, flags);
+			if (vp->event) {
+				uint32_t val = vop2_readl(vop2, RK3568_REG_CFG_DONE);
+				if (!(val & BIT(vp->id))) {
+					drm_crtc_send_vblank_event(crtc, vp->event);
+					vp->event = NULL;
+					drm_crtc_vblank_put(crtc);
+				}
+			}
+			spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
+			ret = IRQ_HANDLED;
+		}
+
+		if (irqs & VP_INT_POST_BUF_EMPTY) {
+			drm_err_ratelimited(vop2->drm,
+					    "POST_BUF_EMPTY irq err at vp%d\n",
+					    vp->id);
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	axi_irqs[0] = vop2_readl(vop2, RK3568_SYS0_INT_STATUS);
+	vop2_writel(vop2, RK3568_SYS0_INT_CLR, axi_irqs[0] << 16 | axi_irqs[0]);
+	axi_irqs[1] = vop2_readl(vop2, RK3568_SYS1_INT_STATUS);
+	vop2_writel(vop2, RK3568_SYS1_INT_CLR, axi_irqs[1] << 16 | axi_irqs[1]);
+
+	for (i = 0; i < ARRAY_SIZE(axi_irqs); i++) {
+		if (axi_irqs[i] & VOP2_INT_BUS_ERRPR) {
+			drm_err_ratelimited(vop2->drm, "BUS_ERROR irq err\n");
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	pm_runtime_put(vop2->dev);
+
+	return ret;
+}
+
+static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned long possible_crtcs)
+{
+	const struct vop2_win_data *win_data = win->data;
+	unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) | BIT(DRM_MODE_BLEND_PREMULTI) |
+				  BIT(DRM_MODE_BLEND_COVERAGE);
+	int ret;
+
+	ret = drm_universal_plane_init(vop2->drm, &win->base, possible_crtcs,
+				       &vop2_plane_funcs, win_data->formats, win_data->nformats,
+				       win_data->format_modifiers, win->type, win_data->name);
+	if (ret) {
+		drm_err(vop2->drm, "failed to initialize plane %d\n", ret);
+		return ret;
+	}
+
+	drm_plane_helper_add(&win->base, &vop2_plane_helper_funcs);
+
+	if (win->data->supported_rotations)
+		drm_plane_create_rotation_property(&win->base, DRM_MODE_ROTATE_0,
+						   DRM_MODE_ROTATE_0 |
+						   win->data->supported_rotations);
+	drm_plane_create_alpha_property(&win->base);
+	drm_plane_create_blend_mode_property(&win->base, blend_caps);
+	drm_plane_create_zpos_property(&win->base, win->win_id, 0,
+				       vop2->registered_num_wins - 1);
+
+	return 0;
+}
+
+static struct vop2_video_port *get_activated_vp(struct vop2 *vop2, int n)
+{
+	int i, id = 0;
+
+	for (i = 0; i < vop2->data->nr_vps; i++) {
+		struct vop2_video_port *vp = &vop2->vps[i];
+
+		if (!vp->crtc.port)
+			continue;
+
+		if (n == id)
+			return vp;
+		id++;
+	}
+
+	return NULL;
+}
+
+static int vop2_create_crtc(struct vop2 *vop2)
+{
+	const struct vop2_data *vop2_data = vop2->data;
+	struct drm_device *drm = vop2->drm;
+	struct device *dev = vop2->dev;
+	struct drm_plane *plane;
+	struct device_node *port;
+	struct vop2_video_port *vp;
+	uint32_t possible_crtcs;
+	int i, nvp, nvps = 0;
+	int ret;
+
+	for (i = 0; i < vop2_data->nr_vps; i++) {
+		const struct vop2_video_port_data *vp_data;
+		struct device_node *np;
+		char dclk_name[9];
+
+		vp_data = &vop2_data->vp[i];
+		vp = &vop2->vps[i];
+		vp->vop2 = vop2;
+		vp->id = vp_data->id;
+		vp->regs = vp_data->regs;
+		vp->data = vp_data;
+
+		snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id);
+		vp->dclk = devm_clk_get(vop2->dev, dclk_name);
+		if (IS_ERR(vp->dclk)) {
+			drm_err(vop2->drm, "failed to get %s\n", dclk_name);
+			return PTR_ERR(vp->dclk);
+		}
+
+		np = of_graph_get_remote_node(dev->of_node, i, -1);
+		if (!np) {
+			printk("%s: No remote for vp%d\n", __func__, i);
+			continue;
+		}
+		of_node_put(np);
+
+		port = of_graph_get_port_by_id(dev->of_node, i);
+		if (!port) {
+			drm_err(vop2->drm, "no port node found for video_port%d\n", i);
+			return -ENOENT;
+		}
+
+		vp->crtc.port = port;
+		nvps++;
+	}
+
+	nvp = 0;
+	for (i = 0; i < vop2->registered_num_wins; i++) {
+		struct vop2_win *win = &vop2->win[i];
+
+		if (win->type == DRM_PLANE_TYPE_PRIMARY) {
+			vp = get_activated_vp(vop2, nvp);
+
+			if (vp) {
+				possible_crtcs = BIT(nvp);
+				vp->primary_plane = win;
+
+				nvp++;
+			} else {
+				/* change the unused primary window to overlay window */
+				win->type = DRM_PLANE_TYPE_OVERLAY;
+			}
+		}
+
+		if (win->type == DRM_PLANE_TYPE_OVERLAY)
+			possible_crtcs = (1 << vop2_data->nr_vps) - 1;
+
+		ret = vop2_plane_init(vop2, win, possible_crtcs);
+
+		if (ret) {
+			drm_err(vop2->drm, "failed to init plane %s: %d\n", win->data->name, ret);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < vop2_data->nr_vps; i++) {
+		vp = &vop2->vps[i];
+
+		if (!vp->crtc.port)
+			continue;
+
+		plane = &vp->primary_plane->base;
+
+		ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL, &vop2_crtc_funcs,
+						"video_port%d", vp->id);
+		if (ret) {
+			drm_err(vop2->drm, "crtc init for video_port%d failed\n", i);
+			return ret;
+		}
+
+		drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);
+
+		init_completion(&vp->dsp_hold_completion);
+	}
+
+	for (i = 0; i < vop2->data->nr_vps; i++) {
+		struct vop2_video_port *vp = &vop2->vps[i];
+		if (vp->crtc.port)
+			vp->nlayers = NR_MIXERS / nvps;
+	}
+
+	return 0;
+}
+
+static void vop2_destroy_crtc(struct drm_crtc *crtc)
+{
+	of_node_put(crtc->port);
+
+	/*
+	 * Destroy CRTC after vop2_plane_destroy() since vop2_disable_plane()
+	 * references the CRTC.
+	 */
+	drm_crtc_cleanup(crtc);
+}
+
+static int vop2_win_init(struct vop2 *vop2)
+{
+	const struct vop2_data *vop2_data = vop2->data;
+	struct vop2_win *win;
+	unsigned int i;
+
+	for (i = 0; i < vop2_data->win_size; i++) {
+		const struct vop2_win_data *win_data = &vop2_data->win[i];
+
+		win = &vop2->win[i];
+		win->data = win_data;
+		win->type = win_data->type;
+		win->regs = win_data->regs;
+		win->offset = win_data->base;
+		win->win_id = i;
+		win->vop2 = vop2;
+	}
+
+	vop2->registered_num_wins = vop2_data->win_size;
+
+	return 0;
+}
+
+static int vop2_bind(struct device *dev, struct device *master, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct vop2_data *vop2_data;
+	struct drm_device *drm = data;
+	struct vop2 *vop2;
+	struct resource *res;
+	size_t alloc_size;
+	int ret;
+
+	vop2_data = of_device_get_match_data(dev);
+	if (!vop2_data)
+		return -ENODEV;
+
+	/* Allocate vop2 struct and its vop2_win array */
+	alloc_size = sizeof(*vop2) + sizeof(*vop2->win) * vop2_data->win_size;
+	vop2 = devm_kzalloc(dev, alloc_size, GFP_KERNEL);
+	if (!vop2)
+		return -ENOMEM;
+
+	vop2->dev = dev;
+	vop2->data = vop2_data;
+	vop2->drm = drm;
+
+	dev_set_drvdata(dev, vop2);
+
+	ret = vop2_win_init(vop2);
+	if (ret)
+		return ret;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	if (!res) {
+		drm_err(vop2->drm, "failed to get vop2 register byname\n");
+		return -EINVAL;
+	}
+	vop2->regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(vop2->regs))
+		return PTR_ERR(vop2->regs);
+	vop2->len = resource_size(res);
+
+	vop2->regsbak = devm_kzalloc(dev, vop2->len, GFP_KERNEL);
+	if (!vop2->regsbak)
+		return -ENOMEM;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gamma_lut");
+	if (res) {
+		vop2->lut_regs = devm_ioremap_resource(dev, res);
+		if (IS_ERR(vop2->lut_regs))
+			return PTR_ERR(vop2->lut_regs);
+	}
+
+	vop2->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
+
+	vop2->hclk = devm_clk_get(vop2->dev, "hclk_vop");
+	if (IS_ERR(vop2->hclk)) {
+		drm_err(vop2->drm, "failed to get hclk source\n");
+		return PTR_ERR(vop2->hclk);
+	}
+
+	vop2->aclk = devm_clk_get(vop2->dev, "aclk_vop");
+	if (IS_ERR(vop2->aclk)) {
+		drm_err(vop2->drm, "failed to get aclk source\n");
+		return PTR_ERR(vop2->aclk);
+	}
+
+	vop2->irq = platform_get_irq(pdev, 0);
+	if (vop2->irq < 0) {
+		drm_err(vop2->drm, "cannot find irq for vop2\n");
+		return vop2->irq;
+	}
+
+	spin_lock_init(&vop2->reg_lock);
+	mutex_init(&vop2->vop2_lock);
+
+	ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2);
+	if (ret)
+		return ret;
+
+	ret = rockchip_drm_dma_attach_device(vop2->drm, vop2->dev);
+	if (ret) {
+		drm_err(vop2->drm, "failed to attach dma mapping, %d\n", ret);
+		return ret;
+	}
+
+	ret = vop2_create_crtc(vop2);
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+}
+
+static void vop2_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct vop2 *vop2 = dev_get_drvdata(dev);
+	struct drm_device *drm = vop2->drm;
+	struct list_head *plane_list = &drm->mode_config.plane_list;
+	struct list_head *crtc_list = &drm->mode_config.crtc_list;
+	struct drm_crtc *crtc, *tmpc;
+	struct drm_plane *plane, *tmpp;
+
+	rockchip_drm_dma_detach_device(vop2->drm, vop2->dev);
+
+	pm_runtime_disable(dev);
+
+	list_for_each_entry_safe(plane, tmpp, plane_list, head)
+		drm_plane_cleanup(plane);
+
+	list_for_each_entry_safe(crtc, tmpc, crtc_list, head)
+		vop2_destroy_crtc(crtc);
+}
+
+const struct component_ops vop2_component_ops = {
+	.bind = vop2_bind,
+	.unbind = vop2_unbind,
+};
+EXPORT_SYMBOL_GPL(vop2_component_ops);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
new file mode 100644
index 0000000000000..b18871a5d85a7
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
@@ -0,0 +1,625 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:Mark Yao <mark.yao@rock-chips.com>
+ */
+
+#ifndef _ROCKCHIP_DRM_VOP2_H
+#define _ROCKCHIP_DRM_VOP2_H
+
+#include "rockchip_drm_vop.h"
+
+#include <drm/drm_modes.h>
+
+#define VOP_FEATURE_OUTPUT_10BIT        BIT(0)
+
+#define WIN_FEATURE_AFBDC		BIT(0)
+#define WIN_FEATURE_CLUSTER		BIT(1)
+
+/*
+ *  the delay number of a window in different mode.
+ */
+enum win_dly_mode {
+	VOP2_DLY_MODE_DEFAULT,   /**< default mode */
+	VOP2_DLY_MODE_HISO_S,    /** HDR in SDR out mode, as a SDR window */
+	VOP2_DLY_MODE_HIHO_H,    /** HDR in HDR out mode, as a HDR window */
+	VOP2_DLY_MODE_MAX,
+};
+
+struct vop_rect {
+	int width;
+	int height;
+};
+
+struct vop_grf_ctrl {
+	struct vop_reg grf_dclk_inv;
+	struct vop_reg grf_bt1120_clk_inv;
+	struct vop_reg grf_bt656_clk_inv;
+};
+
+struct vop2_afbc {
+	struct vop_reg enable;
+	struct vop_reg format;
+	struct vop_reg rb_swap;
+	struct vop_reg uv_swap;
+	struct vop_reg auto_gating_en;
+	struct vop_reg block_split_en;
+	struct vop_reg pic_vir_width;
+	struct vop_reg tile_num;
+	struct vop_reg pic_offset;
+	struct vop_reg pic_size;
+	struct vop_reg dsp_offset;
+	struct vop_reg transform_offset;
+	struct vop_reg hdr_ptr;
+	struct vop_reg half_block_en;
+	struct vop_reg xmirror;
+	struct vop_reg ymirror;
+	struct vop_reg rotate_270;
+	struct vop_reg rotate_90;
+};
+
+enum vop2_scale_up_mode {
+	VOP2_SCALE_UP_NRST_NBOR,
+	VOP2_SCALE_UP_BIL,
+	VOP2_SCALE_UP_BIC,
+};
+
+enum vop2_scale_down_mode {
+	VOP2_SCALE_DOWN_NRST_NBOR,
+	VOP2_SCALE_DOWN_BIL,
+	VOP2_SCALE_DOWN_AVG,
+};
+
+struct vop2_cluster_regs {
+	struct vop_reg enable;
+	struct vop_reg afbc_enable;
+	struct vop_reg lb_mode;
+};
+
+struct vop2_scl_regs {
+	struct vop_reg scale_yrgb_x;
+	struct vop_reg scale_yrgb_y;
+	struct vop_reg scale_cbcr_x;
+	struct vop_reg scale_cbcr_y;
+	struct vop_reg yrgb_hor_scl_mode;
+	struct vop_reg yrgb_hscl_filter_mode;
+	struct vop_reg yrgb_ver_scl_mode;
+	struct vop_reg yrgb_vscl_filter_mode;
+	struct vop_reg cbcr_ver_scl_mode;
+	struct vop_reg cbcr_hscl_filter_mode;
+	struct vop_reg cbcr_hor_scl_mode;
+	struct vop_reg cbcr_vscl_filter_mode;
+	struct vop_reg vsd_cbcr_gt2;
+	struct vop_reg vsd_cbcr_gt4;
+	struct vop_reg vsd_yrgb_gt2;
+	struct vop_reg vsd_yrgb_gt4;
+	struct vop_reg bic_coe_sel;
+};
+
+struct vop2_win_regs {
+	const struct vop2_scl_regs *scl;
+	const struct vop2_cluster_regs *cluster;
+	const struct vop2_afbc *afbc;
+
+	struct vop_reg gate;
+	struct vop_reg enable;
+	struct vop_reg format;
+	struct vop_reg csc_mode;
+	struct vop_reg xmirror;
+	struct vop_reg ymirror;
+	struct vop_reg rb_swap;
+	struct vop_reg uv_swap;
+	struct vop_reg act_info;
+	struct vop_reg dsp_info;
+	struct vop_reg dsp_st;
+	struct vop_reg yrgb_mst;
+	struct vop_reg uv_mst;
+	struct vop_reg yrgb_vir;
+	struct vop_reg uv_vir;
+	struct vop_reg yuv_clip;
+	struct vop_reg lb_mode;
+	struct vop_reg y2r_en;
+	struct vop_reg r2y_en;
+	struct vop_reg channel;
+	struct vop_reg dst_alpha_ctl;
+	struct vop_reg src_alpha_ctl;
+	struct vop_reg alpha_mode;
+	struct vop_reg alpha_en;
+	struct vop_reg global_alpha_val;
+	struct vop_reg color_key;
+	struct vop_reg color_key_en;
+	struct vop_reg dither_up;
+};
+
+struct vop2_video_port_regs {
+	int dsp_background;
+	int pre_scan_htiming;
+	int htotal_pw;
+	int hact_st_end;
+	int vtotal_pw;
+	int vact_st_end;
+	int vact_st_end_f1;
+	int vs_st_end_f1;
+	int hpost_st_end;
+	int vpost_st_end;
+	int vpost_st_end_f1;
+	int post_scl_factor;
+	int dsp_ctrl;
+	int mipi_ctrl;
+	int bg_mix_ctrl;
+	int hdr2sdr_eetf_oetf_y0_offset;
+	int hdr2sdr_sat_y0_offset;
+	int sdr2hdr_eotf_oetf_y0_offset;
+	int sdr2hdr_oetf_dx_pow1_offset;
+	int sdr2hdr_oetf_xn1_offset;
+	int irq_enable;
+	int irq_status;
+	int irq_clear;
+	int line_flag;
+};
+
+struct vop2_wb_regs {
+	struct vop_reg enable;
+	struct vop_reg format;
+	struct vop_reg dither_en;
+	struct vop_reg r2y_en;
+	struct vop_reg yrgb_mst;
+	struct vop_reg uv_mst;
+	struct vop_reg vp_id;
+	struct vop_reg fifo_throd;
+	struct vop_reg scale_x_factor;
+	struct vop_reg scale_x_en;
+	struct vop_reg scale_y_en;
+	struct vop_reg axi_yrgb_id;
+	struct vop_reg axi_uv_id;
+};
+
+struct vop2_win_data {
+	const char *name;
+	uint8_t phys_id;
+
+	uint32_t base;
+	enum drm_plane_type type;
+
+	uint32_t nformats;
+	const uint32_t *formats;
+	const uint64_t *format_modifiers;
+	const unsigned int supported_rotations;
+
+	const struct vop2_win_regs *regs;
+
+	/*
+	 * vertical/horizontal scale up/down filter mode
+	 */
+	const u8 hsu_filter_mode;
+	const u8 hsd_filter_mode;
+	const u8 vsu_filter_mode;
+	const u8 vsd_filter_mode;
+	/**
+	 * @layer_sel_id: defined by register OVERLAY_LAYER_SEL of VOP2
+	 */
+	int layer_sel_id;
+	uint64_t feature;
+
+	unsigned int max_upscale_factor;
+	unsigned int max_downscale_factor;
+	const uint8_t dly[VOP2_DLY_MODE_MAX];
+};
+
+struct vop2_wb_data {
+	uint32_t nformats;
+	const uint32_t *formats;
+	struct vop_rect max_output;
+	const struct vop2_wb_regs *regs;
+};
+
+struct vop2_video_port_data {
+	char id;
+	uint32_t feature;
+	uint16_t gamma_lut_len;
+	uint16_t cubic_lut_len;
+	struct vop_rect max_output;
+	const u8 pre_scan_max_dly[4];
+	const struct vop2_video_port_regs *regs;
+};
+
+/**
+ * VOP2 data struct
+ *
+ * @version: VOP IP version
+ * @win_size: hardware win number
+ */
+struct vop2_data {
+	uint8_t nr_vps;
+	uint8_t nr_mixers;
+	uint8_t nr_layers;
+	uint8_t nr_gammas;
+	const struct vop2_ctrl *ctrl;
+	const struct vop2_win_data *win;
+	const struct vop2_video_port_data *vp;
+	const struct vop_csc_table *csc_table;
+	const struct vop_grf_ctrl *grf_ctrl;
+	struct vop_rect max_input;
+	struct vop_rect max_output;
+
+	unsigned int win_size;
+	unsigned int soc_id;
+};
+
+/* interrupt define */
+#define FS_NEW_INTR			BIT(4)
+#define ADDR_SAME_INTR			BIT(5)
+#define LINE_FLAG1_INTR			BIT(6)
+#define WIN0_EMPTY_INTR			BIT(7)
+#define WIN1_EMPTY_INTR			BIT(8)
+#define WIN2_EMPTY_INTR			BIT(9)
+#define WIN3_EMPTY_INTR			BIT(10)
+#define HWC_EMPTY_INTR			BIT(11)
+#define POST_BUF_EMPTY_INTR		BIT(12)
+#define PWM_GEN_INTR			BIT(13)
+#define DMA_FINISH_INTR			BIT(14)
+#define FS_FIELD_INTR			BIT(15)
+#define FE_INTR				BIT(16)
+#define WB_UV_FIFO_FULL_INTR		BIT(17)
+#define WB_YRGB_FIFO_FULL_INTR		BIT(18)
+#define WB_COMPLETE_INTR		BIT(19)
+
+/*
+ * display output interface supported by rockchip lcdc
+ */
+#define ROCKCHIP_OUT_MODE_P888		0
+#define ROCKCHIP_OUT_MODE_BT1120	0
+#define ROCKCHIP_OUT_MODE_P666		1
+#define ROCKCHIP_OUT_MODE_P565		2
+#define ROCKCHIP_OUT_MODE_BT656		5
+#define ROCKCHIP_OUT_MODE_S888		8
+#define ROCKCHIP_OUT_MODE_S888_DUMMY	12
+#define ROCKCHIP_OUT_MODE_YUV420	14
+/* for use special outface */
+#define ROCKCHIP_OUT_MODE_AAAA		15
+
+enum vop_csc_format {
+	CSC_BT601L,
+	CSC_BT709L,
+	CSC_BT601F,
+	CSC_BT2020,
+};
+
+enum src_factor_mode {
+	SRC_FAC_ALPHA_ZERO,
+	SRC_FAC_ALPHA_ONE,
+	SRC_FAC_ALPHA_DST,
+	SRC_FAC_ALPHA_DST_INVERSE,
+	SRC_FAC_ALPHA_SRC,
+	SRC_FAC_ALPHA_SRC_GLOBAL,
+};
+
+enum dst_factor_mode {
+	DST_FAC_ALPHA_ZERO,
+	DST_FAC_ALPHA_ONE,
+	DST_FAC_ALPHA_SRC,
+	DST_FAC_ALPHA_SRC_INVERSE,
+	DST_FAC_ALPHA_DST,
+	DST_FAC_ALPHA_DST_GLOBAL,
+};
+
+#define RK3568_GRF_VO_CON1			0x0364
+/* System registers definition */
+#define RK3568_REG_CFG_DONE			0x000
+#define RK3568_VERSION_INFO			0x004
+#define RK3568_SYS_AUTO_GATING_CTRL		0x008
+#define RK3568_SYS_AXI_LUT_CTRL			0x024
+#define RK3568_DSP_IF_EN			0x028
+#define RK3568_DSP_IF_CTRL			0x02c
+#define RK3568_DSP_IF_POL			0x030
+#define RK3568_WB_CTRL				0x40
+#define RK3568_WB_XSCAL_FACTOR			0x44
+#define RK3568_WB_YRGB_MST			0x48
+#define RK3568_WB_CBR_MST			0x4C
+#define RK3568_OTP_WIN_EN			0x050
+#define RK3568_LUT_PORT_SEL			0x058
+#define RK3568_SYS_STATUS0			0x060
+#define RK3568_VP0_LINE_FLAG			0x70
+#define RK3568_VP1_LINE_FLAG			0x74
+#define RK3568_VP2_LINE_FLAG			0x78
+#define RK3568_SYS0_INT_EN			0x80
+#define RK3568_SYS0_INT_CLR			0x84
+#define RK3568_SYS0_INT_STATUS			0x88
+#define RK3568_SYS1_INT_EN			0x90
+#define RK3568_SYS1_INT_CLR			0x94
+#define RK3568_SYS1_INT_STATUS			0x98
+#define RK3568_VP0_INT_EN			0xA0
+#define RK3568_VP0_INT_CLR			0xA4
+#define RK3568_VP0_INT_STATUS			0xA8
+#define RK3568_VP0_INT_RAW_STATUS		0xAC
+#define RK3568_VP1_INT_EN			0xB0
+#define RK3568_VP1_INT_CLR			0xB4
+#define RK3568_VP1_INT_STATUS			0xB8
+#define RK3568_VP1_INT_RAW_STATUS		0xBC
+#define RK3568_VP2_INT_EN			0xC0
+#define RK3568_VP2_INT_CLR			0xC4
+#define RK3568_VP2_INT_STATUS			0xC8
+#define RK3568_VP2_INT_RAW_STATUS		0xCC
+
+/* Video Port registers definition */
+#define RK3568_VP0_DSP_CTRL			0xC00
+#define RK3568_VP0_MIPI_CTRL			0xC04
+#define RK3568_VP0_COLOR_BAR_CTRL		0xC08
+#define RK3568_VP0_3D_LUT_CTRL			0xC10
+#define RK3568_VP0_3D_LUT_MST			0xC20
+#define RK3568_VP0_DSP_BG			0xC2C
+#define RK3568_VP0_PRE_SCAN_HTIMING		0xC30
+#define RK3568_VP0_POST_DSP_HACT_INFO		0xC34
+#define RK3568_VP0_POST_DSP_VACT_INFO		0xC38
+#define RK3568_VP0_POST_SCL_FACTOR_YRGB		0xC3C
+#define RK3568_VP0_POST_SCL_CTRL		0xC40
+#define RK3568_VP0_POST_DSP_VACT_INFO_F1	0xC44
+#define RK3568_VP0_DSP_HTOTAL_HS_END		0xC48
+#define RK3568_VP0_DSP_HACT_ST_END		0xC4C
+#define RK3568_VP0_DSP_VTOTAL_VS_END		0xC50
+#define RK3568_VP0_DSP_VACT_ST_END		0xC54
+#define RK3568_VP0_DSP_VS_ST_END_F1		0xC58
+#define RK3568_VP0_DSP_VACT_ST_END_F1		0xC5C
+#define RK3568_VP0_BCSH_CTRL			0xC60
+#define RK3568_VP0_BCSH_BCS			0xC64
+#define RK3568_VP0_BCSH_H			0xC68
+#define RK3568_VP0_BCSH_COLOR_BAR		0xC6C
+
+#define RK3568_VP1_DSP_CTRL			0xD00
+#define RK3568_VP1_MIPI_CTRL			0xD04
+#define RK3568_VP1_COLOR_BAR_CTRL		0xD08
+#define RK3568_VP1_DSP_BG			0xD2C
+#define RK3568_VP1_PRE_SCAN_HTIMING		0xD30
+#define RK3568_VP1_POST_DSP_HACT_INFO		0xD34
+#define RK3568_VP1_POST_DSP_VACT_INFO		0xD38
+#define RK3568_VP1_POST_SCL_FACTOR_YRGB		0xD3C
+#define RK3568_VP1_POST_SCL_CTRL		0xD40
+#define RK3568_VP1_DSP_HACT_INFO		0xD34
+#define RK3568_VP1_DSP_VACT_INFO		0xD38
+#define RK3568_VP1_POST_DSP_VACT_INFO_F1	0xD44
+#define RK3568_VP1_DSP_HTOTAL_HS_END		0xD48
+#define RK3568_VP1_DSP_HACT_ST_END		0xD4C
+#define RK3568_VP1_DSP_VTOTAL_VS_END		0xD50
+#define RK3568_VP1_DSP_VACT_ST_END		0xD54
+#define RK3568_VP1_DSP_VS_ST_END_F1		0xD58
+#define RK3568_VP1_DSP_VACT_ST_END_F1		0xD5C
+#define RK3568_VP1_BCSH_CTRL			0xD60
+#define RK3568_VP1_BCSH_BCS			0xD64
+#define RK3568_VP1_BCSH_H			0xD68
+#define RK3568_VP1_BCSH_COLOR_BAR		0xD6C
+
+#define RK3568_VP2_DSP_CTRL			0xE00
+#define RK3568_VP2_MIPI_CTRL			0xE04
+#define RK3568_VP2_COLOR_BAR_CTRL		0xE08
+#define RK3568_VP2_DSP_BG			0xE2C
+#define RK3568_VP2_PRE_SCAN_HTIMING		0xE30
+#define RK3568_VP2_POST_DSP_HACT_INFO		0xE34
+#define RK3568_VP2_POST_DSP_VACT_INFO		0xE38
+#define RK3568_VP2_POST_SCL_FACTOR_YRGB		0xE3C
+#define RK3568_VP2_POST_SCL_CTRL		0xE40
+#define RK3568_VP2_DSP_HACT_INFO		0xE34
+#define RK3568_VP2_DSP_VACT_INFO		0xE38
+#define RK3568_VP2_POST_DSP_VACT_INFO_F1	0xE44
+#define RK3568_VP2_DSP_HTOTAL_HS_END		0xE48
+#define RK3568_VP2_DSP_HACT_ST_END		0xE4C
+#define RK3568_VP2_DSP_VTOTAL_VS_END		0xE50
+#define RK3568_VP2_DSP_VACT_ST_END		0xE54
+#define RK3568_VP2_DSP_VS_ST_END_F1		0xE58
+#define RK3568_VP2_DSP_VACT_ST_END_F1		0xE5C
+#define RK3568_VP2_BCSH_CTRL			0xE60
+#define RK3568_VP2_BCSH_BCS			0xE64
+#define RK3568_VP2_BCSH_H			0xE68
+#define RK3568_VP2_BCSH_COLOR_BAR		0xE6C
+
+/* Overlay registers definition    */
+#define RK3568_OVL_CTRL				0x600
+#define RK3568_OVL_LAYER_SEL			0x604
+#define RK3568_OVL_PORT_SEL			0x608
+#define RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL	0x610
+#define RK3568_CLUSTER0_MIX_DST_COLOR_CTRL	0x614
+#define RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL	0x618
+#define RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL	0x61C
+#define RK3568_MIX0_SRC_COLOR_CTRL		0x650
+#define RK3568_MIX0_DST_COLOR_CTRL		0x654
+#define RK3568_MIX0_SRC_ALPHA_CTRL		0x658
+#define RK3568_MIX0_DST_ALPHA_CTRL		0x65C
+#define RK3568_HDR0_SRC_COLOR_CTRL		0x6C0
+#define RK3568_HDR0_DST_COLOR_CTRL		0x6C4
+#define RK3568_HDR0_SRC_ALPHA_CTRL		0x6C8
+#define RK3568_HDR0_DST_ALPHA_CTRL		0x6CC
+#define RK3568_VP0_BG_MIX_CTRL			0x6E0
+#define RK3568_VP1_BG_MIX_CTRL			0x6E4
+#define RK3568_VP2_BG_MIX_CTRL			0x6E8
+#define RK3568_CLUSTER_DLY_NUM			0x6F0
+#define RK3568_SMART_DLY_NUM			0x6F8
+
+/* Cluster register definition, offset relative to window base */
+#define RK3568_CLUSTER_WIN_CTRL0		0x00
+#define RK3568_CLUSTER_WIN_CTRL1		0x04
+#define RK3568_CLUSTER_WIN_YRGB_MST		0x10
+#define RK3568_CLUSTER_WIN_CBR_MST		0x14
+#define RK3568_CLUSTER_WIN_VIR			0x18
+#define RK3568_CLUSTER_WIN_ACT_INFO		0x20
+#define RK3568_CLUSTER_WIN_DSP_INFO		0x24
+#define RK3568_CLUSTER_WIN_DSP_ST		0x28
+#define RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB	0x30
+#define RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET	0x3C
+#define RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL	0x50
+#define RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE	0x54
+#define RK3568_CLUSTER_WIN_AFBCD_HDR_PTR	0x58
+#define RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH	0x5C
+#define RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE	0x60
+#define RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET	0x64
+#define RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET	0x68
+#define RK3568_CLUSTER_WIN_AFBCD_CTRL		0x6C
+
+#define RK3568_CLUSTER_CTRL			0x100
+
+/* (E)smart register definition, offset relative to window base */
+#define RK3568_SMART_CTRL0			0x00
+#define RK3568_SMART_CTRL1			0x04
+#define RK3568_SMART_REGION0_CTRL		0x10
+#define RK3568_SMART_REGION0_YRGB_MST		0x14
+#define RK3568_SMART_REGION0_CBR_MST		0x18
+#define RK3568_SMART_REGION0_VIR		0x1C
+#define RK3568_SMART_REGION0_ACT_INFO		0x20
+#define RK3568_SMART_REGION0_DSP_INFO		0x24
+#define RK3568_SMART_REGION0_DSP_ST		0x28
+#define RK3568_SMART_REGION0_SCL_CTRL		0x30
+#define RK3568_SMART_REGION0_SCL_FACTOR_YRGB	0x34
+#define RK3568_SMART_REGION0_SCL_FACTOR_CBR	0x38
+#define RK3568_SMART_REGION0_SCL_OFFSET		0x3C
+#define RK3568_SMART_REGION1_CTRL		0x40
+#define RK3568_SMART_REGION1_YRGB_MST		0x44
+#define RK3568_SMART_REGION1_CBR_MST		0x48
+#define RK3568_SMART_REGION1_VIR		0x4C
+#define RK3568_SMART_REGION1_ACT_INFO		0x50
+#define RK3568_SMART_REGION1_DSP_INFO		0x54
+#define RK3568_SMART_REGION1_DSP_ST		0x58
+#define RK3568_SMART_REGION1_SCL_CTRL		0x60
+#define RK3568_SMART_REGION1_SCL_FACTOR_YRGB	0x64
+#define RK3568_SMART_REGION1_SCL_FACTOR_CBR	0x68
+#define RK3568_SMART_REGION1_SCL_OFFSET		0x6C
+#define RK3568_SMART_REGION2_CTRL		0x70
+#define RK3568_SMART_REGION2_YRGB_MST		0x74
+#define RK3568_SMART_REGION2_CBR_MST		0x78
+#define RK3568_SMART_REGION2_VIR		0x7C
+#define RK3568_SMART_REGION2_ACT_INFO		0x80
+#define RK3568_SMART_REGION2_DSP_INFO		0x84
+#define RK3568_SMART_REGION2_DSP_ST		0x88
+#define RK3568_SMART_REGION2_SCL_CTRL		0x90
+#define RK3568_SMART_REGION2_SCL_FACTOR_YRGB	0x94
+#define RK3568_SMART_REGION2_SCL_FACTOR_CBR	0x98
+#define RK3568_SMART_REGION2_SCL_OFFSET		0x9C
+#define RK3568_SMART_REGION3_CTRL		0xA0
+#define RK3568_SMART_REGION3_YRGB_MST		0xA4
+#define RK3568_SMART_REGION3_CBR_MST		0xA8
+#define RK3568_SMART_REGION3_VIR		0xAC
+#define RK3568_SMART_REGION3_ACT_INFO		0xB0
+#define RK3568_SMART_REGION3_DSP_INFO		0xB4
+#define RK3568_SMART_REGION3_DSP_ST		0xB8
+#define RK3568_SMART_REGION3_SCL_CTRL		0xC0
+#define RK3568_SMART_REGION3_SCL_FACTOR_YRGB	0xC4
+#define RK3568_SMART_REGION3_SCL_FACTOR_CBR	0xC8
+#define RK3568_SMART_REGION3_SCL_OFFSET		0xCC
+#define RK3568_SMART_COLOR_KEY_CTRL		0xD0
+
+/* HDR register definition */
+#define RK3568_HDR_LUT_CTRL			0x2000
+#define RK3568_HDR_LUT_MST			0x2004
+#define RK3568_SDR2HDR_CTRL			0x2010
+#define RK3568_HDR2SDR_CTRL			0x2020
+#define RK3568_HDR2SDR_SRC_RANGE		0x2024
+#define RK3568_HDR2SDR_NORMFACEETF		0x2028
+#define RK3568_HDR2SDR_DST_RANGE		0x202C
+#define RK3568_HDR2SDR_NORMFACCGAMMA		0x2030
+#define RK3568_HDR_EETF_OETF_Y0			0x203C
+#define RK3568_HDR_SAT_Y0			0x20C0
+#define RK3568_HDR_EOTF_OETF_Y0			0x20F0
+#define RK3568_HDR_OETF_DX_POW1			0x2200
+#define RK3568_HDR_OETF_XN1			0x2300
+
+#define RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN		BIT(15)
+
+#define RK3568_VP_DSP_CTRL__STANDBY			BIT(31)
+#define RK3568_VP_DSP_CTRL__DITHER_DOWN_MODE		BIT(20)
+#define RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL		GENMASK(19, 18)
+#define RK3568_VP_DSP_CTRL__DITHER_DOWN_EN		BIT(17)
+#define RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN		BIT(16)
+#define RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y		BIT(15)
+#define RK3568_VP_DSP_CTRL__DSP_RB_SWAP			BIT(9)
+#define RK3568_VP_DSP_CTRL__DSP_INTERLACE		BIT(7)
+#define RK3568_VP_DSP_CTRL__DSP_FILED_POL		BIT(6)
+#define RK3568_VP_DSP_CTRL__P2I_EN			BIT(5)
+#define RK3568_VP_DSP_CTRL__CORE_DCLK_DIV		BIT(4)
+#define RK3568_VP_DSP_CTRL__OUT_MODE			GENMASK(3, 0)
+
+#define RK3568_VP_POST_SCL_CTRL__VSCALEDOWN		BIT(1)
+#define RK3568_VP_POST_SCL_CTRL__HSCALEDOWN		BIT(0)
+
+#define RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX		GENMASK(26, 25)
+#define RK3568_SYS_DSP_INFACE_EN_LVDS1			BIT(24)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX		GENMASK(22, 21)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI1			BIT(20)
+#define RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX		GENMASK(19, 18)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX		GENMASK(17, 16)
+#define RK3568_SYS_DSP_INFACE_EN_EDP_MUX		GENMASK(15, 14)
+#define RK3568_SYS_DSP_INFACE_EN_HDMI_MUX		GENMASK(11, 10)
+#define RK3568_SYS_DSP_INFACE_EN_RGB_MUX		GENMASK(9, 8)
+#define RK3568_SYS_DSP_INFACE_EN_LVDS0			BIT(5)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI0			BIT(4)
+#define RK3568_SYS_DSP_INFACE_EN_EDP			BIT(3)
+#define RK3568_SYS_DSP_INFACE_EN_HDMI			BIT(1)
+#define RK3568_SYS_DSP_INFACE_EN_RGB			BIT(0)
+
+#define RK3568_DSP_IF_POL__MIPI_PIN_POL			GENMASK(19, 16)
+#define RK3568_DSP_IF_POL__EDP_PIN_POL			GENMASK(15, 12)
+#define RK3568_DSP_IF_POL__HDMI_PIN_POL			GENMASK(7, 4)
+#define RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL		GENMASK(3, 0)
+
+#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2_PHASE_LOCK	BIT(5)
+#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2			BIT(4)
+
+#define RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN	BIT(31)
+
+#define RK3568_DSP_IF_POL__CFG_DONE_IMD			BIT(28)
+
+#define VOP2_SYS_AXI_BUS_NUM				2
+
+#define VOP2_CLUSTER_YUV444_10				0x12
+
+#define VOP2_COLOR_KEY_MASK				BIT(31)
+
+#define RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD		BIT(28)
+
+#define RK3568_VP_BG_MIX_CTRL__BG_DLY			GENMASK(31, 24)
+
+#define RK3568_OVL_PORT_SEL__SEL_PORT			GENMASK(31, 16)
+#define RK3568_OVL_PORT_SEL__SMART1			GENMASK(31, 30)
+#define RK3568_OVL_PORT_SEL__SMART0			GENMASK(29, 28)
+#define RK3568_OVL_PORT_SEL__ESMART1			GENMASK(27, 26)
+#define RK3568_OVL_PORT_SEL__ESMART0			GENMASK(25, 24)
+#define RK3568_OVL_PORT_SEL__CLUSTER1			GENMASK(19, 18)
+#define RK3568_OVL_PORT_SEL__CLUSTER0			GENMASK(17, 16)
+#define RK3568_OVL_PORT_SET__PORT2_MUX			GENMASK(11, 8)
+#define RK3568_OVL_PORT_SET__PORT1_MUX			GENMASK(7, 4)
+#define RK3568_OVL_PORT_SET__PORT0_MUX			GENMASK(3, 0)
+#define RK3568_OVL_LAYER_SEL__LAYER(layer, x)		((x) << ((layer) * 4))
+
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER1_1		GENMASK(31, 24)
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER1_0		GENMASK(23, 16)
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_1		GENMASK(15, 8)
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_0		GENMASK(7, 0)
+
+#define RK3568_SMART_DLY_NUM__SMART1			GENMASK(31, 24)
+#define RK3568_SMART_DLY_NUM__SMART0			GENMASK(23, 16)
+#define RK3568_SMART_DLY_NUM__ESMART1			GENMASK(15, 8)
+#define RK3568_SMART_DLY_NUM__ESMART0			GENMASK(7, 0)
+
+#define VP_INT_DSP_HOLD_VALID	BIT(6)
+#define VP_INT_FS_FIELD		BIT(5)
+#define VP_INT_POST_BUF_EMPTY	BIT(4)
+#define VP_INT_LINE_FLAG1	BIT(3)
+#define VP_INT_LINE_FLAG0	BIT(2)
+#define VOP2_INT_BUS_ERRPR	BIT(1)
+#define VP_INT_FS		BIT(0)
+
+#define POLFLAG_DCLK_INV	BIT(3)
+
+enum vop2_layer_phy_id {
+	ROCKCHIP_VOP2_CLUSTER0 = 0,
+	ROCKCHIP_VOP2_CLUSTER1,
+	ROCKCHIP_VOP2_ESMART0,
+	ROCKCHIP_VOP2_ESMART1,
+	ROCKCHIP_VOP2_SMART0,
+	ROCKCHIP_VOP2_SMART1,
+	ROCKCHIP_VOP2_CLUSTER2,
+	ROCKCHIP_VOP2_CLUSTER3,
+	ROCKCHIP_VOP2_ESMART2,
+	ROCKCHIP_VOP2_ESMART3,
+	ROCKCHIP_VOP2_PHY_ID_INVALID = -1,
+};
+
+extern const struct component_ops vop2_component_ops;
+
+#endif /* _ROCKCHIP_DRM_VOP2_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
new file mode 100644
index 0000000000000..683cd53c10158
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) Rockchip Electronics Co.Ltd
+ * Author: Andy Yan <andy.yan@rock-chips.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/component.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_print.h>
+
+#include "rockchip_drm_vop2.h"
+#include "rockchip_vop_reg.h"
+
+#define _VOP_REG(off, _mask, _shift, _write_mask) \
+	{ \
+		.offset = off, \
+		.mask = _mask, \
+		.shift = _shift, \
+		.write_mask = _write_mask, \
+	}
+
+#define VOP_REG(off, _mask, _shift) \
+		_VOP_REG(off, _mask, _shift, false)
+
+#define VOP_REG_MASK(off, _mask, s) \
+		_VOP_REG(off, _mask, s, true)
+
+static const uint32_t formats_win_full_10bit[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV16,
+	DRM_FORMAT_NV24,
+};
+
+static const uint32_t formats_win_full_10bit_yuyv[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV16,
+	DRM_FORMAT_NV24,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_VYUY,
+};
+
+static const uint32_t formats_win_lite[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+};
+
+static const uint64_t format_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static const uint64_t format_modifiers_afbc[] = {
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_CBR),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_CBR |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_CBR),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_CBR |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	/* SPLIT mandates SPARSE, RGB modes mandates YTR */
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_SPARSE |
+				AFBC_FORMAT_MOD_SPLIT),
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static const struct vop2_video_port_regs rk3568_vop_vp0_regs = {
+	.dsp_background = RK3568_VP0_DSP_BG,
+	.pre_scan_htiming = RK3568_VP0_PRE_SCAN_HTIMING,
+	.hpost_st_end = RK3568_VP0_POST_DSP_HACT_INFO,
+	.vpost_st_end = RK3568_VP0_POST_DSP_VACT_INFO,
+	.htotal_pw = RK3568_VP0_DSP_HTOTAL_HS_END,
+	.post_scl_factor = RK3568_VP0_POST_SCL_FACTOR_YRGB,
+	.hact_st_end = RK3568_VP0_DSP_HACT_ST_END,
+	.vtotal_pw = RK3568_VP0_DSP_VTOTAL_VS_END,
+	.vact_st_end = RK3568_VP0_DSP_VACT_ST_END,
+	.vact_st_end_f1 = RK3568_VP0_DSP_VACT_ST_END_F1,
+	.vs_st_end_f1 = RK3568_VP0_DSP_VS_ST_END_F1,
+	.vpost_st_end_f1 = RK3568_VP0_POST_DSP_VACT_INFO_F1,
+
+	.dsp_ctrl = RK3568_VP0_DSP_CTRL,
+	.mipi_ctrl = RK3568_VP0_MIPI_CTRL,
+	.bg_mix_ctrl = RK3568_VP0_BG_MIX_CTRL,
+	.irq_status = RK3568_VP0_INT_STATUS,
+	.irq_enable = RK3568_VP0_INT_EN,
+	.irq_clear = RK3568_VP0_INT_CLR,
+	.line_flag = RK3568_VP0_LINE_FLAG,
+};
+
+static const struct vop2_video_port_regs rk3568_vop_vp1_regs = {
+	.dsp_background = RK3568_VP1_DSP_BG,
+	.pre_scan_htiming = RK3568_VP1_PRE_SCAN_HTIMING,
+	.hpost_st_end = RK3568_VP1_POST_DSP_HACT_INFO,
+	.vpost_st_end = RK3568_VP1_POST_DSP_VACT_INFO,
+	.htotal_pw = RK3568_VP1_DSP_HTOTAL_HS_END,
+	.post_scl_factor = RK3568_VP1_POST_SCL_FACTOR_YRGB,
+	.hact_st_end = RK3568_VP1_DSP_HACT_ST_END,
+	.vtotal_pw = RK3568_VP1_DSP_VTOTAL_VS_END,
+	.vact_st_end = RK3568_VP1_DSP_VACT_ST_END,
+	.vact_st_end_f1 = RK3568_VP1_DSP_VACT_ST_END_F1,
+	.vs_st_end_f1 = RK3568_VP1_DSP_VS_ST_END_F1,
+	.vpost_st_end_f1 = RK3568_VP1_POST_DSP_VACT_INFO_F1,
+	.dsp_ctrl = RK3568_VP1_DSP_CTRL,
+	.mipi_ctrl = RK3568_VP1_MIPI_CTRL,
+	.bg_mix_ctrl = RK3568_VP1_BG_MIX_CTRL,
+	.irq_status = RK3568_VP1_INT_STATUS,
+	.irq_enable = RK3568_VP1_INT_EN,
+	.irq_clear = RK3568_VP1_INT_CLR,
+	.line_flag = RK3568_VP1_LINE_FLAG,
+};
+
+static const struct vop2_video_port_regs rk3568_vop_vp2_regs = {
+	.dsp_background = RK3568_VP2_DSP_BG,
+	.pre_scan_htiming = RK3568_VP2_PRE_SCAN_HTIMING,
+	.hpost_st_end = RK3568_VP2_POST_DSP_HACT_INFO,
+	.vpost_st_end = RK3568_VP2_POST_DSP_VACT_INFO,
+	.post_scl_factor = RK3568_VP2_POST_SCL_FACTOR_YRGB,
+	.htotal_pw = RK3568_VP2_DSP_HTOTAL_HS_END,
+	.hact_st_end = RK3568_VP2_DSP_HACT_ST_END,
+	.vtotal_pw = RK3568_VP2_DSP_VTOTAL_VS_END,
+	.vact_st_end = RK3568_VP2_DSP_VACT_ST_END,
+	.vact_st_end_f1 = RK3568_VP2_DSP_VACT_ST_END_F1,
+	.vs_st_end_f1 = RK3568_VP2_DSP_VS_ST_END_F1,
+	.vpost_st_end_f1 = RK3568_VP2_POST_DSP_VACT_INFO_F1,
+	.dsp_ctrl = RK3568_VP2_DSP_CTRL,
+	.mipi_ctrl = RK3568_VP2_MIPI_CTRL,
+	.bg_mix_ctrl = RK3568_VP2_BG_MIX_CTRL,
+	.irq_status = RK3568_VP2_INT_STATUS,
+	.irq_enable = RK3568_VP2_INT_EN,
+	.irq_clear = RK3568_VP2_INT_CLR,
+	.line_flag = RK3568_VP2_LINE_FLAG,
+};
+
+static const struct vop2_video_port_data rk3568_vop_video_ports[] = {
+	{
+		.id = 0,
+		.feature = VOP_FEATURE_OUTPUT_10BIT,
+		.gamma_lut_len = 1024,
+		.cubic_lut_len = 9 * 9 * 9,
+		.max_output = { 4096, 2304 },
+		.pre_scan_max_dly = { 69, 53, 53, 42 },
+		.regs = &rk3568_vop_vp0_regs,
+	}, {
+		.id = 1,
+		.gamma_lut_len = 1024,
+		.max_output = { 2048, 1536 },
+		.pre_scan_max_dly = { 40, 40, 40, 40 },
+		.regs = &rk3568_vop_vp1_regs,
+	}, {
+		.id = 2,
+		.gamma_lut_len = 1024,
+		.max_output = { 1920, 1080 },
+		.pre_scan_max_dly = { 40, 40, 40, 40 },
+		.regs = &rk3568_vop_vp2_regs,
+	},
+};
+
+static const struct vop2_cluster_regs rk3568_vop_cluster0 =  {
+	.afbc_enable = VOP_REG(RK3568_CLUSTER_CTRL, 0x1, 1),
+	.enable = VOP_REG(RK3568_CLUSTER_CTRL, 1, 0),
+	.lb_mode = VOP_REG(RK3568_CLUSTER_CTRL, 0xf, 4),
+};
+
+static const struct vop2_afbc rk3568_cluster_afbc = {
+	.format = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1f, 2),
+	.rb_swap = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 9),
+	.uv_swap = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 10),
+	.auto_gating_en = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL, 0x1, 4),
+	.half_block_en = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 7),
+	.block_split_en = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 8),
+	.hdr_ptr = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_HDR_PTR, 0xffffffff, 0),
+	.pic_size = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE, 0xffffffff, 0),
+	.pic_vir_width = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0xffff, 0),
+	.tile_num = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0xffff, 16),
+	.pic_offset = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET, 0xffffffff, 0),
+	.dsp_offset = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET, 0xffffffff, 0),
+	.transform_offset = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET, 0xffffffff, 0),
+	.rotate_90 = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 0),
+	.rotate_270 = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 1),
+	.xmirror = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 2),
+	.ymirror = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 3),
+};
+
+static const struct vop2_scl_regs rk3568_cluster_win_scl = {
+	.scale_yrgb_x = VOP_REG(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0xffff, 0x0),
+	.scale_yrgb_y = VOP_REG(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0xffff, 16),
+	.yrgb_ver_scl_mode = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x3, 14),
+	.yrgb_hor_scl_mode = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x3, 12),
+	.bic_coe_sel = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x3, 2),
+	.vsd_yrgb_gt2 = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x1, 28),
+	.vsd_yrgb_gt4 = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x1, 29),
+};
+
+static const struct vop2_scl_regs rk3568_esmart_win_scl = {
+	.scale_yrgb_x = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0xffff, 0x0),
+	.scale_yrgb_y = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0xffff, 16),
+	.scale_cbcr_x = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0xffff, 0x0),
+	.scale_cbcr_y = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0xffff, 16),
+	.yrgb_hor_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 0),
+	.yrgb_hscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 2),
+	.yrgb_ver_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 4),
+	.yrgb_vscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 6),
+	.cbcr_hor_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 8),
+	.cbcr_hscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 10),
+	.cbcr_ver_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 12),
+	.cbcr_vscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 14),
+	.bic_coe_sel = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 16),
+	.vsd_yrgb_gt2 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 8),
+	.vsd_yrgb_gt4 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 9),
+	.vsd_cbcr_gt2 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 10),
+	.vsd_cbcr_gt4 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 11),
+};
+
+static const struct vop2_win_regs rk3568_cluster_win_data = {
+	.scl = &rk3568_cluster_win_scl,
+	.afbc = &rk3568_cluster_afbc,
+	.cluster = &rk3568_vop_cluster0,
+	.enable = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 0),
+	.format = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1f, 1),
+	.rb_swap = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 14),
+	.dither_up = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 18),
+	.act_info = VOP_REG(RK3568_CLUSTER_WIN_ACT_INFO, 0x1fff1fff, 0),
+	.dsp_info = VOP_REG(RK3568_CLUSTER_WIN_DSP_INFO, 0x0fff0fff, 0),
+	.dsp_st = VOP_REG(RK3568_CLUSTER_WIN_DSP_ST, 0x1fff1fff, 0),
+	.yrgb_mst = VOP_REG(RK3568_CLUSTER_WIN_YRGB_MST, 0xffffffff, 0),
+	.uv_mst = VOP_REG(RK3568_CLUSTER_WIN_CBR_MST, 0xffffffff, 0),
+	.yuv_clip = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 19),
+	.yrgb_vir = VOP_REG(RK3568_CLUSTER_WIN_VIR, 0xffff, 0),
+	.uv_vir = VOP_REG(RK3568_CLUSTER_WIN_VIR, 0xffff, 16),
+	.y2r_en = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 8),
+	.r2y_en = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 9),
+	.csc_mode = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x3, 10),
+};
+
+static const struct vop2_win_regs rk3568_esmart_win_data = {
+	.scl = &rk3568_esmart_win_scl,
+	.enable = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 0),
+	.format = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1f, 1),
+	.dither_up = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 12),
+	.rb_swap = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 14),
+	.uv_swap = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 16),
+	.act_info = VOP_REG(RK3568_SMART_REGION0_ACT_INFO, 0x1fff1fff, 0),
+	.dsp_info = VOP_REG(RK3568_SMART_REGION0_DSP_INFO, 0x0fff0fff, 0),
+	.dsp_st = VOP_REG(RK3568_SMART_REGION0_DSP_ST, 0x1fff1fff, 0),
+	.yrgb_mst = VOP_REG(RK3568_SMART_REGION0_YRGB_MST, 0xffffffff, 0),
+	.uv_mst = VOP_REG(RK3568_SMART_REGION0_CBR_MST, 0xffffffff, 0),
+	.yuv_clip = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 17),
+	.yrgb_vir = VOP_REG(RK3568_SMART_REGION0_VIR, 0xffff, 0),
+	.uv_vir = VOP_REG(RK3568_SMART_REGION0_VIR, 0xffff, 16),
+	.y2r_en = VOP_REG(RK3568_SMART_CTRL0, 0x1, 0),
+	.r2y_en = VOP_REG(RK3568_SMART_CTRL0, 0x1, 1),
+	.csc_mode = VOP_REG(RK3568_SMART_CTRL0, 0x3, 2),
+	.ymirror = VOP_REG(RK3568_SMART_CTRL1, 0x1, 31),
+	.color_key = VOP_REG(RK3568_SMART_COLOR_KEY_CTRL, 0x3fffffff, 0),
+	.color_key_en = VOP_REG(RK3568_SMART_COLOR_KEY_CTRL, 0x1, 31),
+};
+
+/*
+ * rk3568 vop with 2 cluster, 2 esmart win, 2 smart win.
+ * Every cluster can work as 4K win or split into two win.
+ * All win in cluster support AFBCD.
+ *
+ * Every esmart win and smart win support 4 Multi-region.
+ *
+ * Scale filter mode:
+ *
+ * * Cluster:  bicubic for horizontal scale up, others use bilinear
+ * * ESmart:
+ *    * nearest-neighbor/bilinear/bicubic for scale up
+ *    * nearest-neighbor/bilinear/average for scale down
+ *
+ *
+ * @TODO describe the wind like cpu-map dt nodes;
+ */
+static const struct vop2_win_data rk3568_vop_win_data[] = {
+	{
+		.name = "Smart0-win0",
+		.phys_id = ROCKCHIP_VOP2_SMART0,
+		.base = 0x1c00,
+		.formats = formats_win_lite,
+		.nformats = ARRAY_SIZE(formats_win_lite),
+		.format_modifiers = format_modifiers,
+		.layer_sel_id = 3,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_PRIMARY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Smart1-win0",
+		.phys_id = ROCKCHIP_VOP2_SMART1,
+		.formats = formats_win_lite,
+		.nformats = ARRAY_SIZE(formats_win_lite),
+		.format_modifiers = format_modifiers,
+		.base = 0x1e00,
+		.layer_sel_id = 7,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_PRIMARY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Esmart1-win0",
+		.phys_id = ROCKCHIP_VOP2_ESMART1,
+		.formats = formats_win_full_10bit_yuyv,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
+		.format_modifiers = format_modifiers,
+		.base = 0x1a00,
+		.layer_sel_id = 6,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_PRIMARY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Esmart0-win0",
+		.phys_id = ROCKCHIP_VOP2_ESMART0,
+		.formats = formats_win_full_10bit_yuyv,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
+		.format_modifiers = format_modifiers,
+		.base = 0x1800,
+		.layer_sel_id = 2,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_OVERLAY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Cluster0-win0",
+		.phys_id = ROCKCHIP_VOP2_CLUSTER0,
+		.base = 0x1000,
+		.formats = formats_win_full_10bit,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit),
+		.format_modifiers = format_modifiers_afbc,
+		.layer_sel_id = 0,
+		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
+					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_cluster_win_data,
+		.max_upscale_factor = 4,
+		.max_downscale_factor = 4,
+		.dly = { 0, 27, 21 },
+		.type = DRM_PLANE_TYPE_OVERLAY,
+		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
+	}, {
+		.name = "Cluster1-win0",
+		.phys_id = ROCKCHIP_VOP2_CLUSTER1,
+		.base = 0x1200,
+		.formats = formats_win_full_10bit,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit),
+		.format_modifiers = format_modifiers_afbc,
+		.layer_sel_id = 1,
+		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
+					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_cluster_win_data,
+		.type = DRM_PLANE_TYPE_OVERLAY,
+		.max_upscale_factor = 4,
+		.max_downscale_factor = 4,
+		.dly = { 0, 27, 21 },
+		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
+	},
+};
+
+static const struct vop_grf_ctrl rk3568_grf_ctrl = {
+	.grf_bt656_clk_inv = VOP_REG(RK3568_GRF_VO_CON1, 0x1, 1),
+	.grf_bt1120_clk_inv = VOP_REG(RK3568_GRF_VO_CON1, 0x1, 2),
+	.grf_dclk_inv = VOP_REG(RK3568_GRF_VO_CON1, 0x1, 3),
+};
+
+static const struct vop2_data rk3566_vop = {
+	.nr_vps = 3,
+	.nr_mixers = 5,
+	.nr_gammas = 1,
+	.max_input = { 4096, 2304 },
+	.max_output = { 4096, 2304 },
+	.grf_ctrl = &rk3568_grf_ctrl,
+	.vp = rk3568_vop_video_ports,
+	.win = rk3568_vop_win_data,
+	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
+	.soc_id = 3566,
+};
+
+static const struct vop2_data rk3568_vop = {
+	.nr_vps = 3,
+	.nr_mixers = 5,
+	.nr_gammas = 1,
+	.max_input = { 4096, 2304 },
+	.max_output = { 4096, 2304 },
+	.grf_ctrl = &rk3568_grf_ctrl,
+	.vp = rk3568_vop_video_ports,
+	.win = rk3568_vop_win_data,
+	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
+	.soc_id = 3568,
+};
+
+static const struct of_device_id vop2_dt_match[] = {
+	{
+		.compatible = "rockchip,rk3568-vop",
+		.data = &rk3568_vop
+	}, {
+		.compatible = "rockchip,rk3568-vop",
+		.data = &rk3566_vop
+	}, {
+	},
+};
+MODULE_DEVICE_TABLE(of, vop2_dt_match);
+
+static int vop2_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	return component_add(dev, &vop2_component_ops);
+}
+
+static int vop2_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &vop2_component_ops);
+
+	return 0;
+}
+
+struct platform_driver vop2_platform_driver = {
+	.probe = vop2_probe,
+	.remove = vop2_remove,
+	.driver = {
+		.name = "rockchip-vop2",
+		.of_match_table = of_match_ptr(vop2_dt_match),
+	},
+};
-- 
2.30.2


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

* [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

From: Andy Yan <andy.yan@rock-chips.com>

The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
It replaces the VOP unit found in the older Rockchip SoCs.

This driver has been derived from the downstream Rockchip Kernel and
heavily modified:

- All nonstandard DRM properties have been removed
- dropped struct vop2_plane_state and pass around less data between
  functions
- Dropped all DRM_FORMAT_* not known on upstream
- rework register access to get rid of excessively used macros
- Drop all waiting for framesyncs

The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
board. Overlay support is tested with the modetest utility. AFBC support
on the cluster windows is tested with weston-simple-dmabuf-egl on
weston using the (yet to be upstreamed) panfrost driver support.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpu/drm/rockchip/Kconfig             |    6 +
 drivers/gpu/drm/rockchip/Makefile            |    1 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c  |    1 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h  |    7 +-
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c   |    2 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h  |   15 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2636 ++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |  625 +++++
 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c |  505 ++++
 9 files changed, 3797 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index b9b156308460a..4ff0043f0ee70 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -28,6 +28,12 @@ config ROCKCHIP_VOP
 	  This selects support for the VOP driver. You should enable it
 	  on all older SoCs up to RK3399.
 
+config ROCKCHIP_VOP2
+	bool "Rockchip VOP2 driver"
+	help
+	  This selects support for the VOP2 driver. You should enable it
+	  on all newer SoCs beginning form RK3568.
+
 config ROCKCHIP_ANALOGIX_DP
 	bool "Rockchip specific extensions for Analogix DP driver"
 	depends on ROCKCHIP_VOP
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index cd6e7bb5ce9c5..29848caef5c21 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -7,6 +7,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
 		rockchip_drm_gem.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
+rockchipdrm-$(CONFIG_ROCKCHIP_VOP2) += rockchip_drm_vop2.o rockchip_vop2_reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 64fa5fd62c01a..2bd9acb265e5a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -474,6 +474,7 @@ static int __init rockchip_drm_init(void)
 
 	num_rockchip_sub_drivers = 0;
 	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP);
+	ADD_ROCKCHIP_SUB_DRIVER(vop2_platform_driver, CONFIG_ROCKCHIP_VOP2);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver,
 				CONFIG_ROCKCHIP_LVDS);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index aa0909e8edf93..fd6994f21817e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -18,7 +18,7 @@
 
 #define ROCKCHIP_MAX_FB_BUFFER	3
 #define ROCKCHIP_MAX_CONNECTOR	2
-#define ROCKCHIP_MAX_CRTC	2
+#define ROCKCHIP_MAX_CRTC	4
 
 struct drm_device;
 struct drm_connector;
@@ -31,6 +31,9 @@ struct rockchip_crtc_state {
 	int output_bpc;
 	int output_flags;
 	bool enable_afbc;
+	uint32_t bus_format;
+	u32 bus_flags;
+	int color_space;
 };
 #define to_rockchip_crtc_state(s) \
 		container_of(s, struct rockchip_crtc_state, base)
@@ -65,4 +68,6 @@ extern struct platform_driver rockchip_dp_driver;
 extern struct platform_driver rockchip_lvds_driver;
 extern struct platform_driver vop_platform_driver;
 extern struct platform_driver rk3066_hdmi_driver;
+extern struct platform_driver vop2_platform_driver;
+
 #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 3aa37e177667e..0d2cb4f3922b8 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -134,4 +134,6 @@ void rockchip_drm_mode_config_init(struct drm_device *dev)
 
 	dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
 	dev->mode_config.helper_private = &rockchip_mode_config_helpers;
+
+	dev->mode_config.normalize_zpos = true;
 }
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 857d97cdc67c6..1e364d7b50e69 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -54,9 +54,23 @@ struct vop_afbc {
 	struct vop_reg enable;
 	struct vop_reg win_sel;
 	struct vop_reg format;
+	struct vop_reg rb_swap;
+	struct vop_reg uv_swap;
+	struct vop_reg auto_gating_en;
+	struct vop_reg block_split_en;
+	struct vop_reg pic_vir_width;
+	struct vop_reg tile_num;
 	struct vop_reg hreg_block_split;
+	struct vop_reg pic_offset;
 	struct vop_reg pic_size;
+	struct vop_reg dsp_offset;
+	struct vop_reg transform_offset;
 	struct vop_reg hdr_ptr;
+	struct vop_reg half_block_en;
+	struct vop_reg xmirror;
+	struct vop_reg ymirror;
+	struct vop_reg rotate_270;
+	struct vop_reg rotate_90;
 	struct vop_reg rstn;
 };
 
@@ -410,4 +424,5 @@ static inline int scl_vop_cal_lb_mode(int width, bool is_yuv)
 }
 
 extern const struct component_ops vop_component_ops;
+
 #endif /* _ROCKCHIP_DRM_VOP_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
new file mode 100644
index 0000000000000..411440d898ab0
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -0,0 +1,2636 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Rockchip Electronics Co., Ltd.
+ * Author: Andy Yan <andy.yan@rock-chips.com>
+ */
+#include <drm/drm.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_flip_work.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_writeback.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_atomic_uapi.h>
+
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <linux/component.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/delay.h>
+#include <linux/swab.h>
+#include <drm/drm_debugfs.h>
+#include <uapi/linux/videodev2.h>
+#include <drm/drm_vblank.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_vop2.h"
+#include "rockchip_vop_reg.h"
+
+/*
+ * VOP2 architecture
+ *
+ +----------+   +-------------+                                                        +-----------+
+ |  Cluster |   | Sel 1 from 6|                                                        | 1 from 3  |
+ |  window0 |   |    Layer0   |                                                        |    RGB    |
+ +----------+   +-------------+              +---------------+    +-------------+      +-----------+
+ +----------+   +-------------+              |N from 6 layers|    |             |
+ |  Cluster |   | Sel 1 from 6|              |   Overlay0    +--->| Video Port0 |      +-----------+
+ |  window1 |   |    Layer1   |              |               |    |             |      | 1 from 3  |
+ +----------+   +-------------+              +---------------+    +-------------+      |   LVDS    |
+ +----------+   +-------------+                                                        +-----------+
+ |  Esmart  |   | Sel 1 from 6|
+ |  window0 |   |   Layer2    |              +---------------+    +-------------+      +-----------+
+ +----------+   +-------------+              |N from 6 Layers|    |             | +--> | 1 from 3  |
+ +----------+   +-------------+   -------->  |   Overlay1    +--->| Video Port1 |      |   MIPI    |
+ |  Esmart  |   | Sel 1 from 6|   -------->  |               |    |             |      +-----------+
+ |  Window1 |   |   Layer3    |              +---------------+    +-------------+
+ +----------+   +-------------+                                                        +-----------+
+ +----------+   +-------------+                                                        | 1 from 3  |
+ |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |   HDMI    |
+ |  Window0 |   |    Layer4   |              |N from 6 Layers|    |             |      +-----------+
+ +----------+   +-------------+              |   Overlay2    +--->| Video Port2 |
+ +----------+   +-------------+              |               |    |             |      +-----------+
+ |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |  1 from 3 |
+ |  Window1 |   |    Layer5   |                                                        |    eDP    |
+ +----------+   +-------------+                                                        +-----------+
+ *
+ */
+
+enum vop2_data_format {
+	VOP2_FMT_ARGB8888 = 0,
+	VOP2_FMT_RGB888,
+	VOP2_FMT_RGB565,
+	VOP2_FMT_XRGB101010,
+	VOP2_FMT_YUV420SP,
+	VOP2_FMT_YUV422SP,
+	VOP2_FMT_YUV444SP,
+	VOP2_FMT_YUYV422 = 8,
+	VOP2_FMT_YUYV420,
+	VOP2_FMT_VYUY422,
+	VOP2_FMT_VYUY420,
+	VOP2_FMT_YUV420SP_TILE_8x4 = 0x10,
+	VOP2_FMT_YUV420SP_TILE_16x2,
+	VOP2_FMT_YUV422SP_TILE_8x4,
+	VOP2_FMT_YUV422SP_TILE_16x2,
+	VOP2_FMT_YUV420SP_10,
+	VOP2_FMT_YUV422SP_10,
+	VOP2_FMT_YUV444SP_10,
+};
+
+enum vop2_afbc_format {
+	VOP2_AFBC_FMT_RGB565,
+	VOP2_AFBC_FMT_ARGB2101010 = 2,
+	VOP2_AFBC_FMT_YUV420_10BIT,
+	VOP2_AFBC_FMT_RGB888,
+	VOP2_AFBC_FMT_ARGB8888,
+	VOP2_AFBC_FMT_YUV420 = 9,
+	VOP2_AFBC_FMT_YUV422 = 0xb,
+	VOP2_AFBC_FMT_YUV422_10BIT = 0xe,
+	VOP2_AFBC_FMT_INVALID = -1,
+};
+
+union vop2_alpha_ctrl {
+	uint32_t val;
+	struct {
+		/* [0:1] */
+		uint32_t color_mode:1;
+		uint32_t alpha_mode:1;
+		/* [2:3] */
+		uint32_t blend_mode:2;
+		uint32_t alpha_cal_mode:1;
+		/* [5:7] */
+		uint32_t factor_mode:3;
+		/* [8:9] */
+		uint32_t alpha_en:1;
+		uint32_t src_dst_swap:1;
+		uint32_t reserved:6;
+		/* [16:23] */
+		uint32_t glb_alpha:8;
+	} bits;
+};
+
+struct vop2_alpha {
+	union vop2_alpha_ctrl src_color_ctrl;
+	union vop2_alpha_ctrl dst_color_ctrl;
+	union vop2_alpha_ctrl src_alpha_ctrl;
+	union vop2_alpha_ctrl dst_alpha_ctrl;
+};
+
+struct vop2_alpha_config {
+	bool src_premulti_en;
+	bool dst_premulti_en;
+	bool src_pixel_alpha_en;
+	bool dst_pixel_alpha_en;
+	uint16_t src_glb_alpha_value;
+	uint16_t dst_glb_alpha_value;
+};
+
+struct vop2_win {
+	struct vop2 *vop2;
+	struct drm_plane base;
+	const struct vop2_win_data *data;
+
+	/**
+	 * @win_id: graphic window id, a cluster maybe split into two
+	 * graphics windows.
+	 */
+	uint8_t win_id;
+
+	uint32_t offset;
+
+	uint8_t delay;
+	enum drm_plane_type type;
+
+	const struct vop2_win_regs *regs;
+};
+
+struct vop2_video_port {
+	struct drm_crtc crtc;
+	struct vop2 *vop2;
+	struct clk *dclk;
+	uint8_t id;
+	const struct vop2_video_port_regs *regs;
+	const struct vop2_video_port_data *data;
+
+	struct completion dsp_hold_completion;
+
+	/**
+	 * @win_mask: Bitmask of wins attached to the video port;
+	 */
+	uint32_t win_mask;
+
+	struct vop2_win *primary_plane;
+	struct drm_pending_vblank_event *event;
+
+	int nlayers;
+};
+
+struct vop2 {
+	struct device *dev;
+	struct drm_device *drm;
+	struct vop2_video_port vps[ROCKCHIP_MAX_CRTC];
+
+	const struct vop2_data *data;
+	/* Number of win that registered as plane,
+	 * maybe less than the total number of hardware
+	 * win.
+	 */
+	uint32_t registered_num_wins;
+
+	uint32_t *regsbak;
+	void __iomem *regs;
+	struct regmap *grf;
+
+	/* physical map length of vop2 register */
+	uint32_t len;
+
+	void __iomem *lut_regs;
+	/* one time only one process allowed to config the register */
+	spinlock_t reg_lock;
+
+	/* protects crtc enable/disable */
+	struct mutex vop2_lock;
+
+	int irq;
+
+	/*
+	 * Some globle resource are shared between all
+	 * the vidoe ports(crtcs), so we need a ref counter here.
+	 */
+	unsigned int enable_count;
+	struct clk *hclk;
+	struct clk *aclk;
+
+	/* must put at the end of the struct */
+	struct vop2_win win[];
+};
+
+static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct vop2_video_port, crtc);
+}
+
+static struct vop2_win *to_vop2_win(struct drm_plane *p)
+{
+	return container_of(p, struct vop2_win, base);
+}
+
+static void vop2_lock(struct vop2 *vop2)
+{
+	mutex_lock(&vop2->vop2_lock);
+}
+
+static void vop2_unlock(struct vop2 *vop2)
+{
+	mutex_unlock(&vop2->vop2_lock);
+}
+
+static void vop2_grf_writel(struct vop2 *vop2, const struct vop_reg *reg,
+				   uint32_t v)
+{
+	uint32_t val = 0;
+
+	if (IS_ERR_OR_NULL(vop2->grf))
+		return;
+
+	if (reg->mask) {
+		val = (v << reg->shift) | (reg->mask << (reg->shift + 16));
+		regmap_write(vop2->grf, reg->offset, val);
+	}
+}
+
+static void vop2_writel(struct vop2 *vop2, uint32_t offset, uint32_t v)
+{
+	writel(v, vop2->regs + offset);
+	vop2->regsbak[offset >> 2] = v;
+}
+
+static uint32_t vop2_readl(struct vop2 *vop2, uint32_t offset)
+{
+	return readl(vop2->regs + offset);
+}
+
+static void vop2_write_reg(struct vop2 *vop2, uint32_t offset,
+			   const struct vop_reg *reg, uint32_t v, bool relaxed)
+{
+	uint32_t mask = reg->mask;
+	uint32_t shift = reg->shift;
+
+	if (!mask)
+		return;
+
+	offset += reg->offset;
+
+	if (reg->write_mask) {
+		v = ((v & mask) << shift) | (mask << (shift + 16));
+	} else {
+		/*
+		 * Several registers in the VOP2 are double buffered and read back
+		 * the new values only after config_done bits have been set. As we
+		 * read-modify-write the hardware registers we need to cache the values
+		 * in memory to make sure we do not overwrite previous values when a
+		 * hardware register is modified multiple times before config_done is
+		 * set.
+		 */
+		uint32_t cached_val = vop2->regsbak[offset >> 2];
+
+		v = (cached_val & ~(mask << shift)) | ((v & mask) << shift);
+		vop2->regsbak[offset >> 2] = v;
+	}
+
+	if (relaxed)
+		writel_relaxed(v, vop2->regs + offset);
+	else
+		writel(v, vop2->regs + offset);
+}
+
+static void vop2_win_write(const struct vop2_win *win, const struct vop_reg *reg,
+			   uint32_t v)
+{
+	vop2_write_reg(win->vop2, win->offset, reg, v, true);
+}
+
+static bool vop2_cluster_window(struct vop2_win *win)
+{
+	return win->data->feature & WIN_FEATURE_CLUSTER;
+}
+
+static void vop2_cfg_done(struct vop2_video_port *vp)
+{
+	struct vop2 *vop2 = vp->vop2;
+	uint32_t val;
+
+	val = vop2_readl(vop2, RK3568_REG_CFG_DONE);
+
+	val &= 0x7;
+
+	vop2_writel(vop2, RK3568_REG_CFG_DONE,
+		    val | BIT(vp->id) | RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
+}
+
+static void vop2_win_disable(struct vop2_win *win)
+{
+	vop2_win_write(win, &win->regs->enable, 0);
+
+	if (vop2_cluster_window(win))
+		vop2_win_write(win, &win->regs->cluster->enable, 0);
+}
+
+static enum vop2_data_format vop2_convert_format(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		return VOP2_FMT_ARGB8888;
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		return VOP2_FMT_RGB888;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		return VOP2_FMT_RGB565;
+	case DRM_FORMAT_NV12:
+		return VOP2_FMT_YUV420SP;
+	case DRM_FORMAT_NV16:
+		return VOP2_FMT_YUV422SP;
+	case DRM_FORMAT_NV24:
+		return VOP2_FMT_YUV444SP;
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_YVYU:
+		return VOP2_FMT_VYUY422;
+	case DRM_FORMAT_VYUY:
+	case DRM_FORMAT_UYVY:
+		return VOP2_FMT_YUYV422;
+	default:
+		DRM_ERROR("unsupported format[%08x]\n", format);
+		return -EINVAL;
+	}
+}
+
+static enum vop2_afbc_format vop2_convert_afbc_format(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		return VOP2_AFBC_FMT_ARGB8888;
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		return VOP2_AFBC_FMT_RGB888;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		return VOP2_AFBC_FMT_RGB565;
+	case DRM_FORMAT_NV12:
+		return VOP2_AFBC_FMT_YUV420;
+	case DRM_FORMAT_NV16:
+		return VOP2_AFBC_FMT_YUV422;
+	default:
+		return VOP2_AFBC_FMT_INVALID;
+	}
+
+	return VOP2_AFBC_FMT_INVALID;
+}
+
+static bool vop2_win_rb_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_BGR888:
+	case DRM_FORMAT_BGR565:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_afbc_rb_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV24:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_afbc_uv_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV16:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_win_uv_swap(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV24:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_win_dither_up(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_BGR565:
+	case DRM_FORMAT_RGB565:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool vop2_output_uv_swap(uint32_t bus_format, uint32_t output_mode)
+{
+	/*
+	 * FIXME:
+	 *
+	 * There is no media type for YUV444 output,
+	 * so when out_mode is AAAA or P888, assume output is YUV444 on
+	 * yuv format.
+	 *
+	 * From H/W testing, YUV444 mode need a rb swap.
+	 */
+	if (bus_format == MEDIA_BUS_FMT_YVYU8_1X16 ||
+	    bus_format == MEDIA_BUS_FMT_VYUY8_1X16 ||
+	    bus_format == MEDIA_BUS_FMT_YVYU8_2X8 ||
+	    bus_format == MEDIA_BUS_FMT_VYUY8_2X8 ||
+	    ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||
+	      bus_format == MEDIA_BUS_FMT_YUV10_1X30) &&
+	     (output_mode == ROCKCHIP_OUT_MODE_AAAA ||
+	      output_mode == ROCKCHIP_OUT_MODE_P888)))
+		return true;
+	else
+		return false;
+}
+
+static bool is_yuv_output(uint32_t bus_format)
+{
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_YUV8_1X24:
+	case MEDIA_BUS_FMT_YUV10_1X30:
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+	case MEDIA_BUS_FMT_YUYV8_2X8:
+	case MEDIA_BUS_FMT_YVYU8_2X8:
+	case MEDIA_BUS_FMT_UYVY8_2X8:
+	case MEDIA_BUS_FMT_VYUY8_2X8:
+	case MEDIA_BUS_FMT_YUYV8_1X16:
+	case MEDIA_BUS_FMT_YVYU8_1X16:
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+	case MEDIA_BUS_FMT_VYUY8_1X16:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rockchip_afbc(struct drm_plane *plane, u64 modifier)
+{
+	int i;
+
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return false;
+
+	for (i = 0 ; i < plane->modifier_count; i++)
+		if (plane->modifiers[i] == modifier)
+			break;
+
+	return (i < plane->modifier_count) ? true : false;
+
+}
+
+static bool rockchip_vop2_mod_supported(struct drm_plane *plane, uint32_t format, u64 modifier)
+{
+	struct vop2_win *win = to_vop2_win(plane);
+	struct vop2 *vop2 = win->vop2;
+
+	if (modifier == DRM_FORMAT_MOD_INVALID)
+		return false;
+
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return true;
+
+	if (!rockchip_afbc(plane, modifier)) {
+		drm_err(vop2->drm, "Unsupported format modifier 0x%llx\n", modifier);
+
+		return false;
+	}
+
+	return vop2_convert_afbc_format(format) >= 0;
+}
+
+static int vop2_afbc_half_block_enable(struct drm_plane_state *pstate)
+{
+	if ((pstate->rotation & DRM_MODE_ROTATE_270) || (pstate->rotation & DRM_MODE_ROTATE_90))
+		return 0;
+	else
+		return 1;
+}
+
+static uint32_t vop2_afbc_transform_offset(struct drm_plane_state *pstate,
+					   bool afbc_half_block_en)
+{
+	struct drm_rect *src = &pstate->src;
+	struct drm_framebuffer *fb = pstate->fb;
+	uint32_t bpp = fb->format->cpp[0] * 8;
+	uint32_t vir_width = (fb->pitches[0] << 3) / bpp;
+	uint32_t width = drm_rect_width(src) >> 16;
+	uint32_t height = drm_rect_height(src) >> 16;
+	uint32_t act_xoffset = src->x1 >> 16;
+	uint32_t act_yoffset = src->y1 >> 16;
+	uint32_t align16_crop = 0;
+	uint32_t align64_crop = 0;
+	uint32_t height_tmp = 0;
+	uint32_t transform_tmp = 0;
+	uint8_t transform_xoffset = 0;
+	uint8_t transform_yoffset = 0;
+	uint8_t top_crop = 0;
+	uint8_t top_crop_line_num = 0;
+	uint8_t bottom_crop_line_num = 0;
+
+	/* 16 pixel align */
+	if (height & 0xf)
+		align16_crop = 16 - (height & 0xf);
+
+	height_tmp = height + align16_crop;
+
+	/* 64 pixel align */
+	if (height_tmp & 0x3f)
+		align64_crop = 64 - (height_tmp & 0x3f);
+
+	top_crop_line_num = top_crop << 2;
+	if (top_crop == 0)
+		bottom_crop_line_num = align16_crop + align64_crop;
+	else if (top_crop == 1)
+		bottom_crop_line_num = align16_crop + align64_crop + 12;
+	else if (top_crop == 2)
+		bottom_crop_line_num = align16_crop + align64_crop + 8;
+
+	switch (pstate->rotation &
+		(DRM_MODE_REFLECT_X |
+		 DRM_MODE_REFLECT_Y |
+		 DRM_MODE_ROTATE_90 |
+		 DRM_MODE_ROTATE_270)) {
+	case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
+		transform_tmp = act_xoffset + width;
+		transform_xoffset = 16 - (transform_tmp & 0xf);
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = (transform_tmp & 0xf);
+
+		break;
+	case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90:
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = vir_width - width - act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270:
+		transform_tmp = top_crop_line_num + act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case DRM_MODE_REFLECT_X:
+		transform_tmp = act_xoffset + width;
+		transform_xoffset = 16 - (transform_tmp & 0xf);
+		transform_tmp = top_crop_line_num + act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = transform_tmp & 0xf;
+
+		break;
+	case DRM_MODE_REFLECT_Y:
+		transform_tmp = act_xoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = transform_tmp & 0xf;
+
+		break;
+	case DRM_MODE_ROTATE_90:
+		transform_tmp = bottom_crop_line_num - act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case DRM_MODE_ROTATE_270:
+		transform_tmp = top_crop_line_num + act_yoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = vir_width - width - act_xoffset;
+		transform_yoffset = transform_tmp & 0xf;
+		break;
+	case 0:
+		transform_tmp = act_xoffset;
+		transform_xoffset = transform_tmp & 0xf;
+		transform_tmp = top_crop_line_num + act_yoffset;
+
+		if (afbc_half_block_en)
+			transform_yoffset = transform_tmp & 0x7;
+		else
+			transform_yoffset = transform_tmp & 0xf;
+
+		break;
+	}
+
+	return (transform_xoffset & 0xf) | ((transform_yoffset & 0xf) << 16);
+}
+
+/*
+ * A Cluster window has 2048 x 16 line buffer, which can
+ * works at 2048 x 16(Full) or 4096 x 8 (Half) mode.
+ * for Cluster_lb_mode register:
+ * 0: half mode, for plane input width range 2048 ~ 4096
+ * 1: half mode, for cluster work at 2 * 2048 plane mode
+ * 2: half mode, for rotate_90/270 mode
+ *
+ */
+static int vop2_get_cluster_lb_mode(struct vop2_win *win, struct drm_plane_state *pstate)
+{
+	if ((pstate->rotation & DRM_MODE_ROTATE_270) || (pstate->rotation & DRM_MODE_ROTATE_90))
+		return 2;
+	else
+		return 0;
+}
+
+/*
+ * bli_sd_factor = (src - 1) / (dst - 1) << 12;
+ * avg_sd_factor:
+ * bli_su_factor:
+ * bic_su_factor:
+ * = (src - 1) / (dst - 1) << 16;
+ *
+ * gt2 enable: dst get one line from two line of the src
+ * gt4 enable: dst get one line from four line of the src.
+ *
+ */
+static uint16_t vop2_scale_factor(enum scale_mode mode,
+				  int32_t filter_mode,
+				  uint32_t src, uint32_t dst)
+{
+	uint32_t fac;
+	int i;
+
+	if (mode == SCALE_NONE)
+		return 0;
+
+	/*
+	 * A workaround to avoid zero div.
+	 */
+	if (dst == 1 || src == 1) {
+		dst++;
+		src++;
+	}
+
+	if ((mode == SCALE_DOWN) && (filter_mode == VOP2_SCALE_DOWN_BIL)) {
+		fac = ((src - 1) << 12) / (dst - 1);
+		for (i = 0; i < 100; i++) {
+			if (fac * (dst - 1) >> 12 < (src - 1))
+				break;
+			fac -= 1;
+			DRM_DEBUG("down fac cali: src:%d, dst:%d, fac:0x%x\n", src, dst, fac);
+		}
+	} else {
+		fac = ((src - 1) << 16) / (dst - 1);
+		for (i = 0; i < 100; i++) {
+			if (fac * (dst - 1) >> 16 < (src - 1))
+				break;
+			fac -= 1;
+			DRM_DEBUG("up fac cali:  src:%d, dst:%d, fac:0x%x\n", src, dst, fac);
+		}
+	}
+
+	return fac;
+}
+
+static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win,
+			     uint32_t src_w, uint32_t src_h, uint32_t dst_w,
+			     uint32_t dst_h, uint32_t pixel_format)
+{
+	const struct vop2_win_data *win_data = win->data;
+	const struct drm_format_info *info;
+	uint16_t cbcr_src_w;
+	uint16_t cbcr_src_h;
+	uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode;
+	uint16_t cbcr_hor_scl_mode, cbcr_ver_scl_mode;
+	uint16_t hscl_filter_mode, vscl_filter_mode;
+	uint8_t gt2 = 0;
+	uint8_t gt4 = 0;
+	uint32_t val;
+
+	info = drm_format_info(pixel_format);
+
+	cbcr_src_w = src_w / info->hsub;
+	cbcr_src_h = src_h / info->vsub;
+
+	if (src_h >= (4 * dst_h)) {
+		gt4 = 1;
+		src_h >>= 2;
+	} else if (src_h >= (2 * dst_h)) {
+		gt2 = 1;
+		src_h >>= 1;
+	}
+
+	yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
+	yrgb_ver_scl_mode = scl_get_scl_mode(src_h, dst_h);
+
+	if (yrgb_hor_scl_mode == SCALE_UP)
+		hscl_filter_mode = win_data->hsu_filter_mode;
+	else
+		hscl_filter_mode = win_data->hsd_filter_mode;
+
+	if (yrgb_ver_scl_mode == SCALE_UP)
+		vscl_filter_mode = win_data->vsu_filter_mode;
+	else
+		vscl_filter_mode = win_data->vsd_filter_mode;
+
+	/*
+	 * RK3568 VOP Esmart/Smart dsp_w should be even pixel
+	 * at scale down mode
+	 */
+	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
+		if ((yrgb_hor_scl_mode == SCALE_DOWN) && (dst_w & 0x1)) {
+			drm_dbg(vop2->drm, "%s dst_w[%d] should align as 2 pixel\n",
+				win->data->name, dst_w);
+			dst_w += 1;
+		}
+	}
+
+	val = vop2_scale_factor(yrgb_hor_scl_mode, hscl_filter_mode,
+				src_w, dst_w);
+	vop2_win_write(win, &win->regs->scl->scale_yrgb_x, val);
+	val = vop2_scale_factor(yrgb_ver_scl_mode, vscl_filter_mode,
+				src_h, dst_h);
+	vop2_win_write(win, &win->regs->scl->scale_yrgb_y, val);
+
+	vop2_win_write(win, &win->regs->scl->vsd_yrgb_gt4, gt4);
+	vop2_win_write(win, &win->regs->scl->vsd_yrgb_gt2, gt2);
+
+	vop2_win_write(win, &win->regs->scl->yrgb_hor_scl_mode, yrgb_hor_scl_mode);
+	vop2_win_write(win, &win->regs->scl->yrgb_ver_scl_mode, yrgb_ver_scl_mode);
+
+	vop2_win_write(win, &win->regs->scl->yrgb_hscl_filter_mode, hscl_filter_mode);
+	vop2_win_write(win, &win->regs->scl->yrgb_vscl_filter_mode, vscl_filter_mode);
+
+	if (info->is_yuv) {
+		gt4 = gt2 = 0;
+
+		if (cbcr_src_h >= (4 * dst_h))
+			gt4 = 1;
+		else if (cbcr_src_h >= (2 * dst_h))
+			gt2 = 1;
+
+		if (gt4)
+			cbcr_src_h >>= 2;
+		else if (gt2)
+			cbcr_src_h >>= 1;
+
+		cbcr_hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w);
+		cbcr_ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h);
+
+		val = vop2_scale_factor(cbcr_hor_scl_mode, hscl_filter_mode,
+					cbcr_src_w, dst_w);
+		vop2_win_write(win, &win->regs->scl->scale_cbcr_x, val);
+		val = vop2_scale_factor(cbcr_ver_scl_mode, vscl_filter_mode,
+					cbcr_src_h, dst_h);
+		vop2_win_write(win, &win->regs->scl->scale_cbcr_y, val);
+
+		vop2_win_write(win, &win->regs->scl->vsd_cbcr_gt4, gt4);
+		vop2_win_write(win, &win->regs->scl->vsd_cbcr_gt2, gt2);
+		vop2_win_write(win, &win->regs->scl->cbcr_hor_scl_mode, cbcr_hor_scl_mode);
+		vop2_win_write(win, &win->regs->scl->cbcr_ver_scl_mode, cbcr_ver_scl_mode);
+		vop2_win_write(win, &win->regs->scl->cbcr_hscl_filter_mode, hscl_filter_mode);
+		vop2_win_write(win, &win->regs->scl->cbcr_vscl_filter_mode, vscl_filter_mode);
+	}
+}
+
+static int vop2_convert_csc_mode(int csc_mode)
+{
+	switch (csc_mode) {
+	case V4L2_COLORSPACE_SMPTE170M:
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+		return CSC_BT601L;
+	case V4L2_COLORSPACE_REC709:
+	case V4L2_COLORSPACE_SMPTE240M:
+	case V4L2_COLORSPACE_DEFAULT:
+		return CSC_BT709L;
+	case V4L2_COLORSPACE_JPEG:
+		return CSC_BT601F;
+	case V4L2_COLORSPACE_BT2020:
+		return CSC_BT2020;
+	default:
+		return CSC_BT709L;
+	}
+}
+
+/*
+ * colorspace path:
+ *      Input        Win csc                     Output
+ * 1. YUV(2020)  --> Y2R->2020To709->R2Y   --> YUV_OUTPUT(601/709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 2. YUV(2020)  --> bypasss               --> YUV_OUTPUT(2020)
+ *    RGB        --> 709To2020->R2Y       __/
+ *
+ * 3. YUV(2020)  --> Y2R->2020To709        --> RGB_OUTPUT(709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 4. YUV(601/709)-> Y2R->709To2020->R2Y   --> YUV_OUTPUT(2020)
+ *    RGB        --> 709To2020->R2Y       __/
+ *
+ * 5. YUV(601/709)-> bypass                --> YUV_OUTPUT(709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 6. YUV(601/709)-> bypass                --> YUV_OUTPUT(601)
+ *    RGB        --> R2Y(601)             __/
+ *
+ * 7. YUV        --> Y2R(709)              --> RGB_OUTPUT(709)
+ *    RGB        --> bypass               __/
+ *
+ * 8. RGB        --> 709To2020->R2Y        --> YUV_OUTPUT(2020)
+ *
+ * 9. RGB        --> R2Y(709)              --> YUV_OUTPUT(709)
+ *
+ * 10. RGB       --> R2Y(601)              --> YUV_OUTPUT(601)
+ *
+ * 11. RGB       --> bypass                --> RGB_OUTPUT(709)
+ */
+
+static void vop2_setup_csc_mode(struct vop2_video_port *vp,
+				struct vop2_win *win,
+				struct drm_plane_state *pstate)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);
+	int is_input_yuv = pstate->fb->format->is_yuv;
+	int is_output_yuv = is_yuv_output(vcstate->bus_format);
+	int input_csc = V4L2_COLORSPACE_DEFAULT;
+	int output_csc = vcstate->color_space;
+	bool r2y_en, y2r_en;
+	int csc_mode;
+
+	if (is_input_yuv && !is_output_yuv) {
+		y2r_en = 1;
+		r2y_en = 0;
+		csc_mode = vop2_convert_csc_mode(input_csc);
+	} else if (!is_input_yuv && is_output_yuv) {
+		y2r_en = 0;
+		r2y_en = 1;
+		csc_mode = vop2_convert_csc_mode(output_csc);
+	} else {
+		y2r_en = 0;
+		r2y_en = 0;
+		csc_mode = 0;
+	}
+
+	vop2_win_write(win, &win->regs->y2r_en, y2r_en);
+	vop2_win_write(win, &win->regs->r2y_en, r2y_en);
+	vop2_win_write(win, &win->regs->csc_mode, csc_mode);
+}
+
+static void vop2_crtc_enable_irq(struct vop2_video_port *vp, uint32_t irq)
+{
+	struct vop2 *vop2 = vp->vop2;
+
+	vop2_writel(vop2, vp->data->regs->irq_clear, irq << 16 | irq);
+	vop2_writel(vop2, vp->data->regs->irq_enable, irq << 16 | irq);
+}
+
+static void vop2_crtc_disable_irq(struct vop2_video_port *vp, uint32_t irq)
+{
+	struct vop2 *vop2 = vp->vop2;
+
+	vop2_writel(vop2, vp->data->regs->irq_enable, irq << 16);
+}
+
+static int vop2_core_clks_prepare_enable(struct vop2 *vop2)
+{
+	int ret;
+
+	ret = clk_prepare_enable(vop2->hclk);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to enable hclk - %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(vop2->aclk);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to enable aclk - %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+err:
+	clk_disable_unprepare(vop2->hclk);
+
+	return ret;
+}
+
+static void vop2_enable(struct vop2 *vop2)
+{
+	int ret;
+	uint32_t v;
+
+	ret = pm_runtime_get_sync(vop2->dev);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to get pm runtime: %d\n", ret);
+		return;
+	}
+
+	ret = vop2_core_clks_prepare_enable(vop2);
+	if (ret) {
+		pm_runtime_put_sync(vop2->dev);
+		return;
+	}
+
+	if (vop2->data->soc_id == 3566)
+		vop2_writel(vop2, RK3568_OTP_WIN_EN, 1);
+
+	memcpy(vop2->regsbak, vop2->regs, vop2->len);
+	vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
+
+	/*
+	 * Disable auto gating, this is a workaround to
+	 * avoid display image shift when a window enabled.
+	 */
+	v = vop2_readl(vop2, RK3568_SYS_AUTO_GATING_CTRL);
+	v &= ~RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN;
+	vop2_writel(vop2, RK3568_SYS_AUTO_GATING_CTRL, v);
+
+	vop2_writel(vop2, RK3568_SYS0_INT_CLR,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+	vop2_writel(vop2, RK3568_SYS0_INT_EN,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+	vop2_writel(vop2, RK3568_SYS1_INT_CLR,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+	vop2_writel(vop2, RK3568_SYS1_INT_EN,
+		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
+}
+
+static void vop2_disable(struct vop2 *vop2)
+{
+	pm_runtime_put_sync(vop2->dev);
+
+	clk_disable_unprepare(vop2->aclk);
+	clk_disable_unprepare(vop2->hclk);
+}
+
+static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
+				     struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	int ret;
+
+	vop2_lock(vop2);
+
+	drm_crtc_vblank_off(crtc);
+
+	/*
+	 * Vop standby will take effect at end of current frame,
+	 * if dsp hold valid irq happen, it means standby complete.
+	 *
+	 * we must wait standby complete when we want to disable aclk,
+	 * if not, memory bus maybe dead.
+	 */
+	reinit_completion(&vp->dsp_hold_completion);
+
+	vop2_crtc_enable_irq(vp, VP_INT_DSP_HOLD_VALID);
+	spin_lock(&vop2->reg_lock);
+
+	vop2_writel(vop2, vp->data->regs->dsp_ctrl, 1);
+
+	spin_unlock(&vop2->reg_lock);
+
+	ret = wait_for_completion_timeout(&vp->dsp_hold_completion, msecs_to_jiffies(50));
+	if (!ret)
+		drm_info(vop2->drm, "wait for vp%d dsp_hold timeout\n", vp->id);
+
+	vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID);
+
+	clk_disable_unprepare(vp->dclk);
+
+	vop2->enable_count--;
+
+	if (!vop2->enable_count)
+		vop2_disable(vop2);
+
+	vop2_unlock(vop2);
+
+	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 int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *astate)
+{
+	struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(astate, plane);
+	struct vop2_win *win = to_vop2_win(plane);
+	struct drm_framebuffer *fb = pstate->fb;
+	struct drm_crtc *crtc = pstate->crtc;
+	struct drm_crtc_state *cstate;
+	struct vop2_video_port *vp;
+	struct vop2 *vop2;
+	const struct vop2_data *vop2_data;
+	struct drm_rect *dest = &pstate->dst;
+	struct drm_rect *src = &pstate->src;
+	int min_scale = win->regs->scl ? FRAC_16_16(1, 8) : DRM_PLANE_HELPER_NO_SCALING;
+	int max_scale = win->regs->scl ? FRAC_16_16(8, 1) : DRM_PLANE_HELPER_NO_SCALING;
+	int format;
+	int ret;
+
+	if (!crtc)
+		return 0;
+
+	vp = to_vop2_video_port(crtc);
+	vop2 = vp->vop2;
+	vop2_data = vop2->data;
+
+	cstate = drm_atomic_get_existing_crtc_state(pstate->state, crtc);
+	if (WARN_ON(!cstate))
+		return -EINVAL;
+
+	ret = drm_atomic_helper_check_plane_state(pstate, cstate,
+						  min_scale, max_scale,
+						  true, true);
+	if (ret)
+		return ret;
+
+	if (!pstate->visible)
+		return 0;
+
+	format = vop2_convert_format(fb->format->format);
+	if (format < 0)
+		return format;
+
+	if (drm_rect_width(src) >> 16 < 4 || drm_rect_height(src) >> 16 < 4 ||
+	    drm_rect_width(dest) < 4 || drm_rect_width(dest) < 4) {
+		drm_err(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n",
+			  drm_rect_width(src) >> 16, drm_rect_height(src) >> 16,
+			  drm_rect_width(dest), drm_rect_height(dest));
+		pstate->visible = false;
+		return 0;
+	}
+
+	if (drm_rect_width(src) >> 16 > vop2_data->max_input.width ||
+	    drm_rect_height(src) >> 16 > vop2_data->max_input.height) {
+		drm_err(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n",
+			  drm_rect_width(src) >> 16,
+			  drm_rect_height(src) >> 16,
+			  vop2_data->max_input.width,
+			  vop2_data->max_input.height);
+		return -EINVAL;
+	}
+
+	/*
+	 * Src.x1 can be odd when do clip, but yuv plane start point
+	 * need align with 2 pixel.
+	 */
+	if (fb->format->is_yuv && ((pstate->src.x1 >> 16) % 2)) {
+		drm_err(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void vop2_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+	struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state, plane);
+	struct vop2_win *win = to_vop2_win(plane);
+	struct vop2 *vop2 = win->vop2;
+
+	drm_dbg(vop2->drm, "%s disable\n", win->data->name);
+
+	if (!old_pstate->crtc)
+		return;
+
+	spin_lock(&vop2->reg_lock);
+
+	vop2_win_disable(win);
+	vop2_win_write(win, &win->regs->yuv_clip, 0);
+
+	spin_unlock(&vop2->reg_lock);
+}
+
+/*
+ * The color key is 10 bit, so all format should
+ * convert to 10 bit here.
+ */
+static void vop2_plane_setup_color_key(struct drm_plane *plane, uint32_t color_key)
+{
+	struct drm_plane_state *pstate = plane->state;
+	struct drm_framebuffer *fb = pstate->fb;
+	struct vop2_win *win = to_vop2_win(plane);
+	uint32_t color_key_en = 0;
+	uint32_t r = 0;
+	uint32_t g = 0;
+	uint32_t b = 0;
+
+	if (!(color_key & VOP2_COLOR_KEY_MASK) || fb->format->is_yuv) {
+		vop2_win_write(win, &win->regs->color_key_en, 0);
+		return;
+	}
+
+	switch (fb->format->format) {
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		r = (color_key & 0xf800) >> 11;
+		g = (color_key & 0x7e0) >> 5;
+		b = (color_key & 0x1f);
+		r <<= 5;
+		g <<= 4;
+		b <<= 5;
+		color_key_en = 1;
+		break;
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		r = (color_key & 0xff0000) >> 16;
+		g = (color_key & 0xff00) >> 8;
+		b = (color_key & 0xff);
+		r <<= 2;
+		g <<= 2;
+		b <<= 2;
+		color_key_en = 1;
+		break;
+	}
+
+	vop2_win_write(win, &win->regs->color_key_en, color_key_en);
+	vop2_win_write(win, &win->regs->color_key, (r << 20) | (g << 10) | b);
+}
+
+static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+	struct drm_plane_state *pstate = plane->state;
+	struct drm_crtc *crtc = pstate->crtc;
+	struct vop2_win *win = to_vop2_win(plane);
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
+	struct vop2 *vop2 = win->vop2;
+	struct drm_framebuffer *fb = pstate->fb;
+	uint32_t bpp = fb->format->cpp[0] * 8;
+	uint32_t actual_w, actual_h, dsp_w, dsp_h;
+	uint32_t act_info, dsp_info;
+	uint32_t format;
+	uint32_t afbc_format;
+	uint32_t rb_swap;
+	uint32_t uv_swap;
+	struct drm_rect *src = &pstate->src;
+	struct drm_rect *dest = &pstate->dst;
+	uint32_t afbc_tile_num;
+	uint32_t afbc_half_block_en;
+	uint32_t transform_offset;
+	bool dither_up;
+	bool xmirror = pstate->rotation & DRM_MODE_REFLECT_X;
+	bool ymirror = pstate->rotation & DRM_MODE_REFLECT_Y;
+	bool rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270;
+	bool rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90;
+	struct rockchip_gem_object *rk_obj;
+	unsigned long offset;
+	bool afbc_en;
+	dma_addr_t yrgb_mst;
+	dma_addr_t uv_mst;
+
+	/*
+	 * can't update plane when vop2 is disabled.
+	 */
+	if (WARN_ON(!crtc))
+		return;
+
+	if (!pstate->visible) {
+		vop2_plane_atomic_disable(plane, state);
+		return;
+	}
+
+	afbc_en = rockchip_afbc(plane, fb->modifier);
+
+	offset = (src->x1 >> 16) * fb->format->cpp[0];
+
+	/*
+	 * AFBC HDR_PTR must set to the zero offset of the framebuffer.
+	 */
+	if (afbc_en)
+		offset = 0;
+	else if (pstate->rotation & DRM_MODE_REFLECT_Y)
+		offset += ((src->y2 >> 16) - 1) * fb->pitches[0];
+	else
+		offset += (src->y1 >> 16) * fb->pitches[0];
+
+	rk_obj = to_rockchip_obj(fb->obj[0]);
+
+	yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];
+	if (fb->format->is_yuv) {
+		int hsub = fb->format->hsub;
+		int vsub = fb->format->vsub;
+
+		offset = (src->x1 >> 16) * fb->format->cpp[1] / hsub;
+		offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
+
+		if ((pstate->rotation & DRM_MODE_REFLECT_Y) && !afbc_en)
+			offset += fb->pitches[1] * ((pstate->src_h >> 16) - 2)  / vsub;
+
+		rk_obj = to_rockchip_obj(fb->obj[0]);
+		uv_mst = rk_obj->dma_addr + offset + fb->offsets[1];
+	}
+
+	actual_w = drm_rect_width(src) >> 16;
+	actual_h = drm_rect_height(src) >> 16;
+	dsp_w = drm_rect_width(dest);
+
+	if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
+		drm_err(vop2->drm, "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",
+			  vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay);
+		dsp_w = adjusted_mode->hdisplay - dest->x1;
+		if (dsp_w < 4)
+			dsp_w = 4;
+		actual_w = dsp_w * actual_w / drm_rect_width(dest);
+	}
+
+	dsp_h = drm_rect_height(dest);
+
+	if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
+		drm_err(vop2->drm, "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
+			  vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
+		dsp_h = adjusted_mode->vdisplay - dest->y1;
+		if (dsp_h < 4)
+			dsp_h = 4;
+		actual_h = dsp_h * actual_h / drm_rect_height(dest);
+	}
+
+	/*
+	 * This is workaround solution for IC design:
+	 * esmart can't support scale down when actual_w % 16 == 1.
+	 */
+	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
+		if (actual_w > dsp_w && (actual_w & 0xf) == 1) {
+			drm_err(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n", vp->id, win->data->name, actual_w);
+			actual_w -= 1;
+		}
+	}
+
+	if (afbc_en && actual_w % 4) {
+		drm_err(vop2->drm, "vp%d %s actual_w[%d] should align as 4 pixel when enable afbc\n",
+			  vp->id, win->data->name, actual_w);
+		actual_w = ALIGN_DOWN(actual_w, 4);
+	}
+
+	act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
+	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
+
+	format = vop2_convert_format(fb->format->format);
+
+	spin_lock(&vop2->reg_lock);
+	drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n",
+		      vp->id, win->data->name, actual_w, actual_h, dsp_w, dsp_h,
+		      dest->x1, dest->y1,
+		      &fb->format->format,
+		      afbc_en ? "AFBC" : "", &yrgb_mst);
+
+	if (afbc_en) {
+		uint32_t stride;
+
+		/* the afbc superblock is 16 x 16 */
+		afbc_format = vop2_convert_afbc_format(fb->format->format);
+
+		/* Enable color transform for YTR */
+		if (fb->modifier & AFBC_FORMAT_MOD_YTR)
+			afbc_format |= (1 << 4);
+
+		afbc_tile_num = ALIGN(actual_w, 16) >> 4;
+
+		/*
+		 * AFBC pic_vir_width is count by pixel, this is different
+		 * with WIN_VIR_STRIDE.
+		 */
+		stride = (fb->pitches[0] << 3) / bpp;
+		if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270))
+			drm_err(vop2->drm, "vp%d %s stride[%d] must align as 64 pixel when enable xmirror/rotate_90/rotate_270[0x%x]\n",
+				  vp->id, win->data->name, stride, pstate->rotation);
+
+		rb_swap = vop2_afbc_rb_swap(fb->format->format);
+		uv_swap = vop2_afbc_uv_swap(fb->format->format);
+		/*
+		 * This is a workaround for crazy IC design, Cluster
+		 * and Esmart/Smart use different format configuration map:
+		 * YUV420_10BIT: 0x10 for Cluster, 0x14 for Esmart/Smart.
+		 *
+		 * This is one thing we can make the convert simple:
+		 * AFBCD decode all the YUV data to YUV444. So we just
+		 * set all the yuv 10 bit to YUV444_10.
+		 */
+		if (fb->format->is_yuv && (bpp == 10))
+			format = VOP2_CLUSTER_YUV444_10;
+
+		afbc_half_block_en = vop2_afbc_half_block_enable(pstate);
+		transform_offset = vop2_afbc_transform_offset(pstate, afbc_half_block_en);
+		if (vop2_cluster_window(win))
+			vop2_win_write(win, &win->regs->cluster->afbc_enable, 1);
+		vop2_win_write(win, &win->regs->afbc->format, afbc_format);
+		vop2_win_write(win, &win->regs->afbc->rb_swap, rb_swap);
+		vop2_win_write(win, &win->regs->afbc->uv_swap, uv_swap);
+		vop2_win_write(win, &win->regs->afbc->auto_gating_en, 0);
+		vop2_win_write(win, &win->regs->afbc->block_split_en, 0);
+		vop2_win_write(win, &win->regs->afbc->half_block_en, afbc_half_block_en);
+		vop2_win_write(win, &win->regs->afbc->hdr_ptr, yrgb_mst);
+		vop2_win_write(win, &win->regs->afbc->pic_size, act_info);
+		vop2_win_write(win, &win->regs->afbc->transform_offset, transform_offset);
+		vop2_win_write(win, &win->regs->afbc->pic_offset, ((src->x1 >> 16) | src->y1));
+		vop2_win_write(win, &win->regs->afbc->dsp_offset, (dest->x1 | (dest->y1 << 16)));
+		vop2_win_write(win, &win->regs->afbc->pic_vir_width, stride);
+		vop2_win_write(win, &win->regs->afbc->tile_num, afbc_tile_num);
+		vop2_win_write(win, &win->regs->afbc->xmirror, xmirror);
+		vop2_win_write(win, &win->regs->afbc->ymirror, ymirror);
+		vop2_win_write(win, &win->regs->afbc->rotate_270, rotate_270);
+		vop2_win_write(win, &win->regs->afbc->rotate_90, rotate_90);
+	} else {
+		if (win->regs->afbc)
+			vop2_win_write(win, &win->regs->afbc->enable, 0);
+		vop2_win_write(win, &win->regs->ymirror, ymirror);
+		vop2_win_write(win, &win->regs->xmirror, xmirror);
+		vop2_win_write(win, &win->regs->yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
+	}
+
+	if (rotate_90 || rotate_270) {
+		act_info = swahw32(act_info);
+		actual_w = drm_rect_height(src) >> 16;
+		actual_h = drm_rect_width(src) >> 16;
+	}
+
+	vop2_win_write(win, &win->regs->format, format);
+	vop2_win_write(win, &win->regs->yrgb_mst, yrgb_mst);
+
+	rb_swap = vop2_win_rb_swap(fb->format->format);
+	uv_swap = vop2_win_uv_swap(fb->format->format);
+	vop2_win_write(win, &win->regs->rb_swap, rb_swap);
+	vop2_win_write(win, &win->regs->uv_swap, uv_swap);
+
+	if (fb->format->is_yuv) {
+		vop2_win_write(win, &win->regs->uv_vir, DIV_ROUND_UP(fb->pitches[1], 4));
+		vop2_win_write(win, &win->regs->uv_mst, uv_mst);
+	}
+
+	vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format);
+	vop2_plane_setup_color_key(plane, 0);
+	vop2_win_write(win, &win->regs->act_info, act_info);
+	vop2_win_write(win, &win->regs->dsp_info, dsp_info);
+	vop2_win_write(win, &win->regs->dsp_st, dest->y1 << 16 | (dest->x1 & 0xffff));
+
+	vop2_setup_csc_mode(vp, win, pstate);
+
+	dither_up = vop2_win_dither_up(fb->format->format);
+	vop2_win_write(win, &win->regs->dither_up, dither_up);
+
+	vop2_win_write(win, &win->regs->enable, 1);
+
+	if (vop2_cluster_window(win)) {
+		int lb_mode = vop2_get_cluster_lb_mode(win, pstate);
+
+		vop2_win_write(win, &win->regs->cluster->lb_mode, lb_mode);
+		vop2_win_write(win, &win->regs->cluster->enable, 1);
+	}
+
+	spin_unlock(&vop2->reg_lock);
+}
+
+static const struct drm_plane_helper_funcs vop2_plane_helper_funcs = {
+	.atomic_check = vop2_plane_atomic_check,
+	.atomic_update = vop2_plane_atomic_update,
+	.atomic_disable = vop2_plane_atomic_disable,
+};
+
+static const struct drm_plane_funcs vop2_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.destroy = drm_plane_cleanup,
+	.reset = drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+	.format_mod_supported = rockchip_vop2_mod_supported,
+};
+
+static int vop2_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+
+	vop2_crtc_enable_irq(vp, VP_INT_FS_FIELD);
+
+	return 0;
+}
+
+static void vop2_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+
+	vop2_crtc_disable_irq(vp, VP_INT_FS_FIELD);
+}
+
+static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc,
+				 const struct drm_display_mode *mode,
+				 struct drm_display_mode *adj_mode)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+
+	drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE);
+
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		adj_mode->crtc_clock *= 2;
+
+	adj_mode->crtc_clock = DIV_ROUND_UP(clk_round_rate(vp->dclk,
+							   adj_mode->crtc_clock * 1000), 1000);
+
+	return true;
+}
+
+static void vop2_dither_setup(struct drm_crtc *crtc, uint32_t *dsp_ctrl)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+
+	switch (vcstate->bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
+		*dsp_ctrl |= RGB888_TO_RGB666;
+		break;
+	case MEDIA_BUS_FMT_YUV8_1X24:
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
+		break;
+	default:
+		break;
+	}
+
+	if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA)
+		*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
+
+	*dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
+				DITHER_DOWN_ALLEGRO);
+}
+
+static void vop2_post_config(struct drm_crtc *crtc)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	uint16_t vtotal = mode->crtc_vtotal;
+	uint16_t hdisplay = mode->crtc_hdisplay;
+	uint16_t hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
+	uint16_t vdisplay = mode->crtc_vdisplay;
+	uint16_t vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
+	uint32_t left_margin = 100, right_margin = 100, top_margin = 100, bottom_margin = 100;
+	uint16_t hsize = hdisplay * (left_margin + right_margin) / 200;
+	uint16_t vsize = vdisplay * (top_margin + bottom_margin) / 200;
+	uint16_t hact_end, vact_end;
+	uint32_t val;
+
+	vsize = rounddown(vsize, 2);
+	hsize = rounddown(hsize, 2);
+	hact_st += hdisplay * (100 - left_margin) / 200;
+	hact_end = hact_st + hsize;
+	val = hact_st << 16;
+	val |= hact_end;
+	vop2_writel(vop2, vp->regs->hpost_st_end, val);
+	vact_st += vdisplay * (100 - top_margin) / 200;
+	vact_end = vact_st + vsize;
+	val = vact_st << 16;
+	val |= vact_end;
+	vop2_writel(vop2, vp->regs->vpost_st_end, val);
+	val = scl_cal_scale2(vdisplay, vsize) << 16;
+	val |= scl_cal_scale2(hdisplay, hsize);
+	vop2_writel(vop2, vp->regs->post_scl_factor, val);
+
+	val = 0;
+	if (hdisplay != hsize)
+		val |= RK3568_VP_POST_SCL_CTRL__HSCALEDOWN;
+	if (vdisplay != vsize)
+		val |= RK3568_VP_POST_SCL_CTRL__VSCALEDOWN;
+	vop2_writel(vop2, RK3568_VP0_POST_SCL_CTRL, val);
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+		uint16_t vact_st_f1 = vtotal + vact_st + 1;
+		uint16_t vact_end_f1 = vact_st_f1 + vsize;
+
+		val = vact_st_f1 << 16 | vact_end_f1;
+		vop2_writel(vop2, vp->regs->vpost_st_end_f1, val);
+	}
+
+	vop2_writel(vop2, vp->regs->dsp_background, 0);
+}
+
+static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id,
+				uint32_t polflags)
+{
+	struct vop2 *vop2 = vp->vop2;
+	uint32_t die, dip;
+
+	die = vop2_readl(vop2, RK3568_DSP_IF_EN);
+	dip = vop2_readl(vop2, RK3568_DSP_IF_POL);
+
+	switch (id) {
+	case RK3568_VOP2_EP_RGB:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_RGB_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_RGB |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_RGB_MUX, vp->id);
+		if (polflags & POLFLAG_DCLK_INV)
+			vop2_grf_writel(vop2, &vop2->data->grf_ctrl->grf_dclk_inv, 1);
+		else
+			vop2_grf_writel(vop2, &vop2->data->grf_ctrl->grf_dclk_inv, 0);
+		break;
+	case RK3568_VOP2_EP_HDMI:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_HDMI_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_HDMI |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_HDMI_MUX, vp->id);
+		break;
+	case RK3568_VOP2_EP_EDP:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_EDP_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_EDP |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_EDP_MUX, vp->id);
+		break;
+	case RK3568_VOP2_EP_MIPI0:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_MIPI0 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags);
+		break;
+	case RK3568_VOP2_EP_MIPI1:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_MIPI1 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags);
+		break;
+	case RK3568_VOP2_EP_LVDS0:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_LVDS0 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);
+		break;
+	case RK3568_VOP2_EP_LVDS1:
+		die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX;
+		die |= RK3568_SYS_DSP_INFACE_EN_LVDS1 |
+			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX, vp->id);
+		dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;
+		dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);
+		break;
+	default:
+		return;
+	};
+
+	dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD;
+
+	vop2_writel(vop2, RK3568_DSP_IF_EN, die);
+	vop2_writel(vop2, RK3568_DSP_IF_POL, dip);
+}
+
+static int us_to_vertical_line(struct drm_display_mode *mode, int us)
+{
+	return us * mode->clock / mode->htotal / 1000;
+}
+
+static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	const struct vop2_data *vop2_data = vop2->data;
+	const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+	struct drm_display_mode *mode = &crtc->state->mode;
+	uint16_t hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+	uint16_t hdisplay = mode->crtc_hdisplay;
+	uint16_t htotal = mode->crtc_htotal;
+	uint16_t hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
+	uint16_t hact_end = hact_st + hdisplay;
+	uint16_t vdisplay = mode->crtc_vdisplay;
+	uint16_t vtotal = mode->crtc_vtotal;
+	uint16_t vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+	uint16_t vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
+	uint16_t vact_end = vact_st + vdisplay;
+	uint8_t out_mode;
+	uint32_t dsp_ctrl = 0;
+	int act_end;
+	uint32_t val, polflags;
+	int ret;
+	struct drm_encoder *encoder;
+
+	drm_dbg(vop2->drm, "Update mode to %dx%d%s%d, type: %d for vp%d\n",
+		hdisplay, vdisplay, mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p",
+		drm_mode_vrefresh(mode), vcstate->output_type, vp->id);
+
+	vop2_lock(vop2);
+
+	ret = clk_prepare_enable(vp->dclk);
+	if (ret < 0) {
+		drm_err(vop2->drm, "failed to enable dclk for video port%d - %d\n",
+			      vp->id, ret);
+		return;
+	}
+
+	if (!vop2->enable_count)
+		vop2_enable(vop2);
+
+	vop2->enable_count++;
+
+	vop2_crtc_enable_irq(vp, VP_INT_POST_BUF_EMPTY);
+
+	polflags = 0;
+	if (vcstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
+		polflags |= POLFLAG_DCLK_INV;
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		polflags |= BIT(HSYNC_POSITIVE);
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		polflags |= BIT(VSYNC_POSITIVE);
+
+	drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) {
+		struct device_node *node, *parent;
+
+		parent = of_get_parent(encoder->port);
+
+		for_each_endpoint_of_node(parent, node) {
+			struct device_node *crtc_port = of_graph_get_remote_port(node);
+			struct device_node *epn;
+			struct of_endpoint endpoint;
+
+			if (crtc->port != crtc_port) {
+				of_node_put(crtc_port);
+				continue;
+			}
+
+			of_node_put(crtc_port);
+
+			epn = of_graph_get_remote_endpoint(node);
+			of_graph_parse_endpoint(epn, &endpoint);
+			of_node_put(epn);
+
+			drm_dbg(vop2->drm, "vp%d is connected to %s, id %d\n",
+					   vp->id, encoder->name, endpoint.id);
+			rk3568_set_intf_mux(vp, endpoint.id, polflags);
+		}
+		of_node_put(parent);
+	}
+
+	if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
+	     !(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT))
+		out_mode = ROCKCHIP_OUT_MODE_P888;
+	else
+		out_mode = vcstate->output_mode;
+
+	dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__OUT_MODE, out_mode);
+
+	if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode))
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RB_SWAP;
+
+	if (is_yuv_output(vcstate->bus_format))
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y;
+
+	vop2_dither_setup(crtc, &dsp_ctrl);
+
+	vop2_writel(vop2, vp->regs->htotal_pw, (htotal << 16) | hsync_len);
+	val = hact_st << 16;
+	val |= hact_end;
+	vop2_writel(vop2, vp->regs->hact_st_end, val);
+
+	val = vact_st << 16;
+	val |= vact_end;
+	vop2_writel(vop2, vp->regs->vact_st_end, val);
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+		uint16_t vact_st_f1 = vtotal + vact_st + 1;
+		uint16_t vact_end_f1 = vact_st_f1 + vdisplay;
+
+		val = vact_st_f1 << 16 | vact_end_f1;
+		vop2_writel(vop2, vp->regs->vact_st_end_f1, val);
+
+		val = vtotal << 16 | (vtotal + vsync_len);
+		vop2_writel(vop2, vp->regs->vs_st_end_f1, val);
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_INTERLACE;
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_FILED_POL;
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__P2I_EN;
+		vtotal += vtotal + 1;
+		act_end = vact_end_f1;
+	} else {
+		act_end = vact_end;
+	}
+
+	vop2_writel(vop2, vp->data->regs->line_flag,
+		    (act_end - us_to_vertical_line(mode, 0)) << 16 | act_end);
+
+	vop2_writel(vop2, vp->regs->vtotal_pw, vtotal << 16 | vsync_len);
+
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV;
+
+	vop2_writel(vop2, vp->regs->mipi_ctrl, 0);
+
+	clk_set_rate(vp->dclk, mode->crtc_clock * 1000);
+
+	vop2_post_config(crtc);
+
+	vop2_cfg_done(vp);
+
+	vop2_writel(vop2, vp->regs->dsp_ctrl, dsp_ctrl);
+
+	drm_crtc_vblank_on(crtc);
+
+	vop2_unlock(vop2);
+}
+
+static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
+				  struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct drm_plane *plane;
+	int nplanes = 0;
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+
+	drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
+		nplanes++;
+
+	if (nplanes > vp->nlayers)
+		return -EINVAL;
+
+	return 0;
+}
+
+static bool is_opaque(uint16_t alpha)
+{
+	return (alpha >> 8) == 0xff;
+}
+
+static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config,
+			     struct vop2_alpha *alpha)
+{
+	int src_glb_alpha_en = is_opaque(alpha_config->src_glb_alpha_value) ? 0 : 1;
+	int dst_glb_alpha_en = is_opaque(alpha_config->dst_glb_alpha_value) ? 0 : 1;
+	int src_color_mode = alpha_config->src_premulti_en ? ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL;
+	int dst_color_mode = alpha_config->dst_premulti_en ? ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL;
+
+	alpha->src_color_ctrl.val = 0;
+	alpha->dst_color_ctrl.val = 0;
+	alpha->src_alpha_ctrl.val = 0;
+	alpha->dst_alpha_ctrl.val = 0;
+
+	if (!alpha_config->src_pixel_alpha_en)
+		alpha->src_color_ctrl.bits.blend_mode = ALPHA_GLOBAL;
+	else if (alpha_config->src_pixel_alpha_en && !src_glb_alpha_en)
+		alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX;
+	else
+		alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL;
+
+	alpha->src_color_ctrl.bits.alpha_en = 1;
+
+	if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_GLOBAL) {
+		alpha->src_color_ctrl.bits.color_mode = src_color_mode;
+		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL;
+	} else if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_PER_PIX) {
+		alpha->src_color_ctrl.bits.color_mode = src_color_mode;
+		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_ONE;
+	} else {
+		alpha->src_color_ctrl.bits.color_mode = ALPHA_SRC_PRE_MUL;
+		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL;
+	}
+	alpha->src_color_ctrl.bits.glb_alpha = alpha_config->src_glb_alpha_value >> 8;
+	alpha->src_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	alpha->src_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
+
+	alpha->dst_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	alpha->dst_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
+	alpha->dst_color_ctrl.bits.blend_mode = ALPHA_GLOBAL;
+	alpha->dst_color_ctrl.bits.glb_alpha = alpha_config->dst_glb_alpha_value >> 8;
+	alpha->dst_color_ctrl.bits.color_mode = dst_color_mode;
+	alpha->dst_color_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
+
+	alpha->src_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	alpha->src_alpha_ctrl.bits.blend_mode = alpha->src_color_ctrl.bits.blend_mode;
+	alpha->src_alpha_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
+	alpha->src_alpha_ctrl.bits.factor_mode = ALPHA_ONE;
+
+	alpha->dst_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
+	if (alpha_config->dst_pixel_alpha_en && !dst_glb_alpha_en)
+		alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX;
+	else
+		alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL;
+	alpha->dst_alpha_ctrl.bits.alpha_cal_mode = ALPHA_NO_SATURATION;
+	alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
+}
+
+static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, uint8_t port_id)
+{
+	struct vop2_video_port *vp;
+	int used_layer = 0;
+	int i;
+
+	for (i = 0; i < port_id; i++) {
+		vp = &vop2->vps[i];
+		used_layer += hweight32(vp->win_mask);
+	}
+
+	return used_layer;
+}
+
+static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win)
+{
+	uint32_t offset = (main_win->data->phys_id * 0x10);
+	struct vop2_alpha_config alpha_config;
+	struct vop2_alpha alpha;
+	struct drm_plane_state *top_win_pstate;
+	struct drm_plane_state *bottom_win_pstate;
+	bool src_pixel_alpha_en = false;
+	uint16_t src_glb_alpha_val, dst_glb_alpha_val;
+	bool premulti_en = false;
+	bool swap = false;
+
+	/* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */
+	top_win_pstate = NULL;
+	bottom_win_pstate = main_win->base.state;
+	src_glb_alpha_val = 0;
+	dst_glb_alpha_val = main_win->base.state->alpha;
+
+	if (!bottom_win_pstate->fb)
+		return;
+
+	alpha_config.src_premulti_en = premulti_en;
+	alpha_config.dst_premulti_en = false;
+	alpha_config.src_pixel_alpha_en = src_pixel_alpha_en;
+	alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
+	alpha_config.src_glb_alpha_value = src_glb_alpha_val;
+	alpha_config.dst_glb_alpha_value = dst_glb_alpha_val;
+	vop2_parse_alpha(&alpha_config, &alpha);
+
+	alpha.src_color_ctrl.bits.src_dst_swap = swap;
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset,
+		    alpha.src_color_ctrl.val);
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset,
+		    alpha.dst_color_ctrl.val);
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset,
+		    alpha.src_alpha_ctrl.val);
+	vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset,
+		    alpha.dst_alpha_ctrl.val);
+}
+
+static void vop2_setup_alpha(struct vop2_video_port *vp)
+{
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_framebuffer *fb;
+	struct vop2_alpha_config alpha_config;
+	struct vop2_alpha alpha;
+	struct drm_plane *plane;
+	int pixel_alpha_en;
+	int premulti_en, gpremulti_en = 0;
+	int mixer_id;
+	uint32_t offset;
+	bool bottom_layer_alpha_en = false;
+	uint32_t dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE;
+
+	mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id);
+	alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
+
+	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+
+		if (plane->state->normalized_zpos == 0 &&
+		    !is_opaque(plane->state->alpha) &&
+		    !vop2_cluster_window(win)) {
+			/*
+			 * If bottom layer have global alpha effect [except cluster layer,
+			 * because cluster have deal with bottom layer global alpha value
+			 * at cluster mix], bottom layer mix need deal with global alpha.
+			 */
+			bottom_layer_alpha_en = true;
+			dst_global_alpha = plane->state->alpha;
+		}
+	}
+
+	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+		int zpos = plane->state->normalized_zpos;
+
+		if (plane->state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
+			premulti_en = 1;
+		else
+			premulti_en = 0;
+
+		plane = &win->base;
+		fb = plane->state->fb;
+
+		pixel_alpha_en = fb->format->has_alpha;
+
+		alpha_config.src_premulti_en = premulti_en;
+
+		if (bottom_layer_alpha_en && zpos == 1) {
+			gpremulti_en = premulti_en;
+			/* Cd = Cs + (1 - As) * Cd * Agd */
+			alpha_config.dst_premulti_en = false;
+			alpha_config.src_pixel_alpha_en = pixel_alpha_en;
+			alpha_config.src_glb_alpha_value = plane->state->alpha;
+			alpha_config.dst_glb_alpha_value = dst_global_alpha;
+		} else if (vop2_cluster_window(win)) {
+			/* Mix output data only have pixel alpha */
+			alpha_config.dst_premulti_en = true;
+			alpha_config.src_pixel_alpha_en = true;
+			alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+		} else {
+			/* Cd = Cs + (1 - As) * Cd */
+			alpha_config.dst_premulti_en = true;
+			alpha_config.src_pixel_alpha_en = pixel_alpha_en;
+			alpha_config.src_glb_alpha_value = plane->state->alpha;
+			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+		}
+
+		vop2_parse_alpha(&alpha_config, &alpha);
+
+		offset = (mixer_id + zpos - 1) * 0x10;
+		vop2_writel(vop2, RK3568_MIX0_SRC_COLOR_CTRL + offset,
+			    alpha.src_color_ctrl.val);
+		vop2_writel(vop2, RK3568_MIX0_DST_COLOR_CTRL + offset,
+			    alpha.dst_color_ctrl.val);
+		vop2_writel(vop2, RK3568_MIX0_SRC_ALPHA_CTRL + offset,
+			    alpha.src_alpha_ctrl.val);
+		vop2_writel(vop2, RK3568_MIX0_DST_ALPHA_CTRL + offset,
+			    alpha.dst_alpha_ctrl.val);
+	}
+
+	if (vp->id == 0) {
+		if (bottom_layer_alpha_en) {
+			/* Transfer pixel alpha to hdr mix */
+			alpha_config.src_premulti_en = gpremulti_en;
+			alpha_config.dst_premulti_en = true;
+			alpha_config.src_pixel_alpha_en = true;
+			alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
+			vop2_parse_alpha(&alpha_config, &alpha);
+
+			vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL,
+				alpha.src_color_ctrl.val);
+			vop2_writel(vop2, RK3568_HDR0_DST_COLOR_CTRL,
+				alpha.dst_color_ctrl.val);
+			vop2_writel(vop2, RK3568_HDR0_SRC_ALPHA_CTRL,
+				alpha.src_alpha_ctrl.val);
+			vop2_writel(vop2, RK3568_HDR0_DST_ALPHA_CTRL,
+				alpha.dst_alpha_ctrl.val);
+		} else {
+			vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, 0);
+		}
+	}
+}
+
+#define NR_VPS		3
+#define NR_MIXERS	6
+
+static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
+{
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_plane *plane;
+	uint32_t layer_sel = 0;
+	uint32_t port_sel;
+	int nlayer, ofs;
+	struct drm_display_mode *adjusted_mode;
+	uint16_t hsync_len;
+	uint16_t hdisplay;
+	uint32_t bg_dly;
+	uint32_t pre_scan_dly;
+	int i;
+	struct vop2_video_port *vp0 = &vop2->vps[0];
+	struct vop2_video_port *vp1 = &vop2->vps[1];
+	struct vop2_video_port *vp2 = &vop2->vps[2];
+
+	adjusted_mode = &vp->crtc.state->adjusted_mode;
+	hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
+	hdisplay = adjusted_mode->crtc_hdisplay;
+
+	bg_dly = vp->data->pre_scan_max_dly[3];
+	vop2_writel(vop2, vp->regs->bg_mix_ctrl,
+			    FIELD_PREP(RK3568_VP_BG_MIX_CTRL__BG_DLY, bg_dly));
+
+	pre_scan_dly = ((bg_dly + (hdisplay >> 1) - 1) << 16) | hsync_len;
+	vop2_writel(vop2, vp->regs->pre_scan_htiming, pre_scan_dly);
+
+	vop2_writel(vop2, RK3568_OVL_CTRL, 0);
+	port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
+	port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT;
+
+	if (vp0->nlayers)
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX,
+				     vp0->nlayers - 1);
+	else
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, 8);
+
+	if (vp1->nlayers)
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX,
+				     (vp0->nlayers + vp1->nlayers - 1));
+	else
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8);
+
+	if (vp2->nlayers)
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX,
+			(vp2->nlayers + vp1->nlayers + vp0->nlayers - 1));
+	else
+		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8);
+
+	layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
+
+	ofs = 0;
+	for (i = 0; i < vp->id; i++)
+		ofs += vop2->vps[i].nlayers;
+
+	nlayer = 0;
+	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+
+		switch (win->data->phys_id) {
+		case ROCKCHIP_VOP2_CLUSTER0:
+			port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER0;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER0, vp->id);
+			break;
+		case ROCKCHIP_VOP2_CLUSTER1:
+			port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER1;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER1, vp->id);
+			break;
+		case ROCKCHIP_VOP2_ESMART0:
+			port_sel &= ~RK3568_OVL_PORT_SEL__ESMART0;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART0, vp->id);
+			break;
+		case ROCKCHIP_VOP2_ESMART1:
+			port_sel &= ~RK3568_OVL_PORT_SEL__ESMART1;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART1, vp->id);
+			break;
+		case ROCKCHIP_VOP2_SMART0:
+			port_sel &= ~RK3568_OVL_PORT_SEL__SMART0;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART0, vp->id);
+			break;
+		case ROCKCHIP_VOP2_SMART1:
+			port_sel &= ~RK3568_OVL_PORT_SEL__SMART1;
+			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART1, vp->id);
+			break;
+		}
+
+		layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7);
+		layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, win->data->layer_sel_id);
+		nlayer++;
+	}
+
+	/* configure unused layers to 0x5 (reserved) */
+	for (; nlayer < 3; nlayer++) {
+		layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7);
+		layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 5);
+	}
+
+	vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
+	vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
+	vop2_writel(vop2, RK3568_OVL_CTRL, RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD);
+}
+
+static void vop2_setup_dly_for_windows(struct vop2 *vop2)
+{
+	struct vop2_win *win;
+	int i = 0;
+	uint32_t cdly = 0, sdly = 0;
+
+	for (i = 0; i < vop2->data->win_size; i++) {
+		uint32_t dly;
+
+		win = &vop2->win[i];
+		dly = win->delay;
+
+		switch (win->data->phys_id) {
+		case ROCKCHIP_VOP2_CLUSTER0:
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_0, dly);
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_1, dly);
+			break;
+		case ROCKCHIP_VOP2_CLUSTER1:
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_0, dly);
+			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_1, dly);
+			break;
+		case ROCKCHIP_VOP2_ESMART0:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART0, dly);
+			break;
+		case ROCKCHIP_VOP2_ESMART1:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART1, dly);
+			break;
+		case ROCKCHIP_VOP2_SMART0:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly);
+			break;
+		case ROCKCHIP_VOP2_SMART1:
+			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly);
+			break;
+		}
+	}
+
+	vop2_writel(vop2, RK3568_CLUSTER_DLY_NUM, cdly);
+	vop2_writel(vop2, RK3568_SMART_DLY_NUM, sdly);
+}
+
+static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+	struct drm_plane *plane;
+
+	vp->win_mask = 0;
+
+	drm_atomic_crtc_for_each_plane(plane, crtc) {
+		struct vop2_win *win = to_vop2_win(plane);
+
+		win->delay = win->data->dly[VOP2_DLY_MODE_DEFAULT];
+
+		vp->win_mask |= BIT(win->data->phys_id);
+
+		if (vop2_cluster_window(win))
+			vop2_setup_cluster_alpha(vop2, win);
+	}
+
+	if (!vp->win_mask)
+		return;
+
+	vop2_setup_layer_mixer(vp);
+	vop2_setup_alpha(vp);
+	vop2_setup_dly_for_windows(vop2);
+}
+
+static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state)
+{
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	struct vop2 *vop2 = vp->vop2;
+
+	spin_lock(&vop2->reg_lock);
+
+	vop2_post_config(crtc);
+
+	spin_unlock(&vop2->reg_lock);
+
+	vop2_cfg_done(vp);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+
+	if (crtc->state->event) {
+		WARN_ON(drm_crtc_vblank_get(crtc));
+		vp->event = crtc->state->event;
+		crtc->state->event = NULL;
+	}
+
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = {
+	.mode_fixup = vop2_crtc_mode_fixup,
+	.atomic_check = vop2_crtc_atomic_check,
+	.atomic_begin = vop2_crtc_atomic_begin,
+	.atomic_flush = vop2_crtc_atomic_flush,
+	.atomic_enable = vop2_crtc_atomic_enable,
+	.atomic_disable = vop2_crtc_atomic_disable,
+};
+
+static void vop2_crtc_reset(struct drm_crtc *crtc)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+
+	if (crtc->state) {
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
+		kfree(vcstate);
+	}
+
+	vcstate = kzalloc(sizeof(*vcstate), GFP_KERNEL);
+	if (!vcstate)
+		return;
+
+	crtc->state = &vcstate->base;
+	crtc->state->crtc = crtc;
+}
+
+static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct rockchip_crtc_state *vcstate, *old_vcstate;
+
+	old_vcstate = to_rockchip_crtc_state(crtc->state);
+
+	vcstate = kmemdup(old_vcstate, sizeof(*old_vcstate), GFP_KERNEL);
+	if (!vcstate)
+		return NULL;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base);
+
+	return &vcstate->base;
+}
+
+static void vop2_crtc_destroy_state(struct drm_crtc *crtc,
+				    struct drm_crtc_state *state)
+{
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state);
+
+	__drm_atomic_helper_crtc_destroy_state(&vcstate->base);
+	kfree(vcstate);
+}
+
+static const struct drm_crtc_funcs vop2_crtc_funcs = {
+	.set_config = drm_atomic_helper_set_config,
+	.page_flip = drm_atomic_helper_page_flip,
+	.destroy = drm_crtc_cleanup,
+	.reset = vop2_crtc_reset,
+	.atomic_duplicate_state = vop2_crtc_duplicate_state,
+	.atomic_destroy_state = vop2_crtc_destroy_state,
+	.enable_vblank = vop2_crtc_enable_vblank,
+	.disable_vblank = vop2_crtc_disable_vblank,
+};
+
+static irqreturn_t vop2_isr(int irq, void *data)
+{
+	struct vop2 *vop2 = data;
+	const struct vop2_data *vop2_data = vop2->data;
+	uint32_t axi_irqs[VOP2_SYS_AXI_BUS_NUM];
+	int ret = IRQ_NONE;
+	int i;
+
+	/*
+	 * The irq is shared with the iommu. If the runtime-pm state of the
+	 * vop2-device is disabled the irq has to be targeted at the iommu.
+	 */
+	if (!pm_runtime_get_if_in_use(vop2->dev))
+		return IRQ_NONE;
+
+	for (i = 0; i < vop2_data->nr_vps; i++) {
+		struct vop2_video_port *vp = &vop2->vps[i];
+		struct drm_crtc *crtc = &vp->crtc;
+		uint32_t irqs;
+
+		irqs = vop2_readl(vop2, vp->data->regs->irq_status);
+		vop2_writel(vop2, vp->data->regs->irq_clear, irqs << 16 | irqs);
+
+		if (irqs & VP_INT_DSP_HOLD_VALID) {
+			complete(&vp->dsp_hold_completion);
+			ret = IRQ_HANDLED;
+		}
+
+		if (irqs & VP_INT_FS_FIELD) {
+			unsigned long flags;
+
+			drm_crtc_handle_vblank(crtc);
+			spin_lock_irqsave(&crtc->dev->event_lock, flags);
+			if (vp->event) {
+				uint32_t val = vop2_readl(vop2, RK3568_REG_CFG_DONE);
+				if (!(val & BIT(vp->id))) {
+					drm_crtc_send_vblank_event(crtc, vp->event);
+					vp->event = NULL;
+					drm_crtc_vblank_put(crtc);
+				}
+			}
+			spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
+			ret = IRQ_HANDLED;
+		}
+
+		if (irqs & VP_INT_POST_BUF_EMPTY) {
+			drm_err_ratelimited(vop2->drm,
+					    "POST_BUF_EMPTY irq err at vp%d\n",
+					    vp->id);
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	axi_irqs[0] = vop2_readl(vop2, RK3568_SYS0_INT_STATUS);
+	vop2_writel(vop2, RK3568_SYS0_INT_CLR, axi_irqs[0] << 16 | axi_irqs[0]);
+	axi_irqs[1] = vop2_readl(vop2, RK3568_SYS1_INT_STATUS);
+	vop2_writel(vop2, RK3568_SYS1_INT_CLR, axi_irqs[1] << 16 | axi_irqs[1]);
+
+	for (i = 0; i < ARRAY_SIZE(axi_irqs); i++) {
+		if (axi_irqs[i] & VOP2_INT_BUS_ERRPR) {
+			drm_err_ratelimited(vop2->drm, "BUS_ERROR irq err\n");
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	pm_runtime_put(vop2->dev);
+
+	return ret;
+}
+
+static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned long possible_crtcs)
+{
+	const struct vop2_win_data *win_data = win->data;
+	unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) | BIT(DRM_MODE_BLEND_PREMULTI) |
+				  BIT(DRM_MODE_BLEND_COVERAGE);
+	int ret;
+
+	ret = drm_universal_plane_init(vop2->drm, &win->base, possible_crtcs,
+				       &vop2_plane_funcs, win_data->formats, win_data->nformats,
+				       win_data->format_modifiers, win->type, win_data->name);
+	if (ret) {
+		drm_err(vop2->drm, "failed to initialize plane %d\n", ret);
+		return ret;
+	}
+
+	drm_plane_helper_add(&win->base, &vop2_plane_helper_funcs);
+
+	if (win->data->supported_rotations)
+		drm_plane_create_rotation_property(&win->base, DRM_MODE_ROTATE_0,
+						   DRM_MODE_ROTATE_0 |
+						   win->data->supported_rotations);
+	drm_plane_create_alpha_property(&win->base);
+	drm_plane_create_blend_mode_property(&win->base, blend_caps);
+	drm_plane_create_zpos_property(&win->base, win->win_id, 0,
+				       vop2->registered_num_wins - 1);
+
+	return 0;
+}
+
+static struct vop2_video_port *get_activated_vp(struct vop2 *vop2, int n)
+{
+	int i, id = 0;
+
+	for (i = 0; i < vop2->data->nr_vps; i++) {
+		struct vop2_video_port *vp = &vop2->vps[i];
+
+		if (!vp->crtc.port)
+			continue;
+
+		if (n == id)
+			return vp;
+		id++;
+	}
+
+	return NULL;
+}
+
+static int vop2_create_crtc(struct vop2 *vop2)
+{
+	const struct vop2_data *vop2_data = vop2->data;
+	struct drm_device *drm = vop2->drm;
+	struct device *dev = vop2->dev;
+	struct drm_plane *plane;
+	struct device_node *port;
+	struct vop2_video_port *vp;
+	uint32_t possible_crtcs;
+	int i, nvp, nvps = 0;
+	int ret;
+
+	for (i = 0; i < vop2_data->nr_vps; i++) {
+		const struct vop2_video_port_data *vp_data;
+		struct device_node *np;
+		char dclk_name[9];
+
+		vp_data = &vop2_data->vp[i];
+		vp = &vop2->vps[i];
+		vp->vop2 = vop2;
+		vp->id = vp_data->id;
+		vp->regs = vp_data->regs;
+		vp->data = vp_data;
+
+		snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id);
+		vp->dclk = devm_clk_get(vop2->dev, dclk_name);
+		if (IS_ERR(vp->dclk)) {
+			drm_err(vop2->drm, "failed to get %s\n", dclk_name);
+			return PTR_ERR(vp->dclk);
+		}
+
+		np = of_graph_get_remote_node(dev->of_node, i, -1);
+		if (!np) {
+			printk("%s: No remote for vp%d\n", __func__, i);
+			continue;
+		}
+		of_node_put(np);
+
+		port = of_graph_get_port_by_id(dev->of_node, i);
+		if (!port) {
+			drm_err(vop2->drm, "no port node found for video_port%d\n", i);
+			return -ENOENT;
+		}
+
+		vp->crtc.port = port;
+		nvps++;
+	}
+
+	nvp = 0;
+	for (i = 0; i < vop2->registered_num_wins; i++) {
+		struct vop2_win *win = &vop2->win[i];
+
+		if (win->type == DRM_PLANE_TYPE_PRIMARY) {
+			vp = get_activated_vp(vop2, nvp);
+
+			if (vp) {
+				possible_crtcs = BIT(nvp);
+				vp->primary_plane = win;
+
+				nvp++;
+			} else {
+				/* change the unused primary window to overlay window */
+				win->type = DRM_PLANE_TYPE_OVERLAY;
+			}
+		}
+
+		if (win->type == DRM_PLANE_TYPE_OVERLAY)
+			possible_crtcs = (1 << vop2_data->nr_vps) - 1;
+
+		ret = vop2_plane_init(vop2, win, possible_crtcs);
+
+		if (ret) {
+			drm_err(vop2->drm, "failed to init plane %s: %d\n", win->data->name, ret);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < vop2_data->nr_vps; i++) {
+		vp = &vop2->vps[i];
+
+		if (!vp->crtc.port)
+			continue;
+
+		plane = &vp->primary_plane->base;
+
+		ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL, &vop2_crtc_funcs,
+						"video_port%d", vp->id);
+		if (ret) {
+			drm_err(vop2->drm, "crtc init for video_port%d failed\n", i);
+			return ret;
+		}
+
+		drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);
+
+		init_completion(&vp->dsp_hold_completion);
+	}
+
+	for (i = 0; i < vop2->data->nr_vps; i++) {
+		struct vop2_video_port *vp = &vop2->vps[i];
+		if (vp->crtc.port)
+			vp->nlayers = NR_MIXERS / nvps;
+	}
+
+	return 0;
+}
+
+static void vop2_destroy_crtc(struct drm_crtc *crtc)
+{
+	of_node_put(crtc->port);
+
+	/*
+	 * Destroy CRTC after vop2_plane_destroy() since vop2_disable_plane()
+	 * references the CRTC.
+	 */
+	drm_crtc_cleanup(crtc);
+}
+
+static int vop2_win_init(struct vop2 *vop2)
+{
+	const struct vop2_data *vop2_data = vop2->data;
+	struct vop2_win *win;
+	unsigned int i;
+
+	for (i = 0; i < vop2_data->win_size; i++) {
+		const struct vop2_win_data *win_data = &vop2_data->win[i];
+
+		win = &vop2->win[i];
+		win->data = win_data;
+		win->type = win_data->type;
+		win->regs = win_data->regs;
+		win->offset = win_data->base;
+		win->win_id = i;
+		win->vop2 = vop2;
+	}
+
+	vop2->registered_num_wins = vop2_data->win_size;
+
+	return 0;
+}
+
+static int vop2_bind(struct device *dev, struct device *master, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct vop2_data *vop2_data;
+	struct drm_device *drm = data;
+	struct vop2 *vop2;
+	struct resource *res;
+	size_t alloc_size;
+	int ret;
+
+	vop2_data = of_device_get_match_data(dev);
+	if (!vop2_data)
+		return -ENODEV;
+
+	/* Allocate vop2 struct and its vop2_win array */
+	alloc_size = sizeof(*vop2) + sizeof(*vop2->win) * vop2_data->win_size;
+	vop2 = devm_kzalloc(dev, alloc_size, GFP_KERNEL);
+	if (!vop2)
+		return -ENOMEM;
+
+	vop2->dev = dev;
+	vop2->data = vop2_data;
+	vop2->drm = drm;
+
+	dev_set_drvdata(dev, vop2);
+
+	ret = vop2_win_init(vop2);
+	if (ret)
+		return ret;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	if (!res) {
+		drm_err(vop2->drm, "failed to get vop2 register byname\n");
+		return -EINVAL;
+	}
+	vop2->regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(vop2->regs))
+		return PTR_ERR(vop2->regs);
+	vop2->len = resource_size(res);
+
+	vop2->regsbak = devm_kzalloc(dev, vop2->len, GFP_KERNEL);
+	if (!vop2->regsbak)
+		return -ENOMEM;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gamma_lut");
+	if (res) {
+		vop2->lut_regs = devm_ioremap_resource(dev, res);
+		if (IS_ERR(vop2->lut_regs))
+			return PTR_ERR(vop2->lut_regs);
+	}
+
+	vop2->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
+
+	vop2->hclk = devm_clk_get(vop2->dev, "hclk_vop");
+	if (IS_ERR(vop2->hclk)) {
+		drm_err(vop2->drm, "failed to get hclk source\n");
+		return PTR_ERR(vop2->hclk);
+	}
+
+	vop2->aclk = devm_clk_get(vop2->dev, "aclk_vop");
+	if (IS_ERR(vop2->aclk)) {
+		drm_err(vop2->drm, "failed to get aclk source\n");
+		return PTR_ERR(vop2->aclk);
+	}
+
+	vop2->irq = platform_get_irq(pdev, 0);
+	if (vop2->irq < 0) {
+		drm_err(vop2->drm, "cannot find irq for vop2\n");
+		return vop2->irq;
+	}
+
+	spin_lock_init(&vop2->reg_lock);
+	mutex_init(&vop2->vop2_lock);
+
+	ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2);
+	if (ret)
+		return ret;
+
+	ret = rockchip_drm_dma_attach_device(vop2->drm, vop2->dev);
+	if (ret) {
+		drm_err(vop2->drm, "failed to attach dma mapping, %d\n", ret);
+		return ret;
+	}
+
+	ret = vop2_create_crtc(vop2);
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+}
+
+static void vop2_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct vop2 *vop2 = dev_get_drvdata(dev);
+	struct drm_device *drm = vop2->drm;
+	struct list_head *plane_list = &drm->mode_config.plane_list;
+	struct list_head *crtc_list = &drm->mode_config.crtc_list;
+	struct drm_crtc *crtc, *tmpc;
+	struct drm_plane *plane, *tmpp;
+
+	rockchip_drm_dma_detach_device(vop2->drm, vop2->dev);
+
+	pm_runtime_disable(dev);
+
+	list_for_each_entry_safe(plane, tmpp, plane_list, head)
+		drm_plane_cleanup(plane);
+
+	list_for_each_entry_safe(crtc, tmpc, crtc_list, head)
+		vop2_destroy_crtc(crtc);
+}
+
+const struct component_ops vop2_component_ops = {
+	.bind = vop2_bind,
+	.unbind = vop2_unbind,
+};
+EXPORT_SYMBOL_GPL(vop2_component_ops);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
new file mode 100644
index 0000000000000..b18871a5d85a7
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
@@ -0,0 +1,625 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:Mark Yao <mark.yao@rock-chips.com>
+ */
+
+#ifndef _ROCKCHIP_DRM_VOP2_H
+#define _ROCKCHIP_DRM_VOP2_H
+
+#include "rockchip_drm_vop.h"
+
+#include <drm/drm_modes.h>
+
+#define VOP_FEATURE_OUTPUT_10BIT        BIT(0)
+
+#define WIN_FEATURE_AFBDC		BIT(0)
+#define WIN_FEATURE_CLUSTER		BIT(1)
+
+/*
+ *  the delay number of a window in different mode.
+ */
+enum win_dly_mode {
+	VOP2_DLY_MODE_DEFAULT,   /**< default mode */
+	VOP2_DLY_MODE_HISO_S,    /** HDR in SDR out mode, as a SDR window */
+	VOP2_DLY_MODE_HIHO_H,    /** HDR in HDR out mode, as a HDR window */
+	VOP2_DLY_MODE_MAX,
+};
+
+struct vop_rect {
+	int width;
+	int height;
+};
+
+struct vop_grf_ctrl {
+	struct vop_reg grf_dclk_inv;
+	struct vop_reg grf_bt1120_clk_inv;
+	struct vop_reg grf_bt656_clk_inv;
+};
+
+struct vop2_afbc {
+	struct vop_reg enable;
+	struct vop_reg format;
+	struct vop_reg rb_swap;
+	struct vop_reg uv_swap;
+	struct vop_reg auto_gating_en;
+	struct vop_reg block_split_en;
+	struct vop_reg pic_vir_width;
+	struct vop_reg tile_num;
+	struct vop_reg pic_offset;
+	struct vop_reg pic_size;
+	struct vop_reg dsp_offset;
+	struct vop_reg transform_offset;
+	struct vop_reg hdr_ptr;
+	struct vop_reg half_block_en;
+	struct vop_reg xmirror;
+	struct vop_reg ymirror;
+	struct vop_reg rotate_270;
+	struct vop_reg rotate_90;
+};
+
+enum vop2_scale_up_mode {
+	VOP2_SCALE_UP_NRST_NBOR,
+	VOP2_SCALE_UP_BIL,
+	VOP2_SCALE_UP_BIC,
+};
+
+enum vop2_scale_down_mode {
+	VOP2_SCALE_DOWN_NRST_NBOR,
+	VOP2_SCALE_DOWN_BIL,
+	VOP2_SCALE_DOWN_AVG,
+};
+
+struct vop2_cluster_regs {
+	struct vop_reg enable;
+	struct vop_reg afbc_enable;
+	struct vop_reg lb_mode;
+};
+
+struct vop2_scl_regs {
+	struct vop_reg scale_yrgb_x;
+	struct vop_reg scale_yrgb_y;
+	struct vop_reg scale_cbcr_x;
+	struct vop_reg scale_cbcr_y;
+	struct vop_reg yrgb_hor_scl_mode;
+	struct vop_reg yrgb_hscl_filter_mode;
+	struct vop_reg yrgb_ver_scl_mode;
+	struct vop_reg yrgb_vscl_filter_mode;
+	struct vop_reg cbcr_ver_scl_mode;
+	struct vop_reg cbcr_hscl_filter_mode;
+	struct vop_reg cbcr_hor_scl_mode;
+	struct vop_reg cbcr_vscl_filter_mode;
+	struct vop_reg vsd_cbcr_gt2;
+	struct vop_reg vsd_cbcr_gt4;
+	struct vop_reg vsd_yrgb_gt2;
+	struct vop_reg vsd_yrgb_gt4;
+	struct vop_reg bic_coe_sel;
+};
+
+struct vop2_win_regs {
+	const struct vop2_scl_regs *scl;
+	const struct vop2_cluster_regs *cluster;
+	const struct vop2_afbc *afbc;
+
+	struct vop_reg gate;
+	struct vop_reg enable;
+	struct vop_reg format;
+	struct vop_reg csc_mode;
+	struct vop_reg xmirror;
+	struct vop_reg ymirror;
+	struct vop_reg rb_swap;
+	struct vop_reg uv_swap;
+	struct vop_reg act_info;
+	struct vop_reg dsp_info;
+	struct vop_reg dsp_st;
+	struct vop_reg yrgb_mst;
+	struct vop_reg uv_mst;
+	struct vop_reg yrgb_vir;
+	struct vop_reg uv_vir;
+	struct vop_reg yuv_clip;
+	struct vop_reg lb_mode;
+	struct vop_reg y2r_en;
+	struct vop_reg r2y_en;
+	struct vop_reg channel;
+	struct vop_reg dst_alpha_ctl;
+	struct vop_reg src_alpha_ctl;
+	struct vop_reg alpha_mode;
+	struct vop_reg alpha_en;
+	struct vop_reg global_alpha_val;
+	struct vop_reg color_key;
+	struct vop_reg color_key_en;
+	struct vop_reg dither_up;
+};
+
+struct vop2_video_port_regs {
+	int dsp_background;
+	int pre_scan_htiming;
+	int htotal_pw;
+	int hact_st_end;
+	int vtotal_pw;
+	int vact_st_end;
+	int vact_st_end_f1;
+	int vs_st_end_f1;
+	int hpost_st_end;
+	int vpost_st_end;
+	int vpost_st_end_f1;
+	int post_scl_factor;
+	int dsp_ctrl;
+	int mipi_ctrl;
+	int bg_mix_ctrl;
+	int hdr2sdr_eetf_oetf_y0_offset;
+	int hdr2sdr_sat_y0_offset;
+	int sdr2hdr_eotf_oetf_y0_offset;
+	int sdr2hdr_oetf_dx_pow1_offset;
+	int sdr2hdr_oetf_xn1_offset;
+	int irq_enable;
+	int irq_status;
+	int irq_clear;
+	int line_flag;
+};
+
+struct vop2_wb_regs {
+	struct vop_reg enable;
+	struct vop_reg format;
+	struct vop_reg dither_en;
+	struct vop_reg r2y_en;
+	struct vop_reg yrgb_mst;
+	struct vop_reg uv_mst;
+	struct vop_reg vp_id;
+	struct vop_reg fifo_throd;
+	struct vop_reg scale_x_factor;
+	struct vop_reg scale_x_en;
+	struct vop_reg scale_y_en;
+	struct vop_reg axi_yrgb_id;
+	struct vop_reg axi_uv_id;
+};
+
+struct vop2_win_data {
+	const char *name;
+	uint8_t phys_id;
+
+	uint32_t base;
+	enum drm_plane_type type;
+
+	uint32_t nformats;
+	const uint32_t *formats;
+	const uint64_t *format_modifiers;
+	const unsigned int supported_rotations;
+
+	const struct vop2_win_regs *regs;
+
+	/*
+	 * vertical/horizontal scale up/down filter mode
+	 */
+	const u8 hsu_filter_mode;
+	const u8 hsd_filter_mode;
+	const u8 vsu_filter_mode;
+	const u8 vsd_filter_mode;
+	/**
+	 * @layer_sel_id: defined by register OVERLAY_LAYER_SEL of VOP2
+	 */
+	int layer_sel_id;
+	uint64_t feature;
+
+	unsigned int max_upscale_factor;
+	unsigned int max_downscale_factor;
+	const uint8_t dly[VOP2_DLY_MODE_MAX];
+};
+
+struct vop2_wb_data {
+	uint32_t nformats;
+	const uint32_t *formats;
+	struct vop_rect max_output;
+	const struct vop2_wb_regs *regs;
+};
+
+struct vop2_video_port_data {
+	char id;
+	uint32_t feature;
+	uint16_t gamma_lut_len;
+	uint16_t cubic_lut_len;
+	struct vop_rect max_output;
+	const u8 pre_scan_max_dly[4];
+	const struct vop2_video_port_regs *regs;
+};
+
+/**
+ * VOP2 data struct
+ *
+ * @version: VOP IP version
+ * @win_size: hardware win number
+ */
+struct vop2_data {
+	uint8_t nr_vps;
+	uint8_t nr_mixers;
+	uint8_t nr_layers;
+	uint8_t nr_gammas;
+	const struct vop2_ctrl *ctrl;
+	const struct vop2_win_data *win;
+	const struct vop2_video_port_data *vp;
+	const struct vop_csc_table *csc_table;
+	const struct vop_grf_ctrl *grf_ctrl;
+	struct vop_rect max_input;
+	struct vop_rect max_output;
+
+	unsigned int win_size;
+	unsigned int soc_id;
+};
+
+/* interrupt define */
+#define FS_NEW_INTR			BIT(4)
+#define ADDR_SAME_INTR			BIT(5)
+#define LINE_FLAG1_INTR			BIT(6)
+#define WIN0_EMPTY_INTR			BIT(7)
+#define WIN1_EMPTY_INTR			BIT(8)
+#define WIN2_EMPTY_INTR			BIT(9)
+#define WIN3_EMPTY_INTR			BIT(10)
+#define HWC_EMPTY_INTR			BIT(11)
+#define POST_BUF_EMPTY_INTR		BIT(12)
+#define PWM_GEN_INTR			BIT(13)
+#define DMA_FINISH_INTR			BIT(14)
+#define FS_FIELD_INTR			BIT(15)
+#define FE_INTR				BIT(16)
+#define WB_UV_FIFO_FULL_INTR		BIT(17)
+#define WB_YRGB_FIFO_FULL_INTR		BIT(18)
+#define WB_COMPLETE_INTR		BIT(19)
+
+/*
+ * display output interface supported by rockchip lcdc
+ */
+#define ROCKCHIP_OUT_MODE_P888		0
+#define ROCKCHIP_OUT_MODE_BT1120	0
+#define ROCKCHIP_OUT_MODE_P666		1
+#define ROCKCHIP_OUT_MODE_P565		2
+#define ROCKCHIP_OUT_MODE_BT656		5
+#define ROCKCHIP_OUT_MODE_S888		8
+#define ROCKCHIP_OUT_MODE_S888_DUMMY	12
+#define ROCKCHIP_OUT_MODE_YUV420	14
+/* for use special outface */
+#define ROCKCHIP_OUT_MODE_AAAA		15
+
+enum vop_csc_format {
+	CSC_BT601L,
+	CSC_BT709L,
+	CSC_BT601F,
+	CSC_BT2020,
+};
+
+enum src_factor_mode {
+	SRC_FAC_ALPHA_ZERO,
+	SRC_FAC_ALPHA_ONE,
+	SRC_FAC_ALPHA_DST,
+	SRC_FAC_ALPHA_DST_INVERSE,
+	SRC_FAC_ALPHA_SRC,
+	SRC_FAC_ALPHA_SRC_GLOBAL,
+};
+
+enum dst_factor_mode {
+	DST_FAC_ALPHA_ZERO,
+	DST_FAC_ALPHA_ONE,
+	DST_FAC_ALPHA_SRC,
+	DST_FAC_ALPHA_SRC_INVERSE,
+	DST_FAC_ALPHA_DST,
+	DST_FAC_ALPHA_DST_GLOBAL,
+};
+
+#define RK3568_GRF_VO_CON1			0x0364
+/* System registers definition */
+#define RK3568_REG_CFG_DONE			0x000
+#define RK3568_VERSION_INFO			0x004
+#define RK3568_SYS_AUTO_GATING_CTRL		0x008
+#define RK3568_SYS_AXI_LUT_CTRL			0x024
+#define RK3568_DSP_IF_EN			0x028
+#define RK3568_DSP_IF_CTRL			0x02c
+#define RK3568_DSP_IF_POL			0x030
+#define RK3568_WB_CTRL				0x40
+#define RK3568_WB_XSCAL_FACTOR			0x44
+#define RK3568_WB_YRGB_MST			0x48
+#define RK3568_WB_CBR_MST			0x4C
+#define RK3568_OTP_WIN_EN			0x050
+#define RK3568_LUT_PORT_SEL			0x058
+#define RK3568_SYS_STATUS0			0x060
+#define RK3568_VP0_LINE_FLAG			0x70
+#define RK3568_VP1_LINE_FLAG			0x74
+#define RK3568_VP2_LINE_FLAG			0x78
+#define RK3568_SYS0_INT_EN			0x80
+#define RK3568_SYS0_INT_CLR			0x84
+#define RK3568_SYS0_INT_STATUS			0x88
+#define RK3568_SYS1_INT_EN			0x90
+#define RK3568_SYS1_INT_CLR			0x94
+#define RK3568_SYS1_INT_STATUS			0x98
+#define RK3568_VP0_INT_EN			0xA0
+#define RK3568_VP0_INT_CLR			0xA4
+#define RK3568_VP0_INT_STATUS			0xA8
+#define RK3568_VP0_INT_RAW_STATUS		0xAC
+#define RK3568_VP1_INT_EN			0xB0
+#define RK3568_VP1_INT_CLR			0xB4
+#define RK3568_VP1_INT_STATUS			0xB8
+#define RK3568_VP1_INT_RAW_STATUS		0xBC
+#define RK3568_VP2_INT_EN			0xC0
+#define RK3568_VP2_INT_CLR			0xC4
+#define RK3568_VP2_INT_STATUS			0xC8
+#define RK3568_VP2_INT_RAW_STATUS		0xCC
+
+/* Video Port registers definition */
+#define RK3568_VP0_DSP_CTRL			0xC00
+#define RK3568_VP0_MIPI_CTRL			0xC04
+#define RK3568_VP0_COLOR_BAR_CTRL		0xC08
+#define RK3568_VP0_3D_LUT_CTRL			0xC10
+#define RK3568_VP0_3D_LUT_MST			0xC20
+#define RK3568_VP0_DSP_BG			0xC2C
+#define RK3568_VP0_PRE_SCAN_HTIMING		0xC30
+#define RK3568_VP0_POST_DSP_HACT_INFO		0xC34
+#define RK3568_VP0_POST_DSP_VACT_INFO		0xC38
+#define RK3568_VP0_POST_SCL_FACTOR_YRGB		0xC3C
+#define RK3568_VP0_POST_SCL_CTRL		0xC40
+#define RK3568_VP0_POST_DSP_VACT_INFO_F1	0xC44
+#define RK3568_VP0_DSP_HTOTAL_HS_END		0xC48
+#define RK3568_VP0_DSP_HACT_ST_END		0xC4C
+#define RK3568_VP0_DSP_VTOTAL_VS_END		0xC50
+#define RK3568_VP0_DSP_VACT_ST_END		0xC54
+#define RK3568_VP0_DSP_VS_ST_END_F1		0xC58
+#define RK3568_VP0_DSP_VACT_ST_END_F1		0xC5C
+#define RK3568_VP0_BCSH_CTRL			0xC60
+#define RK3568_VP0_BCSH_BCS			0xC64
+#define RK3568_VP0_BCSH_H			0xC68
+#define RK3568_VP0_BCSH_COLOR_BAR		0xC6C
+
+#define RK3568_VP1_DSP_CTRL			0xD00
+#define RK3568_VP1_MIPI_CTRL			0xD04
+#define RK3568_VP1_COLOR_BAR_CTRL		0xD08
+#define RK3568_VP1_DSP_BG			0xD2C
+#define RK3568_VP1_PRE_SCAN_HTIMING		0xD30
+#define RK3568_VP1_POST_DSP_HACT_INFO		0xD34
+#define RK3568_VP1_POST_DSP_VACT_INFO		0xD38
+#define RK3568_VP1_POST_SCL_FACTOR_YRGB		0xD3C
+#define RK3568_VP1_POST_SCL_CTRL		0xD40
+#define RK3568_VP1_DSP_HACT_INFO		0xD34
+#define RK3568_VP1_DSP_VACT_INFO		0xD38
+#define RK3568_VP1_POST_DSP_VACT_INFO_F1	0xD44
+#define RK3568_VP1_DSP_HTOTAL_HS_END		0xD48
+#define RK3568_VP1_DSP_HACT_ST_END		0xD4C
+#define RK3568_VP1_DSP_VTOTAL_VS_END		0xD50
+#define RK3568_VP1_DSP_VACT_ST_END		0xD54
+#define RK3568_VP1_DSP_VS_ST_END_F1		0xD58
+#define RK3568_VP1_DSP_VACT_ST_END_F1		0xD5C
+#define RK3568_VP1_BCSH_CTRL			0xD60
+#define RK3568_VP1_BCSH_BCS			0xD64
+#define RK3568_VP1_BCSH_H			0xD68
+#define RK3568_VP1_BCSH_COLOR_BAR		0xD6C
+
+#define RK3568_VP2_DSP_CTRL			0xE00
+#define RK3568_VP2_MIPI_CTRL			0xE04
+#define RK3568_VP2_COLOR_BAR_CTRL		0xE08
+#define RK3568_VP2_DSP_BG			0xE2C
+#define RK3568_VP2_PRE_SCAN_HTIMING		0xE30
+#define RK3568_VP2_POST_DSP_HACT_INFO		0xE34
+#define RK3568_VP2_POST_DSP_VACT_INFO		0xE38
+#define RK3568_VP2_POST_SCL_FACTOR_YRGB		0xE3C
+#define RK3568_VP2_POST_SCL_CTRL		0xE40
+#define RK3568_VP2_DSP_HACT_INFO		0xE34
+#define RK3568_VP2_DSP_VACT_INFO		0xE38
+#define RK3568_VP2_POST_DSP_VACT_INFO_F1	0xE44
+#define RK3568_VP2_DSP_HTOTAL_HS_END		0xE48
+#define RK3568_VP2_DSP_HACT_ST_END		0xE4C
+#define RK3568_VP2_DSP_VTOTAL_VS_END		0xE50
+#define RK3568_VP2_DSP_VACT_ST_END		0xE54
+#define RK3568_VP2_DSP_VS_ST_END_F1		0xE58
+#define RK3568_VP2_DSP_VACT_ST_END_F1		0xE5C
+#define RK3568_VP2_BCSH_CTRL			0xE60
+#define RK3568_VP2_BCSH_BCS			0xE64
+#define RK3568_VP2_BCSH_H			0xE68
+#define RK3568_VP2_BCSH_COLOR_BAR		0xE6C
+
+/* Overlay registers definition    */
+#define RK3568_OVL_CTRL				0x600
+#define RK3568_OVL_LAYER_SEL			0x604
+#define RK3568_OVL_PORT_SEL			0x608
+#define RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL	0x610
+#define RK3568_CLUSTER0_MIX_DST_COLOR_CTRL	0x614
+#define RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL	0x618
+#define RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL	0x61C
+#define RK3568_MIX0_SRC_COLOR_CTRL		0x650
+#define RK3568_MIX0_DST_COLOR_CTRL		0x654
+#define RK3568_MIX0_SRC_ALPHA_CTRL		0x658
+#define RK3568_MIX0_DST_ALPHA_CTRL		0x65C
+#define RK3568_HDR0_SRC_COLOR_CTRL		0x6C0
+#define RK3568_HDR0_DST_COLOR_CTRL		0x6C4
+#define RK3568_HDR0_SRC_ALPHA_CTRL		0x6C8
+#define RK3568_HDR0_DST_ALPHA_CTRL		0x6CC
+#define RK3568_VP0_BG_MIX_CTRL			0x6E0
+#define RK3568_VP1_BG_MIX_CTRL			0x6E4
+#define RK3568_VP2_BG_MIX_CTRL			0x6E8
+#define RK3568_CLUSTER_DLY_NUM			0x6F0
+#define RK3568_SMART_DLY_NUM			0x6F8
+
+/* Cluster register definition, offset relative to window base */
+#define RK3568_CLUSTER_WIN_CTRL0		0x00
+#define RK3568_CLUSTER_WIN_CTRL1		0x04
+#define RK3568_CLUSTER_WIN_YRGB_MST		0x10
+#define RK3568_CLUSTER_WIN_CBR_MST		0x14
+#define RK3568_CLUSTER_WIN_VIR			0x18
+#define RK3568_CLUSTER_WIN_ACT_INFO		0x20
+#define RK3568_CLUSTER_WIN_DSP_INFO		0x24
+#define RK3568_CLUSTER_WIN_DSP_ST		0x28
+#define RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB	0x30
+#define RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET	0x3C
+#define RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL	0x50
+#define RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE	0x54
+#define RK3568_CLUSTER_WIN_AFBCD_HDR_PTR	0x58
+#define RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH	0x5C
+#define RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE	0x60
+#define RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET	0x64
+#define RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET	0x68
+#define RK3568_CLUSTER_WIN_AFBCD_CTRL		0x6C
+
+#define RK3568_CLUSTER_CTRL			0x100
+
+/* (E)smart register definition, offset relative to window base */
+#define RK3568_SMART_CTRL0			0x00
+#define RK3568_SMART_CTRL1			0x04
+#define RK3568_SMART_REGION0_CTRL		0x10
+#define RK3568_SMART_REGION0_YRGB_MST		0x14
+#define RK3568_SMART_REGION0_CBR_MST		0x18
+#define RK3568_SMART_REGION0_VIR		0x1C
+#define RK3568_SMART_REGION0_ACT_INFO		0x20
+#define RK3568_SMART_REGION0_DSP_INFO		0x24
+#define RK3568_SMART_REGION0_DSP_ST		0x28
+#define RK3568_SMART_REGION0_SCL_CTRL		0x30
+#define RK3568_SMART_REGION0_SCL_FACTOR_YRGB	0x34
+#define RK3568_SMART_REGION0_SCL_FACTOR_CBR	0x38
+#define RK3568_SMART_REGION0_SCL_OFFSET		0x3C
+#define RK3568_SMART_REGION1_CTRL		0x40
+#define RK3568_SMART_REGION1_YRGB_MST		0x44
+#define RK3568_SMART_REGION1_CBR_MST		0x48
+#define RK3568_SMART_REGION1_VIR		0x4C
+#define RK3568_SMART_REGION1_ACT_INFO		0x50
+#define RK3568_SMART_REGION1_DSP_INFO		0x54
+#define RK3568_SMART_REGION1_DSP_ST		0x58
+#define RK3568_SMART_REGION1_SCL_CTRL		0x60
+#define RK3568_SMART_REGION1_SCL_FACTOR_YRGB	0x64
+#define RK3568_SMART_REGION1_SCL_FACTOR_CBR	0x68
+#define RK3568_SMART_REGION1_SCL_OFFSET		0x6C
+#define RK3568_SMART_REGION2_CTRL		0x70
+#define RK3568_SMART_REGION2_YRGB_MST		0x74
+#define RK3568_SMART_REGION2_CBR_MST		0x78
+#define RK3568_SMART_REGION2_VIR		0x7C
+#define RK3568_SMART_REGION2_ACT_INFO		0x80
+#define RK3568_SMART_REGION2_DSP_INFO		0x84
+#define RK3568_SMART_REGION2_DSP_ST		0x88
+#define RK3568_SMART_REGION2_SCL_CTRL		0x90
+#define RK3568_SMART_REGION2_SCL_FACTOR_YRGB	0x94
+#define RK3568_SMART_REGION2_SCL_FACTOR_CBR	0x98
+#define RK3568_SMART_REGION2_SCL_OFFSET		0x9C
+#define RK3568_SMART_REGION3_CTRL		0xA0
+#define RK3568_SMART_REGION3_YRGB_MST		0xA4
+#define RK3568_SMART_REGION3_CBR_MST		0xA8
+#define RK3568_SMART_REGION3_VIR		0xAC
+#define RK3568_SMART_REGION3_ACT_INFO		0xB0
+#define RK3568_SMART_REGION3_DSP_INFO		0xB4
+#define RK3568_SMART_REGION3_DSP_ST		0xB8
+#define RK3568_SMART_REGION3_SCL_CTRL		0xC0
+#define RK3568_SMART_REGION3_SCL_FACTOR_YRGB	0xC4
+#define RK3568_SMART_REGION3_SCL_FACTOR_CBR	0xC8
+#define RK3568_SMART_REGION3_SCL_OFFSET		0xCC
+#define RK3568_SMART_COLOR_KEY_CTRL		0xD0
+
+/* HDR register definition */
+#define RK3568_HDR_LUT_CTRL			0x2000
+#define RK3568_HDR_LUT_MST			0x2004
+#define RK3568_SDR2HDR_CTRL			0x2010
+#define RK3568_HDR2SDR_CTRL			0x2020
+#define RK3568_HDR2SDR_SRC_RANGE		0x2024
+#define RK3568_HDR2SDR_NORMFACEETF		0x2028
+#define RK3568_HDR2SDR_DST_RANGE		0x202C
+#define RK3568_HDR2SDR_NORMFACCGAMMA		0x2030
+#define RK3568_HDR_EETF_OETF_Y0			0x203C
+#define RK3568_HDR_SAT_Y0			0x20C0
+#define RK3568_HDR_EOTF_OETF_Y0			0x20F0
+#define RK3568_HDR_OETF_DX_POW1			0x2200
+#define RK3568_HDR_OETF_XN1			0x2300
+
+#define RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN		BIT(15)
+
+#define RK3568_VP_DSP_CTRL__STANDBY			BIT(31)
+#define RK3568_VP_DSP_CTRL__DITHER_DOWN_MODE		BIT(20)
+#define RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL		GENMASK(19, 18)
+#define RK3568_VP_DSP_CTRL__DITHER_DOWN_EN		BIT(17)
+#define RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN		BIT(16)
+#define RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y		BIT(15)
+#define RK3568_VP_DSP_CTRL__DSP_RB_SWAP			BIT(9)
+#define RK3568_VP_DSP_CTRL__DSP_INTERLACE		BIT(7)
+#define RK3568_VP_DSP_CTRL__DSP_FILED_POL		BIT(6)
+#define RK3568_VP_DSP_CTRL__P2I_EN			BIT(5)
+#define RK3568_VP_DSP_CTRL__CORE_DCLK_DIV		BIT(4)
+#define RK3568_VP_DSP_CTRL__OUT_MODE			GENMASK(3, 0)
+
+#define RK3568_VP_POST_SCL_CTRL__VSCALEDOWN		BIT(1)
+#define RK3568_VP_POST_SCL_CTRL__HSCALEDOWN		BIT(0)
+
+#define RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX		GENMASK(26, 25)
+#define RK3568_SYS_DSP_INFACE_EN_LVDS1			BIT(24)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX		GENMASK(22, 21)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI1			BIT(20)
+#define RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX		GENMASK(19, 18)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX		GENMASK(17, 16)
+#define RK3568_SYS_DSP_INFACE_EN_EDP_MUX		GENMASK(15, 14)
+#define RK3568_SYS_DSP_INFACE_EN_HDMI_MUX		GENMASK(11, 10)
+#define RK3568_SYS_DSP_INFACE_EN_RGB_MUX		GENMASK(9, 8)
+#define RK3568_SYS_DSP_INFACE_EN_LVDS0			BIT(5)
+#define RK3568_SYS_DSP_INFACE_EN_MIPI0			BIT(4)
+#define RK3568_SYS_DSP_INFACE_EN_EDP			BIT(3)
+#define RK3568_SYS_DSP_INFACE_EN_HDMI			BIT(1)
+#define RK3568_SYS_DSP_INFACE_EN_RGB			BIT(0)
+
+#define RK3568_DSP_IF_POL__MIPI_PIN_POL			GENMASK(19, 16)
+#define RK3568_DSP_IF_POL__EDP_PIN_POL			GENMASK(15, 12)
+#define RK3568_DSP_IF_POL__HDMI_PIN_POL			GENMASK(7, 4)
+#define RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL		GENMASK(3, 0)
+
+#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2_PHASE_LOCK	BIT(5)
+#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2			BIT(4)
+
+#define RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN	BIT(31)
+
+#define RK3568_DSP_IF_POL__CFG_DONE_IMD			BIT(28)
+
+#define VOP2_SYS_AXI_BUS_NUM				2
+
+#define VOP2_CLUSTER_YUV444_10				0x12
+
+#define VOP2_COLOR_KEY_MASK				BIT(31)
+
+#define RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD		BIT(28)
+
+#define RK3568_VP_BG_MIX_CTRL__BG_DLY			GENMASK(31, 24)
+
+#define RK3568_OVL_PORT_SEL__SEL_PORT			GENMASK(31, 16)
+#define RK3568_OVL_PORT_SEL__SMART1			GENMASK(31, 30)
+#define RK3568_OVL_PORT_SEL__SMART0			GENMASK(29, 28)
+#define RK3568_OVL_PORT_SEL__ESMART1			GENMASK(27, 26)
+#define RK3568_OVL_PORT_SEL__ESMART0			GENMASK(25, 24)
+#define RK3568_OVL_PORT_SEL__CLUSTER1			GENMASK(19, 18)
+#define RK3568_OVL_PORT_SEL__CLUSTER0			GENMASK(17, 16)
+#define RK3568_OVL_PORT_SET__PORT2_MUX			GENMASK(11, 8)
+#define RK3568_OVL_PORT_SET__PORT1_MUX			GENMASK(7, 4)
+#define RK3568_OVL_PORT_SET__PORT0_MUX			GENMASK(3, 0)
+#define RK3568_OVL_LAYER_SEL__LAYER(layer, x)		((x) << ((layer) * 4))
+
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER1_1		GENMASK(31, 24)
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER1_0		GENMASK(23, 16)
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_1		GENMASK(15, 8)
+#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_0		GENMASK(7, 0)
+
+#define RK3568_SMART_DLY_NUM__SMART1			GENMASK(31, 24)
+#define RK3568_SMART_DLY_NUM__SMART0			GENMASK(23, 16)
+#define RK3568_SMART_DLY_NUM__ESMART1			GENMASK(15, 8)
+#define RK3568_SMART_DLY_NUM__ESMART0			GENMASK(7, 0)
+
+#define VP_INT_DSP_HOLD_VALID	BIT(6)
+#define VP_INT_FS_FIELD		BIT(5)
+#define VP_INT_POST_BUF_EMPTY	BIT(4)
+#define VP_INT_LINE_FLAG1	BIT(3)
+#define VP_INT_LINE_FLAG0	BIT(2)
+#define VOP2_INT_BUS_ERRPR	BIT(1)
+#define VP_INT_FS		BIT(0)
+
+#define POLFLAG_DCLK_INV	BIT(3)
+
+enum vop2_layer_phy_id {
+	ROCKCHIP_VOP2_CLUSTER0 = 0,
+	ROCKCHIP_VOP2_CLUSTER1,
+	ROCKCHIP_VOP2_ESMART0,
+	ROCKCHIP_VOP2_ESMART1,
+	ROCKCHIP_VOP2_SMART0,
+	ROCKCHIP_VOP2_SMART1,
+	ROCKCHIP_VOP2_CLUSTER2,
+	ROCKCHIP_VOP2_CLUSTER3,
+	ROCKCHIP_VOP2_ESMART2,
+	ROCKCHIP_VOP2_ESMART3,
+	ROCKCHIP_VOP2_PHY_ID_INVALID = -1,
+};
+
+extern const struct component_ops vop2_component_ops;
+
+#endif /* _ROCKCHIP_DRM_VOP2_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
new file mode 100644
index 0000000000000..683cd53c10158
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) Rockchip Electronics Co.Ltd
+ * Author: Andy Yan <andy.yan@rock-chips.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/component.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_print.h>
+
+#include "rockchip_drm_vop2.h"
+#include "rockchip_vop_reg.h"
+
+#define _VOP_REG(off, _mask, _shift, _write_mask) \
+	{ \
+		.offset = off, \
+		.mask = _mask, \
+		.shift = _shift, \
+		.write_mask = _write_mask, \
+	}
+
+#define VOP_REG(off, _mask, _shift) \
+		_VOP_REG(off, _mask, _shift, false)
+
+#define VOP_REG_MASK(off, _mask, s) \
+		_VOP_REG(off, _mask, s, true)
+
+static const uint32_t formats_win_full_10bit[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV16,
+	DRM_FORMAT_NV24,
+};
+
+static const uint32_t formats_win_full_10bit_yuyv[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV16,
+	DRM_FORMAT_NV24,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_VYUY,
+};
+
+static const uint32_t formats_win_lite[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+};
+
+static const uint64_t format_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static const uint64_t format_modifiers_afbc[] = {
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_CBR),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_CBR |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_CBR),
+
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_CBR |
+				AFBC_FORMAT_MOD_SPARSE),
+
+	/* SPLIT mandates SPARSE, RGB modes mandates YTR */
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_YTR |
+				AFBC_FORMAT_MOD_SPARSE |
+				AFBC_FORMAT_MOD_SPLIT),
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static const struct vop2_video_port_regs rk3568_vop_vp0_regs = {
+	.dsp_background = RK3568_VP0_DSP_BG,
+	.pre_scan_htiming = RK3568_VP0_PRE_SCAN_HTIMING,
+	.hpost_st_end = RK3568_VP0_POST_DSP_HACT_INFO,
+	.vpost_st_end = RK3568_VP0_POST_DSP_VACT_INFO,
+	.htotal_pw = RK3568_VP0_DSP_HTOTAL_HS_END,
+	.post_scl_factor = RK3568_VP0_POST_SCL_FACTOR_YRGB,
+	.hact_st_end = RK3568_VP0_DSP_HACT_ST_END,
+	.vtotal_pw = RK3568_VP0_DSP_VTOTAL_VS_END,
+	.vact_st_end = RK3568_VP0_DSP_VACT_ST_END,
+	.vact_st_end_f1 = RK3568_VP0_DSP_VACT_ST_END_F1,
+	.vs_st_end_f1 = RK3568_VP0_DSP_VS_ST_END_F1,
+	.vpost_st_end_f1 = RK3568_VP0_POST_DSP_VACT_INFO_F1,
+
+	.dsp_ctrl = RK3568_VP0_DSP_CTRL,
+	.mipi_ctrl = RK3568_VP0_MIPI_CTRL,
+	.bg_mix_ctrl = RK3568_VP0_BG_MIX_CTRL,
+	.irq_status = RK3568_VP0_INT_STATUS,
+	.irq_enable = RK3568_VP0_INT_EN,
+	.irq_clear = RK3568_VP0_INT_CLR,
+	.line_flag = RK3568_VP0_LINE_FLAG,
+};
+
+static const struct vop2_video_port_regs rk3568_vop_vp1_regs = {
+	.dsp_background = RK3568_VP1_DSP_BG,
+	.pre_scan_htiming = RK3568_VP1_PRE_SCAN_HTIMING,
+	.hpost_st_end = RK3568_VP1_POST_DSP_HACT_INFO,
+	.vpost_st_end = RK3568_VP1_POST_DSP_VACT_INFO,
+	.htotal_pw = RK3568_VP1_DSP_HTOTAL_HS_END,
+	.post_scl_factor = RK3568_VP1_POST_SCL_FACTOR_YRGB,
+	.hact_st_end = RK3568_VP1_DSP_HACT_ST_END,
+	.vtotal_pw = RK3568_VP1_DSP_VTOTAL_VS_END,
+	.vact_st_end = RK3568_VP1_DSP_VACT_ST_END,
+	.vact_st_end_f1 = RK3568_VP1_DSP_VACT_ST_END_F1,
+	.vs_st_end_f1 = RK3568_VP1_DSP_VS_ST_END_F1,
+	.vpost_st_end_f1 = RK3568_VP1_POST_DSP_VACT_INFO_F1,
+	.dsp_ctrl = RK3568_VP1_DSP_CTRL,
+	.mipi_ctrl = RK3568_VP1_MIPI_CTRL,
+	.bg_mix_ctrl = RK3568_VP1_BG_MIX_CTRL,
+	.irq_status = RK3568_VP1_INT_STATUS,
+	.irq_enable = RK3568_VP1_INT_EN,
+	.irq_clear = RK3568_VP1_INT_CLR,
+	.line_flag = RK3568_VP1_LINE_FLAG,
+};
+
+static const struct vop2_video_port_regs rk3568_vop_vp2_regs = {
+	.dsp_background = RK3568_VP2_DSP_BG,
+	.pre_scan_htiming = RK3568_VP2_PRE_SCAN_HTIMING,
+	.hpost_st_end = RK3568_VP2_POST_DSP_HACT_INFO,
+	.vpost_st_end = RK3568_VP2_POST_DSP_VACT_INFO,
+	.post_scl_factor = RK3568_VP2_POST_SCL_FACTOR_YRGB,
+	.htotal_pw = RK3568_VP2_DSP_HTOTAL_HS_END,
+	.hact_st_end = RK3568_VP2_DSP_HACT_ST_END,
+	.vtotal_pw = RK3568_VP2_DSP_VTOTAL_VS_END,
+	.vact_st_end = RK3568_VP2_DSP_VACT_ST_END,
+	.vact_st_end_f1 = RK3568_VP2_DSP_VACT_ST_END_F1,
+	.vs_st_end_f1 = RK3568_VP2_DSP_VS_ST_END_F1,
+	.vpost_st_end_f1 = RK3568_VP2_POST_DSP_VACT_INFO_F1,
+	.dsp_ctrl = RK3568_VP2_DSP_CTRL,
+	.mipi_ctrl = RK3568_VP2_MIPI_CTRL,
+	.bg_mix_ctrl = RK3568_VP2_BG_MIX_CTRL,
+	.irq_status = RK3568_VP2_INT_STATUS,
+	.irq_enable = RK3568_VP2_INT_EN,
+	.irq_clear = RK3568_VP2_INT_CLR,
+	.line_flag = RK3568_VP2_LINE_FLAG,
+};
+
+static const struct vop2_video_port_data rk3568_vop_video_ports[] = {
+	{
+		.id = 0,
+		.feature = VOP_FEATURE_OUTPUT_10BIT,
+		.gamma_lut_len = 1024,
+		.cubic_lut_len = 9 * 9 * 9,
+		.max_output = { 4096, 2304 },
+		.pre_scan_max_dly = { 69, 53, 53, 42 },
+		.regs = &rk3568_vop_vp0_regs,
+	}, {
+		.id = 1,
+		.gamma_lut_len = 1024,
+		.max_output = { 2048, 1536 },
+		.pre_scan_max_dly = { 40, 40, 40, 40 },
+		.regs = &rk3568_vop_vp1_regs,
+	}, {
+		.id = 2,
+		.gamma_lut_len = 1024,
+		.max_output = { 1920, 1080 },
+		.pre_scan_max_dly = { 40, 40, 40, 40 },
+		.regs = &rk3568_vop_vp2_regs,
+	},
+};
+
+static const struct vop2_cluster_regs rk3568_vop_cluster0 =  {
+	.afbc_enable = VOP_REG(RK3568_CLUSTER_CTRL, 0x1, 1),
+	.enable = VOP_REG(RK3568_CLUSTER_CTRL, 1, 0),
+	.lb_mode = VOP_REG(RK3568_CLUSTER_CTRL, 0xf, 4),
+};
+
+static const struct vop2_afbc rk3568_cluster_afbc = {
+	.format = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1f, 2),
+	.rb_swap = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 9),
+	.uv_swap = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 10),
+	.auto_gating_en = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL, 0x1, 4),
+	.half_block_en = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 7),
+	.block_split_en = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_CTRL, 0x1, 8),
+	.hdr_ptr = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_HDR_PTR, 0xffffffff, 0),
+	.pic_size = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE, 0xffffffff, 0),
+	.pic_vir_width = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0xffff, 0),
+	.tile_num = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0xffff, 16),
+	.pic_offset = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET, 0xffffffff, 0),
+	.dsp_offset = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET, 0xffffffff, 0),
+	.transform_offset = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET, 0xffffffff, 0),
+	.rotate_90 = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 0),
+	.rotate_270 = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 1),
+	.xmirror = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 2),
+	.ymirror = VOP_REG(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0x1, 3),
+};
+
+static const struct vop2_scl_regs rk3568_cluster_win_scl = {
+	.scale_yrgb_x = VOP_REG(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0xffff, 0x0),
+	.scale_yrgb_y = VOP_REG(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0xffff, 16),
+	.yrgb_ver_scl_mode = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x3, 14),
+	.yrgb_hor_scl_mode = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x3, 12),
+	.bic_coe_sel = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x3, 2),
+	.vsd_yrgb_gt2 = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x1, 28),
+	.vsd_yrgb_gt4 = VOP_REG(RK3568_CLUSTER_WIN_CTRL1, 0x1, 29),
+};
+
+static const struct vop2_scl_regs rk3568_esmart_win_scl = {
+	.scale_yrgb_x = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0xffff, 0x0),
+	.scale_yrgb_y = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0xffff, 16),
+	.scale_cbcr_x = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0xffff, 0x0),
+	.scale_cbcr_y = VOP_REG(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0xffff, 16),
+	.yrgb_hor_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 0),
+	.yrgb_hscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 2),
+	.yrgb_ver_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 4),
+	.yrgb_vscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 6),
+	.cbcr_hor_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 8),
+	.cbcr_hscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 10),
+	.cbcr_ver_scl_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 12),
+	.cbcr_vscl_filter_mode = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 14),
+	.bic_coe_sel = VOP_REG(RK3568_SMART_REGION0_SCL_CTRL, 0x3, 16),
+	.vsd_yrgb_gt2 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 8),
+	.vsd_yrgb_gt4 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 9),
+	.vsd_cbcr_gt2 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 10),
+	.vsd_cbcr_gt4 = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 11),
+};
+
+static const struct vop2_win_regs rk3568_cluster_win_data = {
+	.scl = &rk3568_cluster_win_scl,
+	.afbc = &rk3568_cluster_afbc,
+	.cluster = &rk3568_vop_cluster0,
+	.enable = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 0),
+	.format = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1f, 1),
+	.rb_swap = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 14),
+	.dither_up = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 18),
+	.act_info = VOP_REG(RK3568_CLUSTER_WIN_ACT_INFO, 0x1fff1fff, 0),
+	.dsp_info = VOP_REG(RK3568_CLUSTER_WIN_DSP_INFO, 0x0fff0fff, 0),
+	.dsp_st = VOP_REG(RK3568_CLUSTER_WIN_DSP_ST, 0x1fff1fff, 0),
+	.yrgb_mst = VOP_REG(RK3568_CLUSTER_WIN_YRGB_MST, 0xffffffff, 0),
+	.uv_mst = VOP_REG(RK3568_CLUSTER_WIN_CBR_MST, 0xffffffff, 0),
+	.yuv_clip = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 19),
+	.yrgb_vir = VOP_REG(RK3568_CLUSTER_WIN_VIR, 0xffff, 0),
+	.uv_vir = VOP_REG(RK3568_CLUSTER_WIN_VIR, 0xffff, 16),
+	.y2r_en = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 8),
+	.r2y_en = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x1, 9),
+	.csc_mode = VOP_REG(RK3568_CLUSTER_WIN_CTRL0, 0x3, 10),
+};
+
+static const struct vop2_win_regs rk3568_esmart_win_data = {
+	.scl = &rk3568_esmart_win_scl,
+	.enable = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 0),
+	.format = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1f, 1),
+	.dither_up = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 12),
+	.rb_swap = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 14),
+	.uv_swap = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 16),
+	.act_info = VOP_REG(RK3568_SMART_REGION0_ACT_INFO, 0x1fff1fff, 0),
+	.dsp_info = VOP_REG(RK3568_SMART_REGION0_DSP_INFO, 0x0fff0fff, 0),
+	.dsp_st = VOP_REG(RK3568_SMART_REGION0_DSP_ST, 0x1fff1fff, 0),
+	.yrgb_mst = VOP_REG(RK3568_SMART_REGION0_YRGB_MST, 0xffffffff, 0),
+	.uv_mst = VOP_REG(RK3568_SMART_REGION0_CBR_MST, 0xffffffff, 0),
+	.yuv_clip = VOP_REG(RK3568_SMART_REGION0_CTRL, 0x1, 17),
+	.yrgb_vir = VOP_REG(RK3568_SMART_REGION0_VIR, 0xffff, 0),
+	.uv_vir = VOP_REG(RK3568_SMART_REGION0_VIR, 0xffff, 16),
+	.y2r_en = VOP_REG(RK3568_SMART_CTRL0, 0x1, 0),
+	.r2y_en = VOP_REG(RK3568_SMART_CTRL0, 0x1, 1),
+	.csc_mode = VOP_REG(RK3568_SMART_CTRL0, 0x3, 2),
+	.ymirror = VOP_REG(RK3568_SMART_CTRL1, 0x1, 31),
+	.color_key = VOP_REG(RK3568_SMART_COLOR_KEY_CTRL, 0x3fffffff, 0),
+	.color_key_en = VOP_REG(RK3568_SMART_COLOR_KEY_CTRL, 0x1, 31),
+};
+
+/*
+ * rk3568 vop with 2 cluster, 2 esmart win, 2 smart win.
+ * Every cluster can work as 4K win or split into two win.
+ * All win in cluster support AFBCD.
+ *
+ * Every esmart win and smart win support 4 Multi-region.
+ *
+ * Scale filter mode:
+ *
+ * * Cluster:  bicubic for horizontal scale up, others use bilinear
+ * * ESmart:
+ *    * nearest-neighbor/bilinear/bicubic for scale up
+ *    * nearest-neighbor/bilinear/average for scale down
+ *
+ *
+ * @TODO describe the wind like cpu-map dt nodes;
+ */
+static const struct vop2_win_data rk3568_vop_win_data[] = {
+	{
+		.name = "Smart0-win0",
+		.phys_id = ROCKCHIP_VOP2_SMART0,
+		.base = 0x1c00,
+		.formats = formats_win_lite,
+		.nformats = ARRAY_SIZE(formats_win_lite),
+		.format_modifiers = format_modifiers,
+		.layer_sel_id = 3,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_PRIMARY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Smart1-win0",
+		.phys_id = ROCKCHIP_VOP2_SMART1,
+		.formats = formats_win_lite,
+		.nformats = ARRAY_SIZE(formats_win_lite),
+		.format_modifiers = format_modifiers,
+		.base = 0x1e00,
+		.layer_sel_id = 7,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_PRIMARY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Esmart1-win0",
+		.phys_id = ROCKCHIP_VOP2_ESMART1,
+		.formats = formats_win_full_10bit_yuyv,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
+		.format_modifiers = format_modifiers,
+		.base = 0x1a00,
+		.layer_sel_id = 6,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_PRIMARY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Esmart0-win0",
+		.phys_id = ROCKCHIP_VOP2_ESMART0,
+		.formats = formats_win_full_10bit_yuyv,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
+		.format_modifiers = format_modifiers,
+		.base = 0x1800,
+		.layer_sel_id = 2,
+		.supported_rotations = DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_esmart_win_data,
+		.type = DRM_PLANE_TYPE_OVERLAY,
+		.max_upscale_factor = 8,
+		.max_downscale_factor = 8,
+		.dly = { 20, 47, 41 },
+	}, {
+		.name = "Cluster0-win0",
+		.phys_id = ROCKCHIP_VOP2_CLUSTER0,
+		.base = 0x1000,
+		.formats = formats_win_full_10bit,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit),
+		.format_modifiers = format_modifiers_afbc,
+		.layer_sel_id = 0,
+		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
+					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_cluster_win_data,
+		.max_upscale_factor = 4,
+		.max_downscale_factor = 4,
+		.dly = { 0, 27, 21 },
+		.type = DRM_PLANE_TYPE_OVERLAY,
+		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
+	}, {
+		.name = "Cluster1-win0",
+		.phys_id = ROCKCHIP_VOP2_CLUSTER1,
+		.base = 0x1200,
+		.formats = formats_win_full_10bit,
+		.nformats = ARRAY_SIZE(formats_win_full_10bit),
+		.format_modifiers = format_modifiers_afbc,
+		.layer_sel_id = 1,
+		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
+					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
+		.hsu_filter_mode = VOP2_SCALE_UP_BIC,
+		.hsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.vsu_filter_mode = VOP2_SCALE_UP_BIL,
+		.vsd_filter_mode = VOP2_SCALE_DOWN_BIL,
+		.regs = &rk3568_cluster_win_data,
+		.type = DRM_PLANE_TYPE_OVERLAY,
+		.max_upscale_factor = 4,
+		.max_downscale_factor = 4,
+		.dly = { 0, 27, 21 },
+		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
+	},
+};
+
+static const struct vop_grf_ctrl rk3568_grf_ctrl = {
+	.grf_bt656_clk_inv = VOP_REG(RK3568_GRF_VO_CON1, 0x1, 1),
+	.grf_bt1120_clk_inv = VOP_REG(RK3568_GRF_VO_CON1, 0x1, 2),
+	.grf_dclk_inv = VOP_REG(RK3568_GRF_VO_CON1, 0x1, 3),
+};
+
+static const struct vop2_data rk3566_vop = {
+	.nr_vps = 3,
+	.nr_mixers = 5,
+	.nr_gammas = 1,
+	.max_input = { 4096, 2304 },
+	.max_output = { 4096, 2304 },
+	.grf_ctrl = &rk3568_grf_ctrl,
+	.vp = rk3568_vop_video_ports,
+	.win = rk3568_vop_win_data,
+	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
+	.soc_id = 3566,
+};
+
+static const struct vop2_data rk3568_vop = {
+	.nr_vps = 3,
+	.nr_mixers = 5,
+	.nr_gammas = 1,
+	.max_input = { 4096, 2304 },
+	.max_output = { 4096, 2304 },
+	.grf_ctrl = &rk3568_grf_ctrl,
+	.vp = rk3568_vop_video_ports,
+	.win = rk3568_vop_win_data,
+	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
+	.soc_id = 3568,
+};
+
+static const struct of_device_id vop2_dt_match[] = {
+	{
+		.compatible = "rockchip,rk3568-vop",
+		.data = &rk3568_vop
+	}, {
+		.compatible = "rockchip,rk3568-vop",
+		.data = &rk3566_vop
+	}, {
+	},
+};
+MODULE_DEVICE_TABLE(of, vop2_dt_match);
+
+static int vop2_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	return component_add(dev, &vop2_component_ops);
+}
+
+static int vop2_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &vop2_component_ops);
+
+	return 0;
+}
+
+struct platform_driver vop2_platform_driver = {
+	.probe = vop2_probe,
+	.remove = vop2_remove,
+	.driver = {
+		.name = "rockchip-vop2",
+		.of_match_table = of_match_ptr(vop2_dt_match),
+	},
+};
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
  2021-12-08 15:12 ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 15:12   ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

On the rk3568 we have this (simplified) situation:

 .--------.     .-----.    .---------.
-| hpll   |--.--| /n  |----|dclk_vop0|-
 `--------´  |  `-----´    `---------´
             |  .-----.    .---------.
             `--| /m  |----|dclk_vop1|-
             |  `-----´    `---------´
             |             .---------.
             `-------------|hdmi_ref |-
                           `---------´

hpll is the PLL that drives the HDMI reference clock and the pixel
clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
and the hpll there are programmable dividers whereas the HDMI reference
clock is directly connected to the hpll.

For the HDMI output to work the pixel clock must be the same as the HDMI
reference clock, hence the dividers must be programmed to 1. Normally a
rate change on dclk_vop0/1 propagates through to the hpll and the clock
framework picks a suitable combination of hpll and divider settings. by
accident it picks a divider setting of 1 for the standard 1080p case,
but other divider settings for most other resolutions leaving the HDMI
port non working.

This patch is not a solution, it merely puts the finger in the wound. We
leave out the divider for the composite clock for dclk_vop0 which then
leaves the divider at the bootloader default setting of 1. I assume
the divider is disturbing only for the HDMI case, but needed for other
outputs. Any thoughts how this can be handled?

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/clk/rockchip/clk-rk3568.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c
index 69a9e8069a486..2d04d8253ca22 100644
--- a/drivers/clk/rockchip/clk-rk3568.c
+++ b/drivers/clk/rockchip/clk-rk3568.c
@@ -1038,8 +1038,8 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
 			RK3568_CLKGATE_CON(20), 8, GFLAGS),
 	GATE(HCLK_VOP, "hclk_vop", "hclk_vo", 0,
 			RK3568_CLKGATE_CON(20), 9, GFLAGS),
-	COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
-			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS, 0, 8, DFLAGS,
+	COMPOSITE_NODIV(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS,
 			RK3568_CLKGATE_CON(20), 10, GFLAGS),
 	COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
 			RK3568_CLKSEL_CON(40), 10, 2, MFLAGS, 0, 8, DFLAGS,
-- 
2.30.2


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

* [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

On the rk3568 we have this (simplified) situation:

 .--------.     .-----.    .---------.
-| hpll   |--.--| /n  |----|dclk_vop0|-
 `--------´  |  `-----´    `---------´
             |  .-----.    .---------.
             `--| /m  |----|dclk_vop1|-
             |  `-----´    `---------´
             |             .---------.
             `-------------|hdmi_ref |-
                           `---------´

hpll is the PLL that drives the HDMI reference clock and the pixel
clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
and the hpll there are programmable dividers whereas the HDMI reference
clock is directly connected to the hpll.

For the HDMI output to work the pixel clock must be the same as the HDMI
reference clock, hence the dividers must be programmed to 1. Normally a
rate change on dclk_vop0/1 propagates through to the hpll and the clock
framework picks a suitable combination of hpll and divider settings. by
accident it picks a divider setting of 1 for the standard 1080p case,
but other divider settings for most other resolutions leaving the HDMI
port non working.

This patch is not a solution, it merely puts the finger in the wound. We
leave out the divider for the composite clock for dclk_vop0 which then
leaves the divider at the bootloader default setting of 1. I assume
the divider is disturbing only for the HDMI case, but needed for other
outputs. Any thoughts how this can be handled?

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/clk/rockchip/clk-rk3568.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c
index 69a9e8069a486..2d04d8253ca22 100644
--- a/drivers/clk/rockchip/clk-rk3568.c
+++ b/drivers/clk/rockchip/clk-rk3568.c
@@ -1038,8 +1038,8 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
 			RK3568_CLKGATE_CON(20), 8, GFLAGS),
 	GATE(HCLK_VOP, "hclk_vop", "hclk_vo", 0,
 			RK3568_CLKGATE_CON(20), 9, GFLAGS),
-	COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
-			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS, 0, 8, DFLAGS,
+	COMPOSITE_NODIV(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS,
 			RK3568_CLKGATE_CON(20), 10, GFLAGS),
 	COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
 			RK3568_CLKSEL_CON(40), 10, 2, MFLAGS, 0, 8, DFLAGS,
-- 
2.30.2


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

* [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

On the rk3568 we have this (simplified) situation:

 .--------.     .-----.    .---------.
-| hpll   |--.--| /n  |----|dclk_vop0|-
 `--------´  |  `-----´    `---------´
             |  .-----.    .---------.
             `--| /m  |----|dclk_vop1|-
             |  `-----´    `---------´
             |             .---------.
             `-------------|hdmi_ref |-
                           `---------´

hpll is the PLL that drives the HDMI reference clock and the pixel
clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
and the hpll there are programmable dividers whereas the HDMI reference
clock is directly connected to the hpll.

For the HDMI output to work the pixel clock must be the same as the HDMI
reference clock, hence the dividers must be programmed to 1. Normally a
rate change on dclk_vop0/1 propagates through to the hpll and the clock
framework picks a suitable combination of hpll and divider settings. by
accident it picks a divider setting of 1 for the standard 1080p case,
but other divider settings for most other resolutions leaving the HDMI
port non working.

This patch is not a solution, it merely puts the finger in the wound. We
leave out the divider for the composite clock for dclk_vop0 which then
leaves the divider at the bootloader default setting of 1. I assume
the divider is disturbing only for the HDMI case, but needed for other
outputs. Any thoughts how this can be handled?

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/clk/rockchip/clk-rk3568.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c
index 69a9e8069a486..2d04d8253ca22 100644
--- a/drivers/clk/rockchip/clk-rk3568.c
+++ b/drivers/clk/rockchip/clk-rk3568.c
@@ -1038,8 +1038,8 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
 			RK3568_CLKGATE_CON(20), 8, GFLAGS),
 	GATE(HCLK_VOP, "hclk_vop", "hclk_vo", 0,
 			RK3568_CLKGATE_CON(20), 9, GFLAGS),
-	COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
-			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS, 0, 8, DFLAGS,
+	COMPOSITE_NODIV(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS,
 			RK3568_CLKGATE_CON(20), 10, GFLAGS),
 	COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
 			RK3568_CLKSEL_CON(40), 10, 2, MFLAGS, 0, 8, DFLAGS,
-- 
2.30.2


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
@ 2021-12-08 15:12   ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-08 15:12 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis, Sascha Hauer

On the rk3568 we have this (simplified) situation:

 .--------.     .-----.    .---------.
-| hpll   |--.--| /n  |----|dclk_vop0|-
 `--------´  |  `-----´    `---------´
             |  .-----.    .---------.
             `--| /m  |----|dclk_vop1|-
             |  `-----´    `---------´
             |             .---------.
             `-------------|hdmi_ref |-
                           `---------´

hpll is the PLL that drives the HDMI reference clock and the pixel
clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
and the hpll there are programmable dividers whereas the HDMI reference
clock is directly connected to the hpll.

For the HDMI output to work the pixel clock must be the same as the HDMI
reference clock, hence the dividers must be programmed to 1. Normally a
rate change on dclk_vop0/1 propagates through to the hpll and the clock
framework picks a suitable combination of hpll and divider settings. by
accident it picks a divider setting of 1 for the standard 1080p case,
but other divider settings for most other resolutions leaving the HDMI
port non working.

This patch is not a solution, it merely puts the finger in the wound. We
leave out the divider for the composite clock for dclk_vop0 which then
leaves the divider at the bootloader default setting of 1. I assume
the divider is disturbing only for the HDMI case, but needed for other
outputs. Any thoughts how this can be handled?

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/clk/rockchip/clk-rk3568.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c
index 69a9e8069a486..2d04d8253ca22 100644
--- a/drivers/clk/rockchip/clk-rk3568.c
+++ b/drivers/clk/rockchip/clk-rk3568.c
@@ -1038,8 +1038,8 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
 			RK3568_CLKGATE_CON(20), 8, GFLAGS),
 	GATE(HCLK_VOP, "hclk_vop", "hclk_vo", 0,
 			RK3568_CLKGATE_CON(20), 9, GFLAGS),
-	COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
-			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS, 0, 8, DFLAGS,
+	COMPOSITE_NODIV(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS,
 			RK3568_CLKGATE_CON(20), 10, GFLAGS),
 	COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
 			RK3568_CLKSEL_CON(40), 10, 2, MFLAGS, 0, 8, DFLAGS,
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 08/18] dt-bindings: display: rockchip: dw-hdmi: Add regulator support
  2021-12-08 15:12   ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 16:35     ` Robin Murphy
  -1 siblings, 0 replies; 123+ messages in thread
From: Robin Murphy @ 2021-12-08 16:35 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

On 2021-12-08 15:12, Sascha Hauer wrote:
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>   .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 ++++++
>   1 file changed, 6 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> index 2ab6578033da2..b9dca49aa6e05 100644
> --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> @@ -28,6 +28,12 @@ properties:
>     reg-io-width:
>       const: 4
>   
> +  avdd-0v9-supply:
> +    description: A 0.9V supply that powers up the SoC internal circuitry.

Might be worth calling out the actual pin name so it's abundantly clear 
for DT authors cross-referencing schematics. Annoyingly, some SoCs have 
HDMI_AVDD_1V0 instead of HDMI_AVDD_0V9 - I'm not sure it's worth 
splitting hairs that far in terms of the property name itself, but I'll 
leave that for others to decide.

> +  avdd-1v8-supply:
> +    description: A 1.8V supply that powers up the SoC internal circuitry.

At least HDMI_AVDD_1V8 seems more consistent.

Thanks,
Robin.

> +
>     clocks:
>       minItems: 2
>       items:
> 

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 08/18] dt-bindings: display: rockchip: dw-hdmi: Add regulator support
@ 2021-12-08 16:35     ` Robin Murphy
  0 siblings, 0 replies; 123+ messages in thread
From: Robin Murphy @ 2021-12-08 16:35 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sandy Huang,
	linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

On 2021-12-08 15:12, Sascha Hauer wrote:
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>   .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 ++++++
>   1 file changed, 6 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> index 2ab6578033da2..b9dca49aa6e05 100644
> --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> @@ -28,6 +28,12 @@ properties:
>     reg-io-width:
>       const: 4
>   
> +  avdd-0v9-supply:
> +    description: A 0.9V supply that powers up the SoC internal circuitry.

Might be worth calling out the actual pin name so it's abundantly clear 
for DT authors cross-referencing schematics. Annoyingly, some SoCs have 
HDMI_AVDD_1V0 instead of HDMI_AVDD_0V9 - I'm not sure it's worth 
splitting hairs that far in terms of the property name itself, but I'll 
leave that for others to decide.

> +  avdd-1v8-supply:
> +    description: A 1.8V supply that powers up the SoC internal circuitry.

At least HDMI_AVDD_1V8 seems more consistent.

Thanks,
Robin.

> +
>     clocks:
>       minItems: 2
>       items:
> 

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

* Re: [PATCH 08/18] dt-bindings: display: rockchip: dw-hdmi: Add regulator support
@ 2021-12-08 16:35     ` Robin Murphy
  0 siblings, 0 replies; 123+ messages in thread
From: Robin Murphy @ 2021-12-08 16:35 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

On 2021-12-08 15:12, Sascha Hauer wrote:
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>   .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 ++++++
>   1 file changed, 6 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> index 2ab6578033da2..b9dca49aa6e05 100644
> --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> @@ -28,6 +28,12 @@ properties:
>     reg-io-width:
>       const: 4
>   
> +  avdd-0v9-supply:
> +    description: A 0.9V supply that powers up the SoC internal circuitry.

Might be worth calling out the actual pin name so it's abundantly clear 
for DT authors cross-referencing schematics. Annoyingly, some SoCs have 
HDMI_AVDD_1V0 instead of HDMI_AVDD_0V9 - I'm not sure it's worth 
splitting hairs that far in terms of the property name itself, but I'll 
leave that for others to decide.

> +  avdd-1v8-supply:
> +    description: A 1.8V supply that powers up the SoC internal circuitry.

At least HDMI_AVDD_1V8 seems more consistent.

Thanks,
Robin.

> +
>     clocks:
>       minItems: 2
>       items:
> 

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

* Re: [PATCH 08/18] dt-bindings: display: rockchip: dw-hdmi: Add regulator support
@ 2021-12-08 16:35     ` Robin Murphy
  0 siblings, 0 replies; 123+ messages in thread
From: Robin Murphy @ 2021-12-08 16:35 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

On 2021-12-08 15:12, Sascha Hauer wrote:
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>   .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 ++++++
>   1 file changed, 6 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> index 2ab6578033da2..b9dca49aa6e05 100644
> --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> @@ -28,6 +28,12 @@ properties:
>     reg-io-width:
>       const: 4
>   
> +  avdd-0v9-supply:
> +    description: A 0.9V supply that powers up the SoC internal circuitry.

Might be worth calling out the actual pin name so it's abundantly clear 
for DT authors cross-referencing schematics. Annoyingly, some SoCs have 
HDMI_AVDD_1V0 instead of HDMI_AVDD_0V9 - I'm not sure it's worth 
splitting hairs that far in terms of the property name itself, but I'll 
leave that for others to decide.

> +  avdd-1v8-supply:
> +    description: A 1.8V supply that powers up the SoC internal circuitry.

At least HDMI_AVDD_1V8 seems more consistent.

Thanks,
Robin.

> +
>     clocks:
>       minItems: 2
>       items:
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
  2021-12-08 15:12   ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 16:51     ` Heiko Stübner
  -1 siblings, 0 replies; 123+ messages in thread
From: Heiko Stübner @ 2021-12-08 16:51 UTC (permalink / raw)
  To: dri-devel, Sascha Hauer
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang, Peter Geis,
	Sascha Hauer

Hi Sascha,

Am Mittwoch, 8. Dezember 2021, 16:12:30 CET schrieb Sascha Hauer:
> On the rk3568 we have this (simplified) situation:
> 
>  .--------.     .-----.    .---------.
> -| hpll   |--.--| /n  |----|dclk_vop0|-
>  `--------´  |  `-----´    `---------´
>              |  .-----.    .---------.
>              `--| /m  |----|dclk_vop1|-
>              |  `-----´    `---------´
>              |             .---------.
>              `-------------|hdmi_ref |-
>                            `---------´
> 
> hpll is the PLL that drives the HDMI reference clock and the pixel
> clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
> and the hpll there are programmable dividers whereas the HDMI reference
> clock is directly connected to the hpll.
> 
> For the HDMI output to work the pixel clock must be the same as the HDMI
> reference clock, hence the dividers must be programmed to 1. Normally a
> rate change on dclk_vop0/1 propagates through to the hpll and the clock
> framework picks a suitable combination of hpll and divider settings. by
> accident it picks a divider setting of 1 for the standard 1080p case,
> but other divider settings for most other resolutions leaving the HDMI
> port non working.
> 
> This patch is not a solution, it merely puts the finger in the wound. We
> leave out the divider for the composite clock for dclk_vop0 which then
> leaves the divider at the bootloader default setting of 1. I assume
> the divider is disturbing only for the HDMI case, but needed for other
> outputs. Any thoughts how this can be handled?

I'm not even sure if/how the common clock framework keeps track of
diverging wishes to parent-rates :-) .

But I do see two direct issues in the _existing_ code.

dclk_vop0/1 uses CLK_SET_RATE_PARENT so is allowed to change
the rates of its parent clock(s).

Its parent clocks are not only hpll but can also be vpll, gpll and cpll.
So this can cause even more mayhem, if the ccf for example decides
to select the gpll and then change its rate,which may result in a lot
of peripherals getting their rates changed under them ;-) .

On the other hand I see in the clock driver that hdmi-ref is not allowed
to change its parent rate, so can only select between hpll and hpll_ph0
(1/2 the rate?).

So I guess, one way could be:
- add CLK_SET_RATE_PARENT to the hdmi-ref clock
- drop CLK_SET_RATE_PARENT from the dclks
- make sure hdmi-clock is set before the dclk


Heiko


> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/clk/rockchip/clk-rk3568.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c
> index 69a9e8069a486..2d04d8253ca22 100644
> --- a/drivers/clk/rockchip/clk-rk3568.c
> +++ b/drivers/clk/rockchip/clk-rk3568.c
> @@ -1038,8 +1038,8 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
>  			RK3568_CLKGATE_CON(20), 8, GFLAGS),
>  	GATE(HCLK_VOP, "hclk_vop", "hclk_vo", 0,
>  			RK3568_CLKGATE_CON(20), 9, GFLAGS),
> -	COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> -			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS, 0, 8, DFLAGS,
> +	COMPOSITE_NODIV(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> +			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS,
>  			RK3568_CLKGATE_CON(20), 10, GFLAGS),
>  	COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
>  			RK3568_CLKSEL_CON(40), 10, 2, MFLAGS, 0, 8, DFLAGS,
> 





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

* Re: [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
@ 2021-12-08 16:51     ` Heiko Stübner
  0 siblings, 0 replies; 123+ messages in thread
From: Heiko Stübner @ 2021-12-08 16:51 UTC (permalink / raw)
  To: dri-devel, Sascha Hauer
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang, Peter Geis,
	Sascha Hauer

Hi Sascha,

Am Mittwoch, 8. Dezember 2021, 16:12:30 CET schrieb Sascha Hauer:
> On the rk3568 we have this (simplified) situation:
> 
>  .--------.     .-----.    .---------.
> -| hpll   |--.--| /n  |----|dclk_vop0|-
>  `--------´  |  `-----´    `---------´
>              |  .-----.    .---------.
>              `--| /m  |----|dclk_vop1|-
>              |  `-----´    `---------´
>              |             .---------.
>              `-------------|hdmi_ref |-
>                            `---------´
> 
> hpll is the PLL that drives the HDMI reference clock and the pixel
> clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
> and the hpll there are programmable dividers whereas the HDMI reference
> clock is directly connected to the hpll.
> 
> For the HDMI output to work the pixel clock must be the same as the HDMI
> reference clock, hence the dividers must be programmed to 1. Normally a
> rate change on dclk_vop0/1 propagates through to the hpll and the clock
> framework picks a suitable combination of hpll and divider settings. by
> accident it picks a divider setting of 1 for the standard 1080p case,
> but other divider settings for most other resolutions leaving the HDMI
> port non working.
> 
> This patch is not a solution, it merely puts the finger in the wound. We
> leave out the divider for the composite clock for dclk_vop0 which then
> leaves the divider at the bootloader default setting of 1. I assume
> the divider is disturbing only for the HDMI case, but needed for other
> outputs. Any thoughts how this can be handled?

I'm not even sure if/how the common clock framework keeps track of
diverging wishes to parent-rates :-) .

But I do see two direct issues in the _existing_ code.

dclk_vop0/1 uses CLK_SET_RATE_PARENT so is allowed to change
the rates of its parent clock(s).

Its parent clocks are not only hpll but can also be vpll, gpll and cpll.
So this can cause even more mayhem, if the ccf for example decides
to select the gpll and then change its rate,which may result in a lot
of peripherals getting their rates changed under them ;-) .

On the other hand I see in the clock driver that hdmi-ref is not allowed
to change its parent rate, so can only select between hpll and hpll_ph0
(1/2 the rate?).

So I guess, one way could be:
- add CLK_SET_RATE_PARENT to the hdmi-ref clock
- drop CLK_SET_RATE_PARENT from the dclks
- make sure hdmi-clock is set before the dclk


Heiko


> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/clk/rockchip/clk-rk3568.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c
> index 69a9e8069a486..2d04d8253ca22 100644
> --- a/drivers/clk/rockchip/clk-rk3568.c
> +++ b/drivers/clk/rockchip/clk-rk3568.c
> @@ -1038,8 +1038,8 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
>  			RK3568_CLKGATE_CON(20), 8, GFLAGS),
>  	GATE(HCLK_VOP, "hclk_vop", "hclk_vo", 0,
>  			RK3568_CLKGATE_CON(20), 9, GFLAGS),
> -	COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> -			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS, 0, 8, DFLAGS,
> +	COMPOSITE_NODIV(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> +			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS,
>  			RK3568_CLKGATE_CON(20), 10, GFLAGS),
>  	COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
>  			RK3568_CLKSEL_CON(40), 10, 2, MFLAGS, 0, 8, DFLAGS,
> 





_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
@ 2021-12-08 16:51     ` Heiko Stübner
  0 siblings, 0 replies; 123+ messages in thread
From: Heiko Stübner @ 2021-12-08 16:51 UTC (permalink / raw)
  To: dri-devel, Sascha Hauer
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

Hi Sascha,

Am Mittwoch, 8. Dezember 2021, 16:12:30 CET schrieb Sascha Hauer:
> On the rk3568 we have this (simplified) situation:
> 
>  .--------.     .-----.    .---------.
> -| hpll   |--.--| /n  |----|dclk_vop0|-
>  `--------´  |  `-----´    `---------´
>              |  .-----.    .---------.
>              `--| /m  |----|dclk_vop1|-
>              |  `-----´    `---------´
>              |             .---------.
>              `-------------|hdmi_ref |-
>                            `---------´
> 
> hpll is the PLL that drives the HDMI reference clock and the pixel
> clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
> and the hpll there are programmable dividers whereas the HDMI reference
> clock is directly connected to the hpll.
> 
> For the HDMI output to work the pixel clock must be the same as the HDMI
> reference clock, hence the dividers must be programmed to 1. Normally a
> rate change on dclk_vop0/1 propagates through to the hpll and the clock
> framework picks a suitable combination of hpll and divider settings. by
> accident it picks a divider setting of 1 for the standard 1080p case,
> but other divider settings for most other resolutions leaving the HDMI
> port non working.
> 
> This patch is not a solution, it merely puts the finger in the wound. We
> leave out the divider for the composite clock for dclk_vop0 which then
> leaves the divider at the bootloader default setting of 1. I assume
> the divider is disturbing only for the HDMI case, but needed for other
> outputs. Any thoughts how this can be handled?

I'm not even sure if/how the common clock framework keeps track of
diverging wishes to parent-rates :-) .

But I do see two direct issues in the _existing_ code.

dclk_vop0/1 uses CLK_SET_RATE_PARENT so is allowed to change
the rates of its parent clock(s).

Its parent clocks are not only hpll but can also be vpll, gpll and cpll.
So this can cause even more mayhem, if the ccf for example decides
to select the gpll and then change its rate,which may result in a lot
of peripherals getting their rates changed under them ;-) .

On the other hand I see in the clock driver that hdmi-ref is not allowed
to change its parent rate, so can only select between hpll and hpll_ph0
(1/2 the rate?).

So I guess, one way could be:
- add CLK_SET_RATE_PARENT to the hdmi-ref clock
- drop CLK_SET_RATE_PARENT from the dclks
- make sure hdmi-clock is set before the dclk


Heiko


> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/clk/rockchip/clk-rk3568.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c
> index 69a9e8069a486..2d04d8253ca22 100644
> --- a/drivers/clk/rockchip/clk-rk3568.c
> +++ b/drivers/clk/rockchip/clk-rk3568.c
> @@ -1038,8 +1038,8 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
>  			RK3568_CLKGATE_CON(20), 8, GFLAGS),
>  	GATE(HCLK_VOP, "hclk_vop", "hclk_vo", 0,
>  			RK3568_CLKGATE_CON(20), 9, GFLAGS),
> -	COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> -			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS, 0, 8, DFLAGS,
> +	COMPOSITE_NODIV(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> +			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS,
>  			RK3568_CLKGATE_CON(20), 10, GFLAGS),
>  	COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
>  			RK3568_CLKSEL_CON(40), 10, 2, MFLAGS, 0, 8, DFLAGS,
> 





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

* Re: [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
@ 2021-12-08 16:51     ` Heiko Stübner
  0 siblings, 0 replies; 123+ messages in thread
From: Heiko Stübner @ 2021-12-08 16:51 UTC (permalink / raw)
  To: dri-devel, Sascha Hauer
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang, Peter Geis,
	Sascha Hauer

Hi Sascha,

Am Mittwoch, 8. Dezember 2021, 16:12:30 CET schrieb Sascha Hauer:
> On the rk3568 we have this (simplified) situation:
> 
>  .--------.     .-----.    .---------.
> -| hpll   |--.--| /n  |----|dclk_vop0|-
>  `--------´  |  `-----´    `---------´
>              |  .-----.    .---------.
>              `--| /m  |----|dclk_vop1|-
>              |  `-----´    `---------´
>              |             .---------.
>              `-------------|hdmi_ref |-
>                            `---------´
> 
> hpll is the PLL that drives the HDMI reference clock and the pixel
> clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
> and the hpll there are programmable dividers whereas the HDMI reference
> clock is directly connected to the hpll.
> 
> For the HDMI output to work the pixel clock must be the same as the HDMI
> reference clock, hence the dividers must be programmed to 1. Normally a
> rate change on dclk_vop0/1 propagates through to the hpll and the clock
> framework picks a suitable combination of hpll and divider settings. by
> accident it picks a divider setting of 1 for the standard 1080p case,
> but other divider settings for most other resolutions leaving the HDMI
> port non working.
> 
> This patch is not a solution, it merely puts the finger in the wound. We
> leave out the divider for the composite clock for dclk_vop0 which then
> leaves the divider at the bootloader default setting of 1. I assume
> the divider is disturbing only for the HDMI case, but needed for other
> outputs. Any thoughts how this can be handled?

I'm not even sure if/how the common clock framework keeps track of
diverging wishes to parent-rates :-) .

But I do see two direct issues in the _existing_ code.

dclk_vop0/1 uses CLK_SET_RATE_PARENT so is allowed to change
the rates of its parent clock(s).

Its parent clocks are not only hpll but can also be vpll, gpll and cpll.
So this can cause even more mayhem, if the ccf for example decides
to select the gpll and then change its rate,which may result in a lot
of peripherals getting their rates changed under them ;-) .

On the other hand I see in the clock driver that hdmi-ref is not allowed
to change its parent rate, so can only select between hpll and hpll_ph0
(1/2 the rate?).

So I guess, one way could be:
- add CLK_SET_RATE_PARENT to the hdmi-ref clock
- drop CLK_SET_RATE_PARENT from the dclks
- make sure hdmi-clock is set before the dclk


Heiko


> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/clk/rockchip/clk-rk3568.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c
> index 69a9e8069a486..2d04d8253ca22 100644
> --- a/drivers/clk/rockchip/clk-rk3568.c
> +++ b/drivers/clk/rockchip/clk-rk3568.c
> @@ -1038,8 +1038,8 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
>  			RK3568_CLKGATE_CON(20), 8, GFLAGS),
>  	GATE(HCLK_VOP, "hclk_vop", "hclk_vo", 0,
>  			RK3568_CLKGATE_CON(20), 9, GFLAGS),
> -	COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> -			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS, 0, 8, DFLAGS,
> +	COMPOSITE_NODIV(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> +			RK3568_CLKSEL_CON(39), 10, 2, MFLAGS,
>  			RK3568_CLKGATE_CON(20), 10, GFLAGS),
>  	COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
>  			RK3568_CLKSEL_CON(40), 10, 2, MFLAGS, 0, 8, DFLAGS,
> 





_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
  2021-12-08 15:12   ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 16:59     ` Johan Jonker
  -1 siblings, 0 replies; 123+ messages in thread
From: Johan Jonker @ 2021-12-08 16:59 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

Hi,

On 12/8/21 4:12 PM, Sascha Hauer wrote:
> From: Andy Yan <andy.yan@rock-chips.com>
> 
> The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
> It replaces the VOP unit found in the older Rockchip SoCs.
> 
> This driver has been derived from the downstream Rockchip Kernel and
> heavily modified:
> 
> - All nonstandard DRM properties have been removed
> - dropped struct vop2_plane_state and pass around less data between
>   functions
> - Dropped all DRM_FORMAT_* not known on upstream
> - rework register access to get rid of excessively used macros
> - Drop all waiting for framesyncs
> 
> The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
> board. Overlay support is tested with the modetest utility. AFBC support
> on the cluster windows is tested with weston-simple-dmabuf-egl on
> weston using the (yet to be upstreamed) panfrost driver support.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---

[..]

> +
> +static const struct of_device_id vop2_dt_match[] = {
> +	{
> +		.compatible = "rockchip,rk3568-vop",
> +		.data = &rk3568_vop
> +	}, {

> +		.compatible = "rockchip,rk3568-vop",

Maybe use:
.compatible = "rockchip,rk3566-vop",

> +		.data = &rk3566_vop
> +	}, {
> +	},

Maybe sort this list alphabetical based on compatible in case later more
SoCs are added.

rk3566
rk3568

===

The structure layout size above could be reduced for if we get more
compatible strings additions.

Example vop1:

static const struct of_device_id vop_driver_dt_match[] = {
	{ .compatible = "rockchip,rk3036-vop",
	  .data = &rk3036_vop },
	{ .compatible = "rockchip,rk3126-vop",
	  .data = &rk3126_vop },
	{ .compatible = "rockchip,px30-vop-big",
	  .data = &px30_vop_big },
	{ .compatible = "rockchip,px30-vop-lit",
	  .data = &px30_vop_lit },
	{ .compatible = "rockchip,rk3066-vop",
	  .data = &rk3066_vop },
	{ .compatible = "rockchip,rk3188-vop",
	  .data = &rk3188_vop },
	{ .compatible = "rockchip,rk3288-vop",
	  .data = &rk3288_vop },
	{ .compatible = "rockchip,rk3368-vop",
	  .data = &rk3368_vop },
	{ .compatible = "rockchip,rk3366-vop",
	  .data = &rk3366_vop },
	{ .compatible = "rockchip,rk3399-vop-big",
	  .data = &rk3399_vop_big },
	{ .compatible = "rockchip,rk3399-vop-lit",
	  .data = &rk3399_vop_lit },
	{ .compatible = "rockchip,rk3228-vop",
	  .data = &rk3228_vop },
	{ .compatible = "rockchip,rk3328-vop",
	  .data = &rk3328_vop },
	{},
};

> +};
> +MODULE_DEVICE_TABLE(of, vop2_dt_match);
> +
> +static int vop2_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +
> +	return component_add(dev, &vop2_component_ops);
> +}
> +
> +static int vop2_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &vop2_component_ops);
> +
> +	return 0;
> +}
> +
> +struct platform_driver vop2_platform_driver = {
> +	.probe = vop2_probe,
> +	.remove = vop2_remove,
> +	.driver = {
> +		.name = "rockchip-vop2",
> +		.of_match_table = of_match_ptr(vop2_dt_match),
> +	},
> +};
> 

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-08 16:59     ` Johan Jonker
  0 siblings, 0 replies; 123+ messages in thread
From: Johan Jonker @ 2021-12-08 16:59 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

Hi,

On 12/8/21 4:12 PM, Sascha Hauer wrote:
> From: Andy Yan <andy.yan@rock-chips.com>
> 
> The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
> It replaces the VOP unit found in the older Rockchip SoCs.
> 
> This driver has been derived from the downstream Rockchip Kernel and
> heavily modified:
> 
> - All nonstandard DRM properties have been removed
> - dropped struct vop2_plane_state and pass around less data between
>   functions
> - Dropped all DRM_FORMAT_* not known on upstream
> - rework register access to get rid of excessively used macros
> - Drop all waiting for framesyncs
> 
> The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
> board. Overlay support is tested with the modetest utility. AFBC support
> on the cluster windows is tested with weston-simple-dmabuf-egl on
> weston using the (yet to be upstreamed) panfrost driver support.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---

[..]

> +
> +static const struct of_device_id vop2_dt_match[] = {
> +	{
> +		.compatible = "rockchip,rk3568-vop",
> +		.data = &rk3568_vop
> +	}, {

> +		.compatible = "rockchip,rk3568-vop",

Maybe use:
.compatible = "rockchip,rk3566-vop",

> +		.data = &rk3566_vop
> +	}, {
> +	},

Maybe sort this list alphabetical based on compatible in case later more
SoCs are added.

rk3566
rk3568

===

The structure layout size above could be reduced for if we get more
compatible strings additions.

Example vop1:

static const struct of_device_id vop_driver_dt_match[] = {
	{ .compatible = "rockchip,rk3036-vop",
	  .data = &rk3036_vop },
	{ .compatible = "rockchip,rk3126-vop",
	  .data = &rk3126_vop },
	{ .compatible = "rockchip,px30-vop-big",
	  .data = &px30_vop_big },
	{ .compatible = "rockchip,px30-vop-lit",
	  .data = &px30_vop_lit },
	{ .compatible = "rockchip,rk3066-vop",
	  .data = &rk3066_vop },
	{ .compatible = "rockchip,rk3188-vop",
	  .data = &rk3188_vop },
	{ .compatible = "rockchip,rk3288-vop",
	  .data = &rk3288_vop },
	{ .compatible = "rockchip,rk3368-vop",
	  .data = &rk3368_vop },
	{ .compatible = "rockchip,rk3366-vop",
	  .data = &rk3366_vop },
	{ .compatible = "rockchip,rk3399-vop-big",
	  .data = &rk3399_vop_big },
	{ .compatible = "rockchip,rk3399-vop-lit",
	  .data = &rk3399_vop_lit },
	{ .compatible = "rockchip,rk3228-vop",
	  .data = &rk3228_vop },
	{ .compatible = "rockchip,rk3328-vop",
	  .data = &rk3328_vop },
	{},
};

> +};
> +MODULE_DEVICE_TABLE(of, vop2_dt_match);
> +
> +static int vop2_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +
> +	return component_add(dev, &vop2_component_ops);
> +}
> +
> +static int vop2_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &vop2_component_ops);
> +
> +	return 0;
> +}
> +
> +struct platform_driver vop2_platform_driver = {
> +	.probe = vop2_probe,
> +	.remove = vop2_remove,
> +	.driver = {
> +		.name = "rockchip-vop2",
> +		.of_match_table = of_match_ptr(vop2_dt_match),
> +	},
> +};
> 

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-08 16:59     ` Johan Jonker
  0 siblings, 0 replies; 123+ messages in thread
From: Johan Jonker @ 2021-12-08 16:59 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sandy Huang,
	linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

Hi,

On 12/8/21 4:12 PM, Sascha Hauer wrote:
> From: Andy Yan <andy.yan@rock-chips.com>
> 
> The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
> It replaces the VOP unit found in the older Rockchip SoCs.
> 
> This driver has been derived from the downstream Rockchip Kernel and
> heavily modified:
> 
> - All nonstandard DRM properties have been removed
> - dropped struct vop2_plane_state and pass around less data between
>   functions
> - Dropped all DRM_FORMAT_* not known on upstream
> - rework register access to get rid of excessively used macros
> - Drop all waiting for framesyncs
> 
> The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
> board. Overlay support is tested with the modetest utility. AFBC support
> on the cluster windows is tested with weston-simple-dmabuf-egl on
> weston using the (yet to be upstreamed) panfrost driver support.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---

[..]

> +
> +static const struct of_device_id vop2_dt_match[] = {
> +	{
> +		.compatible = "rockchip,rk3568-vop",
> +		.data = &rk3568_vop
> +	}, {

> +		.compatible = "rockchip,rk3568-vop",

Maybe use:
.compatible = "rockchip,rk3566-vop",

> +		.data = &rk3566_vop
> +	}, {
> +	},

Maybe sort this list alphabetical based on compatible in case later more
SoCs are added.

rk3566
rk3568

===

The structure layout size above could be reduced for if we get more
compatible strings additions.

Example vop1:

static const struct of_device_id vop_driver_dt_match[] = {
	{ .compatible = "rockchip,rk3036-vop",
	  .data = &rk3036_vop },
	{ .compatible = "rockchip,rk3126-vop",
	  .data = &rk3126_vop },
	{ .compatible = "rockchip,px30-vop-big",
	  .data = &px30_vop_big },
	{ .compatible = "rockchip,px30-vop-lit",
	  .data = &px30_vop_lit },
	{ .compatible = "rockchip,rk3066-vop",
	  .data = &rk3066_vop },
	{ .compatible = "rockchip,rk3188-vop",
	  .data = &rk3188_vop },
	{ .compatible = "rockchip,rk3288-vop",
	  .data = &rk3288_vop },
	{ .compatible = "rockchip,rk3368-vop",
	  .data = &rk3368_vop },
	{ .compatible = "rockchip,rk3366-vop",
	  .data = &rk3366_vop },
	{ .compatible = "rockchip,rk3399-vop-big",
	  .data = &rk3399_vop_big },
	{ .compatible = "rockchip,rk3399-vop-lit",
	  .data = &rk3399_vop_lit },
	{ .compatible = "rockchip,rk3228-vop",
	  .data = &rk3228_vop },
	{ .compatible = "rockchip,rk3328-vop",
	  .data = &rk3328_vop },
	{},
};

> +};
> +MODULE_DEVICE_TABLE(of, vop2_dt_match);
> +
> +static int vop2_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +
> +	return component_add(dev, &vop2_component_ops);
> +}
> +
> +static int vop2_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &vop2_component_ops);
> +
> +	return 0;
> +}
> +
> +struct platform_driver vop2_platform_driver = {
> +	.probe = vop2_probe,
> +	.remove = vop2_remove,
> +	.driver = {
> +		.name = "rockchip-vop2",
> +		.of_match_table = of_match_ptr(vop2_dt_match),
> +	},
> +};
> 

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-08 16:59     ` Johan Jonker
  0 siblings, 0 replies; 123+ messages in thread
From: Johan Jonker @ 2021-12-08 16:59 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

Hi,

On 12/8/21 4:12 PM, Sascha Hauer wrote:
> From: Andy Yan <andy.yan@rock-chips.com>
> 
> The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
> It replaces the VOP unit found in the older Rockchip SoCs.
> 
> This driver has been derived from the downstream Rockchip Kernel and
> heavily modified:
> 
> - All nonstandard DRM properties have been removed
> - dropped struct vop2_plane_state and pass around less data between
>   functions
> - Dropped all DRM_FORMAT_* not known on upstream
> - rework register access to get rid of excessively used macros
> - Drop all waiting for framesyncs
> 
> The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
> board. Overlay support is tested with the modetest utility. AFBC support
> on the cluster windows is tested with weston-simple-dmabuf-egl on
> weston using the (yet to be upstreamed) panfrost driver support.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---

[..]

> +
> +static const struct of_device_id vop2_dt_match[] = {
> +	{
> +		.compatible = "rockchip,rk3568-vop",
> +		.data = &rk3568_vop
> +	}, {

> +		.compatible = "rockchip,rk3568-vop",

Maybe use:
.compatible = "rockchip,rk3566-vop",

> +		.data = &rk3566_vop
> +	}, {
> +	},

Maybe sort this list alphabetical based on compatible in case later more
SoCs are added.

rk3566
rk3568

===

The structure layout size above could be reduced for if we get more
compatible strings additions.

Example vop1:

static const struct of_device_id vop_driver_dt_match[] = {
	{ .compatible = "rockchip,rk3036-vop",
	  .data = &rk3036_vop },
	{ .compatible = "rockchip,rk3126-vop",
	  .data = &rk3126_vop },
	{ .compatible = "rockchip,px30-vop-big",
	  .data = &px30_vop_big },
	{ .compatible = "rockchip,px30-vop-lit",
	  .data = &px30_vop_lit },
	{ .compatible = "rockchip,rk3066-vop",
	  .data = &rk3066_vop },
	{ .compatible = "rockchip,rk3188-vop",
	  .data = &rk3188_vop },
	{ .compatible = "rockchip,rk3288-vop",
	  .data = &rk3288_vop },
	{ .compatible = "rockchip,rk3368-vop",
	  .data = &rk3368_vop },
	{ .compatible = "rockchip,rk3366-vop",
	  .data = &rk3366_vop },
	{ .compatible = "rockchip,rk3399-vop-big",
	  .data = &rk3399_vop_big },
	{ .compatible = "rockchip,rk3399-vop-lit",
	  .data = &rk3399_vop_lit },
	{ .compatible = "rockchip,rk3228-vop",
	  .data = &rk3228_vop },
	{ .compatible = "rockchip,rk3328-vop",
	  .data = &rk3328_vop },
	{},
};

> +};
> +MODULE_DEVICE_TABLE(of, vop2_dt_match);
> +
> +static int vop2_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +
> +	return component_add(dev, &vop2_component_ops);
> +}
> +
> +static int vop2_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &vop2_component_ops);
> +
> +	return 0;
> +}
> +
> +struct platform_driver vop2_platform_driver = {
> +	.probe = vop2_probe,
> +	.remove = vop2_remove,
> +	.driver = {
> +		.name = "rockchip-vop2",
> +		.of_match_table = of_match_ptr(vop2_dt_match),
> +	},
> +};
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 13/18] arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
  2021-12-08 15:12   ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 17:30     ` Johan Jonker
  -1 siblings, 0 replies; 123+ messages in thread
From: Johan Jonker @ 2021-12-08 17:30 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

Hi,

Could add a patch version to the subject?

On 12/8/21 4:12 PM, Sascha Hauer wrote:
> This enabled the VOP2 display controller along with hdmi and the
> required port routes which is enough to get a picture out of the
> hdmi port of the board.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../boot/dts/rockchip/rk3568-evb1-v10.dts     | 31 +++++++++++++++++++
>  1 file changed, 31 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> index 184e2aa2416af..b1b0963fa8525 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> @@ -7,6 +7,7 @@
>  /dts-v1/;
>  #include <dt-bindings/gpio/gpio.h>
>  #include <dt-bindings/pinctrl/rockchip.h>
> +#include <dt-bindings/soc/rockchip,vop2.h>
>  #include "rk3568.dtsi"
>  
>  / {
> @@ -106,6 +107,12 @@ &gmac1m1_rgmii_clk
>  	status = "okay";
>  };
>  
> +&hdmi {

> +	status = "okay";
> +	avdd-0v9-supply = <&vdda0v9_image>;
> +	avdd-1v8-supply = <&vcca1v8_image>;

status below

> +};

===
Example from rk3066a-mk808.dts
In dtsi:
	hdmi {
		ports {
			#address-cells = <1>;
			#size-cells = <0>;
			hdmi_in: port@0 {
				reg = <0>;
				#address-cells = <1>;
				#size-cells = <0>;
			};

			hdmi_out: port@1 {
				reg = <1>;
			};

===
In dts:
	hdmi-con {
		compatible = "hdmi-connector";
		type = "c";

		port {
			hdmi_con_in: endpoint {
				remote-endpoint = <&hdmi_out_con>;
			};
		};
	};

===

&hdmi_out {
	hdmi_out_con: endpoint {
		remote-endpoint = <&hdmi_con_in>;
	};
};

===

> +
>  &i2c0 {
>  	status = "okay";
>  
> @@ -390,3 +397,27 @@ &sdmmc0 {
>  &uart2 {
>  	status = "okay";
>  };
> +
> +&vop {

> +	status = "okay";
> +	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
> +	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;

status below

> +};
> +
> +&vop_mmu {
> +	status = "okay";
> +};
> +
> +&hdmi_in {
> +	hdmi_in_vp0: endpoint@0 {
> +		reg = <0>;
> +		remote-endpoint = <&vp0_out_hdmi>;
> +	};
> +};
> +
> +&vp0 {
> +	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
> +		reg = <RK3568_VOP2_EP_HDMI>;
> +		remote-endpoint = <&hdmi_in_vp0>;
> +	};
> +};
> 

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

* Re: [PATCH 13/18] arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
@ 2021-12-08 17:30     ` Johan Jonker
  0 siblings, 0 replies; 123+ messages in thread
From: Johan Jonker @ 2021-12-08 17:30 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

Hi,

Could add a patch version to the subject?

On 12/8/21 4:12 PM, Sascha Hauer wrote:
> This enabled the VOP2 display controller along with hdmi and the
> required port routes which is enough to get a picture out of the
> hdmi port of the board.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../boot/dts/rockchip/rk3568-evb1-v10.dts     | 31 +++++++++++++++++++
>  1 file changed, 31 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> index 184e2aa2416af..b1b0963fa8525 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> @@ -7,6 +7,7 @@
>  /dts-v1/;
>  #include <dt-bindings/gpio/gpio.h>
>  #include <dt-bindings/pinctrl/rockchip.h>
> +#include <dt-bindings/soc/rockchip,vop2.h>
>  #include "rk3568.dtsi"
>  
>  / {
> @@ -106,6 +107,12 @@ &gmac1m1_rgmii_clk
>  	status = "okay";
>  };
>  
> +&hdmi {

> +	status = "okay";
> +	avdd-0v9-supply = <&vdda0v9_image>;
> +	avdd-1v8-supply = <&vcca1v8_image>;

status below

> +};

===
Example from rk3066a-mk808.dts
In dtsi:
	hdmi {
		ports {
			#address-cells = <1>;
			#size-cells = <0>;
			hdmi_in: port@0 {
				reg = <0>;
				#address-cells = <1>;
				#size-cells = <0>;
			};

			hdmi_out: port@1 {
				reg = <1>;
			};

===
In dts:
	hdmi-con {
		compatible = "hdmi-connector";
		type = "c";

		port {
			hdmi_con_in: endpoint {
				remote-endpoint = <&hdmi_out_con>;
			};
		};
	};

===

&hdmi_out {
	hdmi_out_con: endpoint {
		remote-endpoint = <&hdmi_con_in>;
	};
};

===

> +
>  &i2c0 {
>  	status = "okay";
>  
> @@ -390,3 +397,27 @@ &sdmmc0 {
>  &uart2 {
>  	status = "okay";
>  };
> +
> +&vop {

> +	status = "okay";
> +	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
> +	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;

status below

> +};
> +
> +&vop_mmu {
> +	status = "okay";
> +};
> +
> +&hdmi_in {
> +	hdmi_in_vp0: endpoint@0 {
> +		reg = <0>;
> +		remote-endpoint = <&vp0_out_hdmi>;
> +	};
> +};
> +
> +&vp0 {
> +	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
> +		reg = <RK3568_VOP2_EP_HDMI>;
> +		remote-endpoint = <&hdmi_in_vp0>;
> +	};
> +};
> 

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 13/18] arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
@ 2021-12-08 17:30     ` Johan Jonker
  0 siblings, 0 replies; 123+ messages in thread
From: Johan Jonker @ 2021-12-08 17:30 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sandy Huang,
	linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

Hi,

Could add a patch version to the subject?

On 12/8/21 4:12 PM, Sascha Hauer wrote:
> This enabled the VOP2 display controller along with hdmi and the
> required port routes which is enough to get a picture out of the
> hdmi port of the board.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../boot/dts/rockchip/rk3568-evb1-v10.dts     | 31 +++++++++++++++++++
>  1 file changed, 31 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> index 184e2aa2416af..b1b0963fa8525 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> @@ -7,6 +7,7 @@
>  /dts-v1/;
>  #include <dt-bindings/gpio/gpio.h>
>  #include <dt-bindings/pinctrl/rockchip.h>
> +#include <dt-bindings/soc/rockchip,vop2.h>
>  #include "rk3568.dtsi"
>  
>  / {
> @@ -106,6 +107,12 @@ &gmac1m1_rgmii_clk
>  	status = "okay";
>  };
>  
> +&hdmi {

> +	status = "okay";
> +	avdd-0v9-supply = <&vdda0v9_image>;
> +	avdd-1v8-supply = <&vcca1v8_image>;

status below

> +};

===
Example from rk3066a-mk808.dts
In dtsi:
	hdmi {
		ports {
			#address-cells = <1>;
			#size-cells = <0>;
			hdmi_in: port@0 {
				reg = <0>;
				#address-cells = <1>;
				#size-cells = <0>;
			};

			hdmi_out: port@1 {
				reg = <1>;
			};

===
In dts:
	hdmi-con {
		compatible = "hdmi-connector";
		type = "c";

		port {
			hdmi_con_in: endpoint {
				remote-endpoint = <&hdmi_out_con>;
			};
		};
	};

===

&hdmi_out {
	hdmi_out_con: endpoint {
		remote-endpoint = <&hdmi_con_in>;
	};
};

===

> +
>  &i2c0 {
>  	status = "okay";
>  
> @@ -390,3 +397,27 @@ &sdmmc0 {
>  &uart2 {
>  	status = "okay";
>  };
> +
> +&vop {

> +	status = "okay";
> +	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
> +	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;

status below

> +};
> +
> +&vop_mmu {
> +	status = "okay";
> +};
> +
> +&hdmi_in {
> +	hdmi_in_vp0: endpoint@0 {
> +		reg = <0>;
> +		remote-endpoint = <&vp0_out_hdmi>;
> +	};
> +};
> +
> +&vp0 {
> +	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
> +		reg = <RK3568_VOP2_EP_HDMI>;
> +		remote-endpoint = <&hdmi_in_vp0>;
> +	};
> +};
> 

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

* Re: [PATCH 13/18] arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi
@ 2021-12-08 17:30     ` Johan Jonker
  0 siblings, 0 replies; 123+ messages in thread
From: Johan Jonker @ 2021-12-08 17:30 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

Hi,

Could add a patch version to the subject?

On 12/8/21 4:12 PM, Sascha Hauer wrote:
> This enabled the VOP2 display controller along with hdmi and the
> required port routes which is enough to get a picture out of the
> hdmi port of the board.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../boot/dts/rockchip/rk3568-evb1-v10.dts     | 31 +++++++++++++++++++
>  1 file changed, 31 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> index 184e2aa2416af..b1b0963fa8525 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
> @@ -7,6 +7,7 @@
>  /dts-v1/;
>  #include <dt-bindings/gpio/gpio.h>
>  #include <dt-bindings/pinctrl/rockchip.h>
> +#include <dt-bindings/soc/rockchip,vop2.h>
>  #include "rk3568.dtsi"
>  
>  / {
> @@ -106,6 +107,12 @@ &gmac1m1_rgmii_clk
>  	status = "okay";
>  };
>  
> +&hdmi {

> +	status = "okay";
> +	avdd-0v9-supply = <&vdda0v9_image>;
> +	avdd-1v8-supply = <&vcca1v8_image>;

status below

> +};

===
Example from rk3066a-mk808.dts
In dtsi:
	hdmi {
		ports {
			#address-cells = <1>;
			#size-cells = <0>;
			hdmi_in: port@0 {
				reg = <0>;
				#address-cells = <1>;
				#size-cells = <0>;
			};

			hdmi_out: port@1 {
				reg = <1>;
			};

===
In dts:
	hdmi-con {
		compatible = "hdmi-connector";
		type = "c";

		port {
			hdmi_con_in: endpoint {
				remote-endpoint = <&hdmi_out_con>;
			};
		};
	};

===

&hdmi_out {
	hdmi_out_con: endpoint {
		remote-endpoint = <&hdmi_con_in>;
	};
};

===

> +
>  &i2c0 {
>  	status = "okay";
>  
> @@ -390,3 +397,27 @@ &sdmmc0 {
>  &uart2 {
>  	status = "okay";
>  };
> +
> +&vop {

> +	status = "okay";
> +	assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
> +	assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;

status below

> +};
> +
> +&vop_mmu {
> +	status = "okay";
> +};
> +
> +&hdmi_in {
> +	hdmi_in_vp0: endpoint@0 {
> +		reg = <0>;
> +		remote-endpoint = <&vp0_out_hdmi>;
> +	};
> +};
> +
> +&vp0 {
> +	vp0_out_hdmi: endpoint@RK3568_VOP2_EP_HDMI {
> +		reg = <RK3568_VOP2_EP_HDMI>;
> +		remote-endpoint = <&hdmi_in_vp0>;
> +	};
> +};
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
  2021-12-08 15:12   ` Sascha Hauer
  (?)
  (?)
@ 2021-12-08 21:50     ` kernel test robot
  -1 siblings, 0 replies; 123+ messages in thread
From: kernel test robot @ 2021-12-08 21:50 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: kbuild-all, devicetree, Benjamin Gaignard, Peter Geis,
	Sascha Hauer, Sandy Huang, linux-rockchip, Michael Riesch,
	kernel, Andy Yan

Hi Sascha,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on rockchip/for-next]
[also build test WARNING on drm/drm-next drm-intel/for-linux-next drm-exynos/exynos-drm-next v5.16-rc4]
[cannot apply to drm-tip/drm-tip tegra-drm/drm/tegra/for-next airlied/drm-next next-20211208]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: mips-allmodconfig (https://download.01.org/0day-ci/archive/20211209/202112090519.Beunfs20-lkp@intel.com/config)
compiler: mips-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/8d57a528cbdfec4716a21d22d3d6c04c40451355
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
        git checkout 8d57a528cbdfec4716a21d22d3d6c04c40451355
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=mips SHELL=/bin/bash drivers/gpu/drm/rockchip/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_setup_cluster_alpha':
>> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1861:33: warning: variable 'top_win_pstate' set but not used [-Wunused-but-set-variable]
    1861 |         struct drm_plane_state *top_win_pstate;
         |                                 ^~~~~~~~~~~~~~


vim +/top_win_pstate +1861 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c

  1855	
  1856	static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win)
  1857	{
  1858		uint32_t offset = (main_win->data->phys_id * 0x10);
  1859		struct vop2_alpha_config alpha_config;
  1860		struct vop2_alpha alpha;
> 1861		struct drm_plane_state *top_win_pstate;
  1862		struct drm_plane_state *bottom_win_pstate;
  1863		bool src_pixel_alpha_en = false;
  1864		uint16_t src_glb_alpha_val, dst_glb_alpha_val;
  1865		bool premulti_en = false;
  1866		bool swap = false;
  1867	
  1868		/* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */
  1869		top_win_pstate = NULL;
  1870		bottom_win_pstate = main_win->base.state;
  1871		src_glb_alpha_val = 0;
  1872		dst_glb_alpha_val = main_win->base.state->alpha;
  1873	
  1874		if (!bottom_win_pstate->fb)
  1875			return;
  1876	
  1877		alpha_config.src_premulti_en = premulti_en;
  1878		alpha_config.dst_premulti_en = false;
  1879		alpha_config.src_pixel_alpha_en = src_pixel_alpha_en;
  1880		alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
  1881		alpha_config.src_glb_alpha_value = src_glb_alpha_val;
  1882		alpha_config.dst_glb_alpha_value = dst_glb_alpha_val;
  1883		vop2_parse_alpha(&alpha_config, &alpha);
  1884	
  1885		alpha.src_color_ctrl.bits.src_dst_swap = swap;
  1886		vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset,
  1887			    alpha.src_color_ctrl.val);
  1888		vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset,
  1889			    alpha.dst_color_ctrl.val);
  1890		vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset,
  1891			    alpha.src_alpha_ctrl.val);
  1892		vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset,
  1893			    alpha.dst_alpha_ctrl.val);
  1894	}
  1895	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-08 21:50     ` kernel test robot
  0 siblings, 0 replies; 123+ messages in thread
From: kernel test robot @ 2021-12-08 21:50 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: devicetree, kbuild-all, kernel, Sascha Hauer, Sandy Huang,
	linux-rockchip, Michael Riesch, Peter Geis, Andy Yan,
	Benjamin Gaignard

Hi Sascha,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on rockchip/for-next]
[also build test WARNING on drm/drm-next drm-intel/for-linux-next drm-exynos/exynos-drm-next v5.16-rc4]
[cannot apply to drm-tip/drm-tip tegra-drm/drm/tegra/for-next airlied/drm-next next-20211208]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: mips-allmodconfig (https://download.01.org/0day-ci/archive/20211209/202112090519.Beunfs20-lkp@intel.com/config)
compiler: mips-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/8d57a528cbdfec4716a21d22d3d6c04c40451355
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
        git checkout 8d57a528cbdfec4716a21d22d3d6c04c40451355
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=mips SHELL=/bin/bash drivers/gpu/drm/rockchip/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_setup_cluster_alpha':
>> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1861:33: warning: variable 'top_win_pstate' set but not used [-Wunused-but-set-variable]
    1861 |         struct drm_plane_state *top_win_pstate;
         |                                 ^~~~~~~~~~~~~~


vim +/top_win_pstate +1861 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c

  1855	
  1856	static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win)
  1857	{
  1858		uint32_t offset = (main_win->data->phys_id * 0x10);
  1859		struct vop2_alpha_config alpha_config;
  1860		struct vop2_alpha alpha;
> 1861		struct drm_plane_state *top_win_pstate;
  1862		struct drm_plane_state *bottom_win_pstate;
  1863		bool src_pixel_alpha_en = false;
  1864		uint16_t src_glb_alpha_val, dst_glb_alpha_val;
  1865		bool premulti_en = false;
  1866		bool swap = false;
  1867	
  1868		/* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */
  1869		top_win_pstate = NULL;
  1870		bottom_win_pstate = main_win->base.state;
  1871		src_glb_alpha_val = 0;
  1872		dst_glb_alpha_val = main_win->base.state->alpha;
  1873	
  1874		if (!bottom_win_pstate->fb)
  1875			return;
  1876	
  1877		alpha_config.src_premulti_en = premulti_en;
  1878		alpha_config.dst_premulti_en = false;
  1879		alpha_config.src_pixel_alpha_en = src_pixel_alpha_en;
  1880		alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
  1881		alpha_config.src_glb_alpha_value = src_glb_alpha_val;
  1882		alpha_config.dst_glb_alpha_value = dst_glb_alpha_val;
  1883		vop2_parse_alpha(&alpha_config, &alpha);
  1884	
  1885		alpha.src_color_ctrl.bits.src_dst_swap = swap;
  1886		vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset,
  1887			    alpha.src_color_ctrl.val);
  1888		vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset,
  1889			    alpha.dst_color_ctrl.val);
  1890		vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset,
  1891			    alpha.src_alpha_ctrl.val);
  1892		vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset,
  1893			    alpha.dst_alpha_ctrl.val);
  1894	}
  1895	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-08 21:50     ` kernel test robot
  0 siblings, 0 replies; 123+ messages in thread
From: kernel test robot @ 2021-12-08 21:50 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: kbuild-all, devicetree, Benjamin Gaignard, Peter Geis,
	Sascha Hauer, Sandy Huang, linux-rockchip, Michael Riesch,
	kernel, Andy Yan

Hi Sascha,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on rockchip/for-next]
[also build test WARNING on drm/drm-next drm-intel/for-linux-next drm-exynos/exynos-drm-next v5.16-rc4]
[cannot apply to drm-tip/drm-tip tegra-drm/drm/tegra/for-next airlied/drm-next next-20211208]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: mips-allmodconfig (https://download.01.org/0day-ci/archive/20211209/202112090519.Beunfs20-lkp@intel.com/config)
compiler: mips-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/8d57a528cbdfec4716a21d22d3d6c04c40451355
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
        git checkout 8d57a528cbdfec4716a21d22d3d6c04c40451355
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=mips SHELL=/bin/bash drivers/gpu/drm/rockchip/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_setup_cluster_alpha':
>> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1861:33: warning: variable 'top_win_pstate' set but not used [-Wunused-but-set-variable]
    1861 |         struct drm_plane_state *top_win_pstate;
         |                                 ^~~~~~~~~~~~~~


vim +/top_win_pstate +1861 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c

  1855	
  1856	static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win)
  1857	{
  1858		uint32_t offset = (main_win->data->phys_id * 0x10);
  1859		struct vop2_alpha_config alpha_config;
  1860		struct vop2_alpha alpha;
> 1861		struct drm_plane_state *top_win_pstate;
  1862		struct drm_plane_state *bottom_win_pstate;
  1863		bool src_pixel_alpha_en = false;
  1864		uint16_t src_glb_alpha_val, dst_glb_alpha_val;
  1865		bool premulti_en = false;
  1866		bool swap = false;
  1867	
  1868		/* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */
  1869		top_win_pstate = NULL;
  1870		bottom_win_pstate = main_win->base.state;
  1871		src_glb_alpha_val = 0;
  1872		dst_glb_alpha_val = main_win->base.state->alpha;
  1873	
  1874		if (!bottom_win_pstate->fb)
  1875			return;
  1876	
  1877		alpha_config.src_premulti_en = premulti_en;
  1878		alpha_config.dst_premulti_en = false;
  1879		alpha_config.src_pixel_alpha_en = src_pixel_alpha_en;
  1880		alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
  1881		alpha_config.src_glb_alpha_value = src_glb_alpha_val;
  1882		alpha_config.dst_glb_alpha_value = dst_glb_alpha_val;
  1883		vop2_parse_alpha(&alpha_config, &alpha);
  1884	
  1885		alpha.src_color_ctrl.bits.src_dst_swap = swap;
  1886		vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset,
  1887			    alpha.src_color_ctrl.val);
  1888		vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset,
  1889			    alpha.dst_color_ctrl.val);
  1890		vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset,
  1891			    alpha.src_alpha_ctrl.val);
  1892		vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset,
  1893			    alpha.dst_alpha_ctrl.val);
  1894	}
  1895	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-08 21:50     ` kernel test robot
  0 siblings, 0 replies; 123+ messages in thread
From: kernel test robot @ 2021-12-08 21:50 UTC (permalink / raw)
  To: kbuild-all

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

Hi Sascha,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on rockchip/for-next]
[also build test WARNING on drm/drm-next drm-intel/for-linux-next drm-exynos/exynos-drm-next v5.16-rc4]
[cannot apply to drm-tip/drm-tip tegra-drm/drm/tegra/for-next airlied/drm-next next-20211208]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: mips-allmodconfig (https://download.01.org/0day-ci/archive/20211209/202112090519.Beunfs20-lkp(a)intel.com/config)
compiler: mips-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/8d57a528cbdfec4716a21d22d3d6c04c40451355
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
        git checkout 8d57a528cbdfec4716a21d22d3d6c04c40451355
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=mips SHELL=/bin/bash drivers/gpu/drm/rockchip/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_setup_cluster_alpha':
>> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1861:33: warning: variable 'top_win_pstate' set but not used [-Wunused-but-set-variable]
    1861 |         struct drm_plane_state *top_win_pstate;
         |                                 ^~~~~~~~~~~~~~


vim +/top_win_pstate +1861 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c

  1855	
  1856	static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win)
  1857	{
  1858		uint32_t offset = (main_win->data->phys_id * 0x10);
  1859		struct vop2_alpha_config alpha_config;
  1860		struct vop2_alpha alpha;
> 1861		struct drm_plane_state *top_win_pstate;
  1862		struct drm_plane_state *bottom_win_pstate;
  1863		bool src_pixel_alpha_en = false;
  1864		uint16_t src_glb_alpha_val, dst_glb_alpha_val;
  1865		bool premulti_en = false;
  1866		bool swap = false;
  1867	
  1868		/* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */
  1869		top_win_pstate = NULL;
  1870		bottom_win_pstate = main_win->base.state;
  1871		src_glb_alpha_val = 0;
  1872		dst_glb_alpha_val = main_win->base.state->alpha;
  1873	
  1874		if (!bottom_win_pstate->fb)
  1875			return;
  1876	
  1877		alpha_config.src_premulti_en = premulti_en;
  1878		alpha_config.dst_premulti_en = false;
  1879		alpha_config.src_pixel_alpha_en = src_pixel_alpha_en;
  1880		alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
  1881		alpha_config.src_glb_alpha_value = src_glb_alpha_val;
  1882		alpha_config.dst_glb_alpha_value = dst_glb_alpha_val;
  1883		vop2_parse_alpha(&alpha_config, &alpha);
  1884	
  1885		alpha.src_color_ctrl.bits.src_dst_swap = swap;
  1886		vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset,
  1887			    alpha.src_color_ctrl.val);
  1888		vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset,
  1889			    alpha.dst_color_ctrl.val);
  1890		vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset,
  1891			    alpha.src_alpha_ctrl.val);
  1892		vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset,
  1893			    alpha.dst_alpha_ctrl.val);
  1894	}
  1895	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
  2021-12-08 15:12   ` Sascha Hauer
  (?)
  (?)
@ 2021-12-09  0:49     ` kernel test robot
  -1 siblings, 0 replies; 123+ messages in thread
From: kernel test robot @ 2021-12-09  0:49 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: kbuild-all, devicetree, Benjamin Gaignard, Peter Geis,
	Sascha Hauer, Sandy Huang, linux-rockchip, Michael Riesch,
	kernel, Andy Yan

Hi Sascha,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on rockchip/for-next]
[also build test ERROR on drm/drm-next drm-intel/for-linux-next drm-exynos/exynos-drm-next v5.16-rc4]
[cannot apply to drm-tip/drm-tip tegra-drm/drm/tegra/for-next airlied/drm-next next-20211208]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: arc-allyesconfig (https://download.01.org/0day-ci/archive/20211209/202112090830.YVovXyce-lkp@intel.com/config)
compiler: arceb-elf-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/8d57a528cbdfec4716a21d22d3d6c04c40451355
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
        git checkout 8d57a528cbdfec4716a21d22d3d6c04c40451355
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arc SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_dither_setup':
>> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1489:22: error: implicit declaration of function 'FIELD_PREP' [-Werror=implicit-function-declaration]
    1489 |         *dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
         |                      ^~~~~~~~~~
   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_setup_cluster_alpha':
   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1861:33: warning: variable 'top_win_pstate' set but not used [-Wunused-but-set-variable]
    1861 |         struct drm_plane_state *top_win_pstate;
         |                                 ^~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +/FIELD_PREP +1489 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c

  1463	
  1464	static void vop2_dither_setup(struct drm_crtc *crtc, uint32_t *dsp_ctrl)
  1465	{
  1466		struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
  1467	
  1468		switch (vcstate->bus_format) {
  1469		case MEDIA_BUS_FMT_RGB565_1X16:
  1470			*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
  1471			break;
  1472		case MEDIA_BUS_FMT_RGB666_1X18:
  1473		case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
  1474		case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
  1475			*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
  1476			*dsp_ctrl |= RGB888_TO_RGB666;
  1477			break;
  1478		case MEDIA_BUS_FMT_YUV8_1X24:
  1479		case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
  1480			*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
  1481			break;
  1482		default:
  1483			break;
  1484		}
  1485	
  1486		if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA)
  1487			*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
  1488	
> 1489		*dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
  1490					DITHER_DOWN_ALLEGRO);
  1491	}
  1492	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-09  0:49     ` kernel test robot
  0 siblings, 0 replies; 123+ messages in thread
From: kernel test robot @ 2021-12-09  0:49 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: kbuild-all, devicetree, Benjamin Gaignard, Peter Geis,
	Sascha Hauer, Sandy Huang, linux-rockchip, Michael Riesch,
	kernel, Andy Yan

Hi Sascha,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on rockchip/for-next]
[also build test ERROR on drm/drm-next drm-intel/for-linux-next drm-exynos/exynos-drm-next v5.16-rc4]
[cannot apply to drm-tip/drm-tip tegra-drm/drm/tegra/for-next airlied/drm-next next-20211208]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: arc-allyesconfig (https://download.01.org/0day-ci/archive/20211209/202112090830.YVovXyce-lkp@intel.com/config)
compiler: arceb-elf-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/8d57a528cbdfec4716a21d22d3d6c04c40451355
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
        git checkout 8d57a528cbdfec4716a21d22d3d6c04c40451355
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arc SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_dither_setup':
>> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1489:22: error: implicit declaration of function 'FIELD_PREP' [-Werror=implicit-function-declaration]
    1489 |         *dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
         |                      ^~~~~~~~~~
   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_setup_cluster_alpha':
   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1861:33: warning: variable 'top_win_pstate' set but not used [-Wunused-but-set-variable]
    1861 |         struct drm_plane_state *top_win_pstate;
         |                                 ^~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +/FIELD_PREP +1489 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c

  1463	
  1464	static void vop2_dither_setup(struct drm_crtc *crtc, uint32_t *dsp_ctrl)
  1465	{
  1466		struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
  1467	
  1468		switch (vcstate->bus_format) {
  1469		case MEDIA_BUS_FMT_RGB565_1X16:
  1470			*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
  1471			break;
  1472		case MEDIA_BUS_FMT_RGB666_1X18:
  1473		case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
  1474		case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
  1475			*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
  1476			*dsp_ctrl |= RGB888_TO_RGB666;
  1477			break;
  1478		case MEDIA_BUS_FMT_YUV8_1X24:
  1479		case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
  1480			*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
  1481			break;
  1482		default:
  1483			break;
  1484		}
  1485	
  1486		if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA)
  1487			*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
  1488	
> 1489		*dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
  1490					DITHER_DOWN_ALLEGRO);
  1491	}
  1492	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-09  0:49     ` kernel test robot
  0 siblings, 0 replies; 123+ messages in thread
From: kernel test robot @ 2021-12-09  0:49 UTC (permalink / raw)
  To: Sascha Hauer, dri-devel
  Cc: devicetree, kbuild-all, kernel, Sascha Hauer, Sandy Huang,
	linux-rockchip, Michael Riesch, Peter Geis, Andy Yan,
	Benjamin Gaignard

Hi Sascha,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on rockchip/for-next]
[also build test ERROR on drm/drm-next drm-intel/for-linux-next drm-exynos/exynos-drm-next v5.16-rc4]
[cannot apply to drm-tip/drm-tip tegra-drm/drm/tegra/for-next airlied/drm-next next-20211208]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: arc-allyesconfig (https://download.01.org/0day-ci/archive/20211209/202112090830.YVovXyce-lkp@intel.com/config)
compiler: arceb-elf-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/8d57a528cbdfec4716a21d22d3d6c04c40451355
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
        git checkout 8d57a528cbdfec4716a21d22d3d6c04c40451355
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arc SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_dither_setup':
>> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1489:22: error: implicit declaration of function 'FIELD_PREP' [-Werror=implicit-function-declaration]
    1489 |         *dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
         |                      ^~~~~~~~~~
   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_setup_cluster_alpha':
   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1861:33: warning: variable 'top_win_pstate' set but not used [-Wunused-but-set-variable]
    1861 |         struct drm_plane_state *top_win_pstate;
         |                                 ^~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +/FIELD_PREP +1489 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c

  1463	
  1464	static void vop2_dither_setup(struct drm_crtc *crtc, uint32_t *dsp_ctrl)
  1465	{
  1466		struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
  1467	
  1468		switch (vcstate->bus_format) {
  1469		case MEDIA_BUS_FMT_RGB565_1X16:
  1470			*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
  1471			break;
  1472		case MEDIA_BUS_FMT_RGB666_1X18:
  1473		case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
  1474		case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
  1475			*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
  1476			*dsp_ctrl |= RGB888_TO_RGB666;
  1477			break;
  1478		case MEDIA_BUS_FMT_YUV8_1X24:
  1479		case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
  1480			*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
  1481			break;
  1482		default:
  1483			break;
  1484		}
  1485	
  1486		if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA)
  1487			*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
  1488	
> 1489		*dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
  1490					DITHER_DOWN_ALLEGRO);
  1491	}
  1492	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-09  0:49     ` kernel test robot
  0 siblings, 0 replies; 123+ messages in thread
From: kernel test robot @ 2021-12-09  0:49 UTC (permalink / raw)
  To: kbuild-all

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

Hi Sascha,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on rockchip/for-next]
[also build test ERROR on drm/drm-next drm-intel/for-linux-next drm-exynos/exynos-drm-next v5.16-rc4]
[cannot apply to drm-tip/drm-tip tegra-drm/drm/tegra/for-next airlied/drm-next next-20211208]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: arc-allyesconfig (https://download.01.org/0day-ci/archive/20211209/202112090830.YVovXyce-lkp(a)intel.com/config)
compiler: arceb-elf-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/8d57a528cbdfec4716a21d22d3d6c04c40451355
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Sascha-Hauer/drm-rockchip-RK356x-VOP2-support/20211208-231502
        git checkout 8d57a528cbdfec4716a21d22d3d6c04c40451355
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arc SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_dither_setup':
>> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1489:22: error: implicit declaration of function 'FIELD_PREP' [-Werror=implicit-function-declaration]
    1489 |         *dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
         |                      ^~~~~~~~~~
   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c: In function 'vop2_setup_cluster_alpha':
   drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1861:33: warning: variable 'top_win_pstate' set but not used [-Wunused-but-set-variable]
    1861 |         struct drm_plane_state *top_win_pstate;
         |                                 ^~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +/FIELD_PREP +1489 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c

  1463	
  1464	static void vop2_dither_setup(struct drm_crtc *crtc, uint32_t *dsp_ctrl)
  1465	{
  1466		struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
  1467	
  1468		switch (vcstate->bus_format) {
  1469		case MEDIA_BUS_FMT_RGB565_1X16:
  1470			*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
  1471			break;
  1472		case MEDIA_BUS_FMT_RGB666_1X18:
  1473		case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
  1474		case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
  1475			*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
  1476			*dsp_ctrl |= RGB888_TO_RGB666;
  1477			break;
  1478		case MEDIA_BUS_FMT_YUV8_1X24:
  1479		case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
  1480			*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
  1481			break;
  1482		default:
  1483			break;
  1484		}
  1485	
  1486		if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA)
  1487			*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
  1488	
> 1489		*dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
  1490					DITHER_DOWN_ALLEGRO);
  1491	}
  1492	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

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

* Re: [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
  2021-12-08 16:51     ` Heiko Stübner
  (?)
  (?)
@ 2021-12-10  8:51       ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-10  8:51 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Peter Geis

On Wed, Dec 08, 2021 at 05:51:43PM +0100, Heiko Stübner wrote:
> Hi Sascha,
> 
> Am Mittwoch, 8. Dezember 2021, 16:12:30 CET schrieb Sascha Hauer:
> > On the rk3568 we have this (simplified) situation:
> > 
> >  .--------.     .-----.    .---------.
> > -| hpll   |--.--| /n  |----|dclk_vop0|-
> >  `--------´  |  `-----´    `---------´
> >              |  .-----.    .---------.
> >              `--| /m  |----|dclk_vop1|-
> >              |  `-----´    `---------´
> >              |             .---------.
> >              `-------------|hdmi_ref |-
> >                            `---------´
> > 
> > hpll is the PLL that drives the HDMI reference clock and the pixel
> > clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
> > and the hpll there are programmable dividers whereas the HDMI reference
> > clock is directly connected to the hpll.
> > 
> > For the HDMI output to work the pixel clock must be the same as the HDMI
> > reference clock, hence the dividers must be programmed to 1. Normally a
> > rate change on dclk_vop0/1 propagates through to the hpll and the clock
> > framework picks a suitable combination of hpll and divider settings. by
> > accident it picks a divider setting of 1 for the standard 1080p case,
> > but other divider settings for most other resolutions leaving the HDMI
> > port non working.
> > 
> > This patch is not a solution, it merely puts the finger in the wound. We
> > leave out the divider for the composite clock for dclk_vop0 which then
> > leaves the divider at the bootloader default setting of 1. I assume
> > the divider is disturbing only for the HDMI case, but needed for other
> > outputs. Any thoughts how this can be handled?
> 
> I'm not even sure if/how the common clock framework keeps track of
> diverging wishes to parent-rates :-) .

I don't think the common clock framework tries to keep track of that.

> 
> But I do see two direct issues in the _existing_ code.
> 
> dclk_vop0/1 uses CLK_SET_RATE_PARENT so is allowed to change
> the rates of its parent clock(s).
> 
> Its parent clocks are not only hpll but can also be vpll, gpll and cpll.
> So this can cause even more mayhem, if the ccf for example decides
> to select the gpll and then change its rate,which may result in a lot
> of peripherals getting their rates changed under them ;-) .

Right, we can only allow the CLK_SET_RATE_PARENT parent flag on the dclk
clocks when the parent is HPLL. Since we can't be sure that HPLL is the
parent we have to remove the flag.

> 
> On the other hand I see in the clock driver that hdmi-ref is not allowed
> to change its parent rate, so can only select between hpll and hpll_ph0
> (1/2 the rate?).
> 
> So I guess, one way could be:
> - add CLK_SET_RATE_PARENT to the hdmi-ref clock
> - drop CLK_SET_RATE_PARENT from the dclks
> - make sure hdmi-clock is set before the dclk

That solves it for the HDMI case. I can imagine that for a LVDS user the
CLK_SET_RATE_PARENT flag on the dclks is quite handy to get a PLL
frequency suitable for the display. Otherwise he would have to set a
suitable PLL frequency using assigned-clock-rates in the device tree.
That's still possible so this might be a good compromise.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
@ 2021-12-10  8:51       ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-10  8:51 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sandy Huang,
	dri-devel, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

On Wed, Dec 08, 2021 at 05:51:43PM +0100, Heiko Stübner wrote:
> Hi Sascha,
> 
> Am Mittwoch, 8. Dezember 2021, 16:12:30 CET schrieb Sascha Hauer:
> > On the rk3568 we have this (simplified) situation:
> > 
> >  .--------.     .-----.    .---------.
> > -| hpll   |--.--| /n  |----|dclk_vop0|-
> >  `--------´  |  `-----´    `---------´
> >              |  .-----.    .---------.
> >              `--| /m  |----|dclk_vop1|-
> >              |  `-----´    `---------´
> >              |             .---------.
> >              `-------------|hdmi_ref |-
> >                            `---------´
> > 
> > hpll is the PLL that drives the HDMI reference clock and the pixel
> > clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
> > and the hpll there are programmable dividers whereas the HDMI reference
> > clock is directly connected to the hpll.
> > 
> > For the HDMI output to work the pixel clock must be the same as the HDMI
> > reference clock, hence the dividers must be programmed to 1. Normally a
> > rate change on dclk_vop0/1 propagates through to the hpll and the clock
> > framework picks a suitable combination of hpll and divider settings. by
> > accident it picks a divider setting of 1 for the standard 1080p case,
> > but other divider settings for most other resolutions leaving the HDMI
> > port non working.
> > 
> > This patch is not a solution, it merely puts the finger in the wound. We
> > leave out the divider for the composite clock for dclk_vop0 which then
> > leaves the divider at the bootloader default setting of 1. I assume
> > the divider is disturbing only for the HDMI case, but needed for other
> > outputs. Any thoughts how this can be handled?
> 
> I'm not even sure if/how the common clock framework keeps track of
> diverging wishes to parent-rates :-) .

I don't think the common clock framework tries to keep track of that.

> 
> But I do see two direct issues in the _existing_ code.
> 
> dclk_vop0/1 uses CLK_SET_RATE_PARENT so is allowed to change
> the rates of its parent clock(s).
> 
> Its parent clocks are not only hpll but can also be vpll, gpll and cpll.
> So this can cause even more mayhem, if the ccf for example decides
> to select the gpll and then change its rate,which may result in a lot
> of peripherals getting their rates changed under them ;-) .

Right, we can only allow the CLK_SET_RATE_PARENT parent flag on the dclk
clocks when the parent is HPLL. Since we can't be sure that HPLL is the
parent we have to remove the flag.

> 
> On the other hand I see in the clock driver that hdmi-ref is not allowed
> to change its parent rate, so can only select between hpll and hpll_ph0
> (1/2 the rate?).
> 
> So I guess, one way could be:
> - add CLK_SET_RATE_PARENT to the hdmi-ref clock
> - drop CLK_SET_RATE_PARENT from the dclks
> - make sure hdmi-clock is set before the dclk

That solves it for the HDMI case. I can imagine that for a LVDS user the
CLK_SET_RATE_PARENT flag on the dclks is quite handy to get a PLL
frequency suitable for the display. Otherwise he would have to set a
suitable PLL frequency using assigned-clock-rates in the device tree.
That's still possible so this might be a good compromise.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
@ 2021-12-10  8:51       ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-10  8:51 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Peter Geis

On Wed, Dec 08, 2021 at 05:51:43PM +0100, Heiko Stübner wrote:
> Hi Sascha,
> 
> Am Mittwoch, 8. Dezember 2021, 16:12:30 CET schrieb Sascha Hauer:
> > On the rk3568 we have this (simplified) situation:
> > 
> >  .--------.     .-----.    .---------.
> > -| hpll   |--.--| /n  |----|dclk_vop0|-
> >  `--------´  |  `-----´    `---------´
> >              |  .-----.    .---------.
> >              `--| /m  |----|dclk_vop1|-
> >              |  `-----´    `---------´
> >              |             .---------.
> >              `-------------|hdmi_ref |-
> >                            `---------´
> > 
> > hpll is the PLL that drives the HDMI reference clock and the pixel
> > clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
> > and the hpll there are programmable dividers whereas the HDMI reference
> > clock is directly connected to the hpll.
> > 
> > For the HDMI output to work the pixel clock must be the same as the HDMI
> > reference clock, hence the dividers must be programmed to 1. Normally a
> > rate change on dclk_vop0/1 propagates through to the hpll and the clock
> > framework picks a suitable combination of hpll and divider settings. by
> > accident it picks a divider setting of 1 for the standard 1080p case,
> > but other divider settings for most other resolutions leaving the HDMI
> > port non working.
> > 
> > This patch is not a solution, it merely puts the finger in the wound. We
> > leave out the divider for the composite clock for dclk_vop0 which then
> > leaves the divider at the bootloader default setting of 1. I assume
> > the divider is disturbing only for the HDMI case, but needed for other
> > outputs. Any thoughts how this can be handled?
> 
> I'm not even sure if/how the common clock framework keeps track of
> diverging wishes to parent-rates :-) .

I don't think the common clock framework tries to keep track of that.

> 
> But I do see two direct issues in the _existing_ code.
> 
> dclk_vop0/1 uses CLK_SET_RATE_PARENT so is allowed to change
> the rates of its parent clock(s).
> 
> Its parent clocks are not only hpll but can also be vpll, gpll and cpll.
> So this can cause even more mayhem, if the ccf for example decides
> to select the gpll and then change its rate,which may result in a lot
> of peripherals getting their rates changed under them ;-) .

Right, we can only allow the CLK_SET_RATE_PARENT parent flag on the dclk
clocks when the parent is HPLL. Since we can't be sure that HPLL is the
parent we have to remove the flag.

> 
> On the other hand I see in the clock driver that hdmi-ref is not allowed
> to change its parent rate, so can only select between hpll and hpll_ph0
> (1/2 the rate?).
> 
> So I guess, one way could be:
> - add CLK_SET_RATE_PARENT to the hdmi-ref clock
> - drop CLK_SET_RATE_PARENT from the dclks
> - make sure hdmi-clock is set before the dclk

That solves it for the HDMI case. I can imagine that for a LVDS user the
CLK_SET_RATE_PARENT flag on the dclks is quite handy to get a PLL
frequency suitable for the display. Otherwise he would have to set a
suitable PLL frequency using assigned-clock-rates in the device tree.
That's still possible so this might be a good compromise.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0
@ 2021-12-10  8:51       ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-10  8:51 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Peter Geis

On Wed, Dec 08, 2021 at 05:51:43PM +0100, Heiko Stübner wrote:
> Hi Sascha,
> 
> Am Mittwoch, 8. Dezember 2021, 16:12:30 CET schrieb Sascha Hauer:
> > On the rk3568 we have this (simplified) situation:
> > 
> >  .--------.     .-----.    .---------.
> > -| hpll   |--.--| /n  |----|dclk_vop0|-
> >  `--------´  |  `-----´    `---------´
> >              |  .-----.    .---------.
> >              `--| /m  |----|dclk_vop1|-
> >              |  `-----´    `---------´
> >              |             .---------.
> >              `-------------|hdmi_ref |-
> >                            `---------´
> > 
> > hpll is the PLL that drives the HDMI reference clock and the pixel
> > clocks for the different CRTCs (dclk_vop0/1). Between the pixel clocks
> > and the hpll there are programmable dividers whereas the HDMI reference
> > clock is directly connected to the hpll.
> > 
> > For the HDMI output to work the pixel clock must be the same as the HDMI
> > reference clock, hence the dividers must be programmed to 1. Normally a
> > rate change on dclk_vop0/1 propagates through to the hpll and the clock
> > framework picks a suitable combination of hpll and divider settings. by
> > accident it picks a divider setting of 1 for the standard 1080p case,
> > but other divider settings for most other resolutions leaving the HDMI
> > port non working.
> > 
> > This patch is not a solution, it merely puts the finger in the wound. We
> > leave out the divider for the composite clock for dclk_vop0 which then
> > leaves the divider at the bootloader default setting of 1. I assume
> > the divider is disturbing only for the HDMI case, but needed for other
> > outputs. Any thoughts how this can be handled?
> 
> I'm not even sure if/how the common clock framework keeps track of
> diverging wishes to parent-rates :-) .

I don't think the common clock framework tries to keep track of that.

> 
> But I do see two direct issues in the _existing_ code.
> 
> dclk_vop0/1 uses CLK_SET_RATE_PARENT so is allowed to change
> the rates of its parent clock(s).
> 
> Its parent clocks are not only hpll but can also be vpll, gpll and cpll.
> So this can cause even more mayhem, if the ccf for example decides
> to select the gpll and then change its rate,which may result in a lot
> of peripherals getting their rates changed under them ;-) .

Right, we can only allow the CLK_SET_RATE_PARENT parent flag on the dclk
clocks when the parent is HPLL. Since we can't be sure that HPLL is the
parent we have to remove the flag.

> 
> On the other hand I see in the clock driver that hdmi-ref is not allowed
> to change its parent rate, so can only select between hpll and hpll_ph0
> (1/2 the rate?).
> 
> So I guess, one way could be:
> - add CLK_SET_RATE_PARENT to the hdmi-ref clock
> - drop CLK_SET_RATE_PARENT from the dclks
> - make sure hdmi-clock is set before the dclk

That solves it for the HDMI case. I can imagine that for a LVDS user the
CLK_SET_RATE_PARENT flag on the dclks is quite handy to get a PLL
frequency suitable for the display. Otherwise he would have to set a
suitable PLL frequency using assigned-clock-rates in the device tree.
That's still possible so this might be a good compromise.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
  2021-12-08 16:59     ` Johan Jonker
  (?)
  (?)
@ 2021-12-10  8:55       ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-10  8:55 UTC (permalink / raw)
  To: Johan Jonker
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

Hi Johan,

On Wed, Dec 08, 2021 at 05:59:16PM +0100, Johan Jonker wrote:
> Hi,
> 
> On 12/8/21 4:12 PM, Sascha Hauer wrote:
> > From: Andy Yan <andy.yan@rock-chips.com>
> > 
> > The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
> > It replaces the VOP unit found in the older Rockchip SoCs.
> > 
> > This driver has been derived from the downstream Rockchip Kernel and
> > heavily modified:
> > 
> > - All nonstandard DRM properties have been removed
> > - dropped struct vop2_plane_state and pass around less data between
> >   functions
> > - Dropped all DRM_FORMAT_* not known on upstream
> > - rework register access to get rid of excessively used macros
> > - Drop all waiting for framesyncs
> > 
> > The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
> > board. Overlay support is tested with the modetest utility. AFBC support
> > on the cluster windows is tested with weston-simple-dmabuf-egl on
> > weston using the (yet to be upstreamed) panfrost driver support.
> > 
> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> > ---
> 
> [..]
> 
> > +
> > +static const struct of_device_id vop2_dt_match[] = {
> > +	{
> > +		.compatible = "rockchip,rk3568-vop",
> > +		.data = &rk3568_vop
> > +	}, {
> 
> > +		.compatible = "rockchip,rk3568-vop",
> 
> Maybe use:
> .compatible = "rockchip,rk3566-vop",

Copy/Paste bug. Will fix.

> 
> > +		.data = &rk3566_vop
> > +	}, {
> > +	},
> 
> Maybe sort this list alphabetical based on compatible in case later more
> SoCs are added.
> 
> rk3566
> rk3568

Ok.

> 
> ===
> 
> The structure layout size above could be reduced for if we get more
> compatible strings additions.
> 
> Example vop1:
> 
> static const struct of_device_id vop_driver_dt_match[] = {
> 	{ .compatible = "rockchip,rk3036-vop",
> 	  .data = &rk3036_vop },
> 	{ .compatible = "rockchip,rk3126-vop",
> 	  .data = &rk3126_vop },
> 	{ .compatible = "rockchip,px30-vop-big",
> 	  .data = &px30_vop_big },
> 	{ .compatible = "rockchip,px30-vop-lit",
> 	  .data = &px30_vop_lit },
> 	{ .compatible = "rockchip,rk3066-vop",
> 	  .data = &rk3066_vop },
> 	{ .compatible = "rockchip,rk3188-vop",
> 	  .data = &rk3188_vop },
> 	{ .compatible = "rockchip,rk3288-vop",
> 	  .data = &rk3288_vop },
> 	{ .compatible = "rockchip,rk3368-vop",
> 	  .data = &rk3368_vop },
> 	{ .compatible = "rockchip,rk3366-vop",
> 	  .data = &rk3366_vop },
> 	{ .compatible = "rockchip,rk3399-vop-big",
> 	  .data = &rk3399_vop_big },
> 	{ .compatible = "rockchip,rk3399-vop-lit",
> 	  .data = &rk3399_vop_lit },
> 	{ .compatible = "rockchip,rk3228-vop",
> 	  .data = &rk3228_vop },
> 	{ .compatible = "rockchip,rk3328-vop",
> 	  .data = &rk3328_vop },
> 	{},

It's shorter, but ugly ;)
That's only my personal taste though, I don't care much.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-10  8:55       ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-10  8:55 UTC (permalink / raw)
  To: Johan Jonker
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

Hi Johan,

On Wed, Dec 08, 2021 at 05:59:16PM +0100, Johan Jonker wrote:
> Hi,
> 
> On 12/8/21 4:12 PM, Sascha Hauer wrote:
> > From: Andy Yan <andy.yan@rock-chips.com>
> > 
> > The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
> > It replaces the VOP unit found in the older Rockchip SoCs.
> > 
> > This driver has been derived from the downstream Rockchip Kernel and
> > heavily modified:
> > 
> > - All nonstandard DRM properties have been removed
> > - dropped struct vop2_plane_state and pass around less data between
> >   functions
> > - Dropped all DRM_FORMAT_* not known on upstream
> > - rework register access to get rid of excessively used macros
> > - Drop all waiting for framesyncs
> > 
> > The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
> > board. Overlay support is tested with the modetest utility. AFBC support
> > on the cluster windows is tested with weston-simple-dmabuf-egl on
> > weston using the (yet to be upstreamed) panfrost driver support.
> > 
> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> > ---
> 
> [..]
> 
> > +
> > +static const struct of_device_id vop2_dt_match[] = {
> > +	{
> > +		.compatible = "rockchip,rk3568-vop",
> > +		.data = &rk3568_vop
> > +	}, {
> 
> > +		.compatible = "rockchip,rk3568-vop",
> 
> Maybe use:
> .compatible = "rockchip,rk3566-vop",

Copy/Paste bug. Will fix.

> 
> > +		.data = &rk3566_vop
> > +	}, {
> > +	},
> 
> Maybe sort this list alphabetical based on compatible in case later more
> SoCs are added.
> 
> rk3566
> rk3568

Ok.

> 
> ===
> 
> The structure layout size above could be reduced for if we get more
> compatible strings additions.
> 
> Example vop1:
> 
> static const struct of_device_id vop_driver_dt_match[] = {
> 	{ .compatible = "rockchip,rk3036-vop",
> 	  .data = &rk3036_vop },
> 	{ .compatible = "rockchip,rk3126-vop",
> 	  .data = &rk3126_vop },
> 	{ .compatible = "rockchip,px30-vop-big",
> 	  .data = &px30_vop_big },
> 	{ .compatible = "rockchip,px30-vop-lit",
> 	  .data = &px30_vop_lit },
> 	{ .compatible = "rockchip,rk3066-vop",
> 	  .data = &rk3066_vop },
> 	{ .compatible = "rockchip,rk3188-vop",
> 	  .data = &rk3188_vop },
> 	{ .compatible = "rockchip,rk3288-vop",
> 	  .data = &rk3288_vop },
> 	{ .compatible = "rockchip,rk3368-vop",
> 	  .data = &rk3368_vop },
> 	{ .compatible = "rockchip,rk3366-vop",
> 	  .data = &rk3366_vop },
> 	{ .compatible = "rockchip,rk3399-vop-big",
> 	  .data = &rk3399_vop_big },
> 	{ .compatible = "rockchip,rk3399-vop-lit",
> 	  .data = &rk3399_vop_lit },
> 	{ .compatible = "rockchip,rk3228-vop",
> 	  .data = &rk3228_vop },
> 	{ .compatible = "rockchip,rk3328-vop",
> 	  .data = &rk3328_vop },
> 	{},

It's shorter, but ugly ;)
That's only my personal taste though, I don't care much.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-10  8:55       ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-10  8:55 UTC (permalink / raw)
  To: Johan Jonker
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sandy Huang,
	dri-devel, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

Hi Johan,

On Wed, Dec 08, 2021 at 05:59:16PM +0100, Johan Jonker wrote:
> Hi,
> 
> On 12/8/21 4:12 PM, Sascha Hauer wrote:
> > From: Andy Yan <andy.yan@rock-chips.com>
> > 
> > The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
> > It replaces the VOP unit found in the older Rockchip SoCs.
> > 
> > This driver has been derived from the downstream Rockchip Kernel and
> > heavily modified:
> > 
> > - All nonstandard DRM properties have been removed
> > - dropped struct vop2_plane_state and pass around less data between
> >   functions
> > - Dropped all DRM_FORMAT_* not known on upstream
> > - rework register access to get rid of excessively used macros
> > - Drop all waiting for framesyncs
> > 
> > The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
> > board. Overlay support is tested with the modetest utility. AFBC support
> > on the cluster windows is tested with weston-simple-dmabuf-egl on
> > weston using the (yet to be upstreamed) panfrost driver support.
> > 
> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> > ---
> 
> [..]
> 
> > +
> > +static const struct of_device_id vop2_dt_match[] = {
> > +	{
> > +		.compatible = "rockchip,rk3568-vop",
> > +		.data = &rk3568_vop
> > +	}, {
> 
> > +		.compatible = "rockchip,rk3568-vop",
> 
> Maybe use:
> .compatible = "rockchip,rk3566-vop",

Copy/Paste bug. Will fix.

> 
> > +		.data = &rk3566_vop
> > +	}, {
> > +	},
> 
> Maybe sort this list alphabetical based on compatible in case later more
> SoCs are added.
> 
> rk3566
> rk3568

Ok.

> 
> ===
> 
> The structure layout size above could be reduced for if we get more
> compatible strings additions.
> 
> Example vop1:
> 
> static const struct of_device_id vop_driver_dt_match[] = {
> 	{ .compatible = "rockchip,rk3036-vop",
> 	  .data = &rk3036_vop },
> 	{ .compatible = "rockchip,rk3126-vop",
> 	  .data = &rk3126_vop },
> 	{ .compatible = "rockchip,px30-vop-big",
> 	  .data = &px30_vop_big },
> 	{ .compatible = "rockchip,px30-vop-lit",
> 	  .data = &px30_vop_lit },
> 	{ .compatible = "rockchip,rk3066-vop",
> 	  .data = &rk3066_vop },
> 	{ .compatible = "rockchip,rk3188-vop",
> 	  .data = &rk3188_vop },
> 	{ .compatible = "rockchip,rk3288-vop",
> 	  .data = &rk3288_vop },
> 	{ .compatible = "rockchip,rk3368-vop",
> 	  .data = &rk3368_vop },
> 	{ .compatible = "rockchip,rk3366-vop",
> 	  .data = &rk3366_vop },
> 	{ .compatible = "rockchip,rk3399-vop-big",
> 	  .data = &rk3399_vop_big },
> 	{ .compatible = "rockchip,rk3399-vop-lit",
> 	  .data = &rk3399_vop_lit },
> 	{ .compatible = "rockchip,rk3228-vop",
> 	  .data = &rk3228_vop },
> 	{ .compatible = "rockchip,rk3328-vop",
> 	  .data = &rk3328_vop },
> 	{},

It's shorter, but ugly ;)
That's only my personal taste though, I don't care much.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 17/18] drm: rockchip: Add VOP2 driver
@ 2021-12-10  8:55       ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-10  8:55 UTC (permalink / raw)
  To: Johan Jonker
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

Hi Johan,

On Wed, Dec 08, 2021 at 05:59:16PM +0100, Johan Jonker wrote:
> Hi,
> 
> On 12/8/21 4:12 PM, Sascha Hauer wrote:
> > From: Andy Yan <andy.yan@rock-chips.com>
> > 
> > The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
> > It replaces the VOP unit found in the older Rockchip SoCs.
> > 
> > This driver has been derived from the downstream Rockchip Kernel and
> > heavily modified:
> > 
> > - All nonstandard DRM properties have been removed
> > - dropped struct vop2_plane_state and pass around less data between
> >   functions
> > - Dropped all DRM_FORMAT_* not known on upstream
> > - rework register access to get rid of excessively used macros
> > - Drop all waiting for framesyncs
> > 
> > The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
> > board. Overlay support is tested with the modetest utility. AFBC support
> > on the cluster windows is tested with weston-simple-dmabuf-egl on
> > weston using the (yet to be upstreamed) panfrost driver support.
> > 
> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> > ---
> 
> [..]
> 
> > +
> > +static const struct of_device_id vop2_dt_match[] = {
> > +	{
> > +		.compatible = "rockchip,rk3568-vop",
> > +		.data = &rk3568_vop
> > +	}, {
> 
> > +		.compatible = "rockchip,rk3568-vop",
> 
> Maybe use:
> .compatible = "rockchip,rk3566-vop",

Copy/Paste bug. Will fix.

> 
> > +		.data = &rk3566_vop
> > +	}, {
> > +	},
> 
> Maybe sort this list alphabetical based on compatible in case later more
> SoCs are added.
> 
> rk3566
> rk3568

Ok.

> 
> ===
> 
> The structure layout size above could be reduced for if we get more
> compatible strings additions.
> 
> Example vop1:
> 
> static const struct of_device_id vop_driver_dt_match[] = {
> 	{ .compatible = "rockchip,rk3036-vop",
> 	  .data = &rk3036_vop },
> 	{ .compatible = "rockchip,rk3126-vop",
> 	  .data = &rk3126_vop },
> 	{ .compatible = "rockchip,px30-vop-big",
> 	  .data = &px30_vop_big },
> 	{ .compatible = "rockchip,px30-vop-lit",
> 	  .data = &px30_vop_lit },
> 	{ .compatible = "rockchip,rk3066-vop",
> 	  .data = &rk3066_vop },
> 	{ .compatible = "rockchip,rk3188-vop",
> 	  .data = &rk3188_vop },
> 	{ .compatible = "rockchip,rk3288-vop",
> 	  .data = &rk3288_vop },
> 	{ .compatible = "rockchip,rk3368-vop",
> 	  .data = &rk3368_vop },
> 	{ .compatible = "rockchip,rk3366-vop",
> 	  .data = &rk3366_vop },
> 	{ .compatible = "rockchip,rk3399-vop-big",
> 	  .data = &rk3399_vop_big },
> 	{ .compatible = "rockchip,rk3399-vop-lit",
> 	  .data = &rk3399_vop_lit },
> 	{ .compatible = "rockchip,rk3228-vop",
> 	  .data = &rk3228_vop },
> 	{ .compatible = "rockchip,rk3328-vop",
> 	  .data = &rk3328_vop },
> 	{},

It's shorter, but ugly ;)
That's only my personal taste though, I don't care much.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
  2021-12-08 15:12   ` Sascha Hauer
  (?)
  (?)
@ 2021-12-12 22:09     ` Heiko Stuebner
  -1 siblings, 0 replies; 123+ messages in thread
From: Heiko Stuebner @ 2021-12-12 22:09 UTC (permalink / raw)
  To: dri-devel, Sascha Hauer
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang, Peter Geis,
	Sascha Hauer

Am Mittwoch, 8. Dezember 2021, 16:12:19 CET schrieb Sascha Hauer:
> "vpll" is a misnomer. A clock input to a device should be named after
> the usage in the device, not after the clock that drives it. On the
> rk3568 the same clock is driven by the HPLL.
> To fix that, this patch renames the vpll clock to ref clock.  The clock
> name "vpll" is left for compatibility to old device trees.

Can't we just say that the binding only takes the "ref" name, but
the code still allows "vpll".

I think I remember Rob suggesting something similar in the past.

I don't think that we need to keep the binding(-validation)
compatible with old devicetrees, but the kernel itself should stay
compatible.


Heiko


> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> index 6e09dd2ee05ac..2ab6578033da2 100644
> --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> @@ -48,10 +48,14 @@ properties:
>            - cec
>            - grf
>            - vpll
> +          - ref
>        - enum:
>            - grf
>            - vpll
> -      - const: vpll
> +          - ref
> +      - enum:
> +          - vpll
> +          - ref
>  
>    ddc-i2c-bus:
>      $ref: /schemas/types.yaml#/definitions/phandle
> 





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

* Re: [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
@ 2021-12-12 22:09     ` Heiko Stuebner
  0 siblings, 0 replies; 123+ messages in thread
From: Heiko Stuebner @ 2021-12-12 22:09 UTC (permalink / raw)
  To: dri-devel, Sascha Hauer
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sascha Hauer,
	Sandy Huang, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

Am Mittwoch, 8. Dezember 2021, 16:12:19 CET schrieb Sascha Hauer:
> "vpll" is a misnomer. A clock input to a device should be named after
> the usage in the device, not after the clock that drives it. On the
> rk3568 the same clock is driven by the HPLL.
> To fix that, this patch renames the vpll clock to ref clock.  The clock
> name "vpll" is left for compatibility to old device trees.

Can't we just say that the binding only takes the "ref" name, but
the code still allows "vpll".

I think I remember Rob suggesting something similar in the past.

I don't think that we need to keep the binding(-validation)
compatible with old devicetrees, but the kernel itself should stay
compatible.


Heiko


> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> index 6e09dd2ee05ac..2ab6578033da2 100644
> --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> @@ -48,10 +48,14 @@ properties:
>            - cec
>            - grf
>            - vpll
> +          - ref
>        - enum:
>            - grf
>            - vpll
> -      - const: vpll
> +          - ref
> +      - enum:
> +          - vpll
> +          - ref
>  
>    ddc-i2c-bus:
>      $ref: /schemas/types.yaml#/definitions/phandle
> 





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

* Re: [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
@ 2021-12-12 22:09     ` Heiko Stuebner
  0 siblings, 0 replies; 123+ messages in thread
From: Heiko Stuebner @ 2021-12-12 22:09 UTC (permalink / raw)
  To: dri-devel, Sascha Hauer
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang, Peter Geis,
	Sascha Hauer

Am Mittwoch, 8. Dezember 2021, 16:12:19 CET schrieb Sascha Hauer:
> "vpll" is a misnomer. A clock input to a device should be named after
> the usage in the device, not after the clock that drives it. On the
> rk3568 the same clock is driven by the HPLL.
> To fix that, this patch renames the vpll clock to ref clock.  The clock
> name "vpll" is left for compatibility to old device trees.

Can't we just say that the binding only takes the "ref" name, but
the code still allows "vpll".

I think I remember Rob suggesting something similar in the past.

I don't think that we need to keep the binding(-validation)
compatible with old devicetrees, but the kernel itself should stay
compatible.


Heiko


> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> index 6e09dd2ee05ac..2ab6578033da2 100644
> --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> @@ -48,10 +48,14 @@ properties:
>            - cec
>            - grf
>            - vpll
> +          - ref
>        - enum:
>            - grf
>            - vpll
> -      - const: vpll
> +          - ref
> +      - enum:
> +          - vpll
> +          - ref
>  
>    ddc-i2c-bus:
>      $ref: /schemas/types.yaml#/definitions/phandle
> 





_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
@ 2021-12-12 22:09     ` Heiko Stuebner
  0 siblings, 0 replies; 123+ messages in thread
From: Heiko Stuebner @ 2021-12-12 22:09 UTC (permalink / raw)
  To: dri-devel, Sascha Hauer
  Cc: linux-arm-kernel, linux-rockchip, devicetree, kernel, Andy Yan,
	Benjamin Gaignard, Michael Riesch, Sandy Huang, Peter Geis,
	Sascha Hauer

Am Mittwoch, 8. Dezember 2021, 16:12:19 CET schrieb Sascha Hauer:
> "vpll" is a misnomer. A clock input to a device should be named after
> the usage in the device, not after the clock that drives it. On the
> rk3568 the same clock is driven by the HPLL.
> To fix that, this patch renames the vpll clock to ref clock.  The clock
> name "vpll" is left for compatibility to old device trees.

Can't we just say that the binding only takes the "ref" name, but
the code still allows "vpll".

I think I remember Rob suggesting something similar in the past.

I don't think that we need to keep the binding(-validation)
compatible with old devicetrees, but the kernel itself should stay
compatible.


Heiko


> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../bindings/display/rockchip/rockchip,dw-hdmi.yaml         | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> index 6e09dd2ee05ac..2ab6578033da2 100644
> --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml
> @@ -48,10 +48,14 @@ properties:
>            - cec
>            - grf
>            - vpll
> +          - ref
>        - enum:
>            - grf
>            - vpll
> -      - const: vpll
> +          - ref
> +      - enum:
> +          - vpll
> +          - ref
>  
>    ddc-i2c-bus:
>      $ref: /schemas/types.yaml#/definitions/phandle
> 





_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
  2021-12-12 22:09     ` Heiko Stuebner
  (?)
  (?)
@ 2021-12-13 11:08       ` Sascha Hauer
  -1 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-13 11:08 UTC (permalink / raw)
  To: Heiko Stuebner
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Peter Geis

On Sun, Dec 12, 2021 at 11:09:24PM +0100, Heiko Stuebner wrote:
> Am Mittwoch, 8. Dezember 2021, 16:12:19 CET schrieb Sascha Hauer:
> > "vpll" is a misnomer. A clock input to a device should be named after
> > the usage in the device, not after the clock that drives it. On the
> > rk3568 the same clock is driven by the HPLL.
> > To fix that, this patch renames the vpll clock to ref clock.  The clock
> > name "vpll" is left for compatibility to old device trees.
> 
> Can't we just say that the binding only takes the "ref" name, but
> the code still allows "vpll".
> 
> I think I remember Rob suggesting something similar in the past.
> 
> I don't think that we need to keep the binding(-validation)
> compatible with old devicetrees, but the kernel itself should stay
> compatible.

Sounds reasonable. I'll also add a patch changing the in-tree users next
round.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
@ 2021-12-13 11:08       ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-13 11:08 UTC (permalink / raw)
  To: Heiko Stuebner
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sandy Huang,
	dri-devel, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

On Sun, Dec 12, 2021 at 11:09:24PM +0100, Heiko Stuebner wrote:
> Am Mittwoch, 8. Dezember 2021, 16:12:19 CET schrieb Sascha Hauer:
> > "vpll" is a misnomer. A clock input to a device should be named after
> > the usage in the device, not after the clock that drives it. On the
> > rk3568 the same clock is driven by the HPLL.
> > To fix that, this patch renames the vpll clock to ref clock.  The clock
> > name "vpll" is left for compatibility to old device trees.
> 
> Can't we just say that the binding only takes the "ref" name, but
> the code still allows "vpll".
> 
> I think I remember Rob suggesting something similar in the past.
> 
> I don't think that we need to keep the binding(-validation)
> compatible with old devicetrees, but the kernel itself should stay
> compatible.

Sounds reasonable. I'll also add a patch changing the in-tree users next
round.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
@ 2021-12-13 11:08       ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-13 11:08 UTC (permalink / raw)
  To: Heiko Stuebner
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Peter Geis

On Sun, Dec 12, 2021 at 11:09:24PM +0100, Heiko Stuebner wrote:
> Am Mittwoch, 8. Dezember 2021, 16:12:19 CET schrieb Sascha Hauer:
> > "vpll" is a misnomer. A clock input to a device should be named after
> > the usage in the device, not after the clock that drives it. On the
> > rk3568 the same clock is driven by the HPLL.
> > To fix that, this patch renames the vpll clock to ref clock.  The clock
> > name "vpll" is left for compatibility to old device trees.
> 
> Can't we just say that the binding only takes the "ref" name, but
> the code still allows "vpll".
> 
> I think I remember Rob suggesting something similar in the past.
> 
> I don't think that we need to keep the binding(-validation)
> compatible with old devicetrees, but the kernel itself should stay
> compatible.

Sounds reasonable. I'll also add a patch changing the in-tree users next
round.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name
@ 2021-12-13 11:08       ` Sascha Hauer
  0 siblings, 0 replies; 123+ messages in thread
From: Sascha Hauer @ 2021-12-13 11:08 UTC (permalink / raw)
  To: Heiko Stuebner
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Peter Geis

On Sun, Dec 12, 2021 at 11:09:24PM +0100, Heiko Stuebner wrote:
> Am Mittwoch, 8. Dezember 2021, 16:12:19 CET schrieb Sascha Hauer:
> > "vpll" is a misnomer. A clock input to a device should be named after
> > the usage in the device, not after the clock that drives it. On the
> > rk3568 the same clock is driven by the HPLL.
> > To fix that, this patch renames the vpll clock to ref clock.  The clock
> > name "vpll" is left for compatibility to old device trees.
> 
> Can't we just say that the binding only takes the "ref" name, but
> the code still allows "vpll".
> 
> I think I remember Rob suggesting something similar in the past.
> 
> I don't think that we need to keep the binding(-validation)
> compatible with old devicetrees, but the kernel itself should stay
> compatible.

Sounds reasonable. I'll also add a patch changing the in-tree users next
round.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 06/18] dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
  2021-12-08 15:12   ` Sascha Hauer
  (?)
  (?)
@ 2021-12-15 16:27     ` Rob Herring
  -1 siblings, 0 replies; 123+ messages in thread
From: Rob Herring @ 2021-12-15 16:27 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-rockchip, devicetree, Peter Geis, kernel, linux-arm-kernel,
	Sandy Huang, dri-devel, Benjamin Gaignard, Michael Riesch,
	Andy Yan, Heiko Stübner

On Wed, 08 Dec 2021 16:12:18 +0100, Sascha Hauer wrote:
> None of the upstream device tree files has a "unwedge" pinctrl
> specified. Make it optional.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
>  1 file changed, 1 insertion(+)
> 

Acked-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH 06/18] dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
@ 2021-12-15 16:27     ` Rob Herring
  0 siblings, 0 replies; 123+ messages in thread
From: Rob Herring @ 2021-12-15 16:27 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sandy Huang,
	dri-devel, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

On Wed, 08 Dec 2021 16:12:18 +0100, Sascha Hauer wrote:
> None of the upstream device tree files has a "unwedge" pinctrl
> specified. Make it optional.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
>  1 file changed, 1 insertion(+)
> 

Acked-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH 06/18] dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
@ 2021-12-15 16:27     ` Rob Herring
  0 siblings, 0 replies; 123+ messages in thread
From: Rob Herring @ 2021-12-15 16:27 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-rockchip, devicetree, Peter Geis, kernel, linux-arm-kernel,
	Sandy Huang, dri-devel, Benjamin Gaignard, Michael Riesch,
	Andy Yan, Heiko Stübner

On Wed, 08 Dec 2021 16:12:18 +0100, Sascha Hauer wrote:
> None of the upstream device tree files has a "unwedge" pinctrl
> specified. Make it optional.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
>  1 file changed, 1 insertion(+)
> 

Acked-by: Rob Herring <robh@kernel.org>

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 06/18] dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional
@ 2021-12-15 16:27     ` Rob Herring
  0 siblings, 0 replies; 123+ messages in thread
From: Rob Herring @ 2021-12-15 16:27 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-rockchip, devicetree, Peter Geis, kernel, linux-arm-kernel,
	Sandy Huang, dri-devel, Benjamin Gaignard, Michael Riesch,
	Andy Yan, Heiko Stübner

On Wed, 08 Dec 2021 16:12:18 +0100, Sascha Hauer wrote:
> None of the upstream device tree files has a "unwedge" pinctrl
> specified. Make it optional.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml   | 1 +
>  1 file changed, 1 insertion(+)
> 

Acked-by: Rob Herring <robh@kernel.org>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 10/18] dt-bindings: display: rockchip: Add binding for VOP2
  2021-12-08 15:12   ` Sascha Hauer
  (?)
  (?)
@ 2021-12-15 16:38     ` Rob Herring
  -1 siblings, 0 replies; 123+ messages in thread
From: Rob Herring @ 2021-12-15 16:38 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

On Wed, Dec 08, 2021 at 04:12:22PM +0100, Sascha Hauer wrote:
> The VOP2 is found on newer Rockchip SoCs like the rk3568 or the rk3566.
> The binding differs slightly from the existing VOP binding, so add a new
> binding file for it.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../display/rockchip/rockchip-vop2.yaml       | 118 ++++++++++++++++++
>  1 file changed, 118 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> new file mode 100644
> index 0000000000000..6533c4ae4ec3a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> @@ -0,0 +1,118 @@
> +# SPDX-License-Identifier: GPL-2.0

Dual license new bindings.

> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/rockchip/rockchip-vop2.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Rockchip SoC display controller (VOP2)
> +
> +description:
> +  VOP2 (Video Output Processor v2) is the display controller for the Rockchip
> +  series of SoCs which transfers the image data from a video memory
> +  buffer to an external LCD interface.
> +
> +maintainers:
> +  - Sandy Huang <hjc@rock-chips.com>
> +  - Heiko Stuebner <heiko@sntech.de>
> +
> +properties:
> +  compatible:
> +    enum:
> +      - rockchip,rk3566-vop
> +      - rockchip,rk3568-vop
> +
> +  reg:
> +    minItems: 1
> +    items:
> +      - description:
> +          Must contain one entry corresponding to the base address and length
> +          of the register space.
> +      - description:
> +          Can optionally contain a second entry corresponding to
> +          the CRTC gamma LUT address.
> +
> +  interrupts:
> +    maxItems: 1
> +    description:
> +      The VOP interrupt is shared by several interrupt sources, such as
> +      frame start (VSYNC), line flag and other status interrupts.
> +
> +  clocks:
> +    items:
> +      - description: Clock for ddr buffer transfer.
> +      - description: Clock for the ahb bus to R/W the phy regs.
> +      - description: Pixel clock for video port 0.
> +      - description: Pixel clock for video port 1.
> +      - description: Pixel clock for video port 2.
> +
> +  clock-names:
> +    items:
> +      - const: aclk_vop
> +      - const: hclk_vop
> +      - const: dclk_vp0
> +      - const: dclk_vp1
> +      - const: dclk_vp2
> +
> +  port:
> +    $ref: /schemas/graph.yaml#/properties/port

Please describe what the port represents.

> +
> +  assigned-clocks:
> +    maxItems: 2
> +
> +  assigned-clock-rates:
> +    maxItems: 2
> +
> +  iommus:
> +    maxItems: 1
> +
> +  power-domains:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - clock-names
> +  - port
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +        #include <dt-bindings/clock/rk3568-cru.h>
> +        #include <dt-bindings/interrupt-controller/arm-gic.h>
> +        #include <dt-bindings/power/rk3568-power.h>
> +        bus {
> +            #address-cells = <2>;
> +            #size-cells = <2>;
> +            vop: vop@fe040000 {
> +                compatible = "rockchip,rk3568-vop";
> +                reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
> +                interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
> +                clocks = <&cru ACLK_VOP>,
> +                         <&cru HCLK_VOP>,
> +                         <&cru DCLK_VOP0>,
> +                         <&cru DCLK_VOP1>,
> +                         <&cru DCLK_VOP2>;
> +                clock-names = "aclk_vop",
> +                              "hclk_vop",
> +                              "dclk_vp0",
> +                              "dclk_vp1",
> +                              "dclk_vp2";
> +                power-domains = <&power RK3568_PD_VO>;
> +                iommus = <&vop_mmu>;
> +                vop_out: port {
> +                    #address-cells = <1>;
> +                    #size-cells = <0>;
> +                    vp0_out_dsi0: endpoint@0 {
> +                        reg = <0>;
> +                        remote-endpoint = <&dsi0_in_vp0>;
> +                    };
> +                    vp0_out_hdmi: endpoint@1 {
> +                        reg = <1>;
> +                        remote-endpoint = <&hdmi0_in_vp0>;
> +                    };
> +                };
> +            };
> +        };
> -- 
> 2.30.2
> 
> 

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

* Re: [PATCH 10/18] dt-bindings: display: rockchip: Add binding for VOP2
@ 2021-12-15 16:38     ` Rob Herring
  0 siblings, 0 replies; 123+ messages in thread
From: Rob Herring @ 2021-12-15 16:38 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: devicetree, Benjamin Gaignard, Peter Geis, Sandy Huang,
	dri-devel, linux-rockchip, Michael Riesch, kernel, Andy Yan,
	linux-arm-kernel

On Wed, Dec 08, 2021 at 04:12:22PM +0100, Sascha Hauer wrote:
> The VOP2 is found on newer Rockchip SoCs like the rk3568 or the rk3566.
> The binding differs slightly from the existing VOP binding, so add a new
> binding file for it.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../display/rockchip/rockchip-vop2.yaml       | 118 ++++++++++++++++++
>  1 file changed, 118 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> new file mode 100644
> index 0000000000000..6533c4ae4ec3a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> @@ -0,0 +1,118 @@
> +# SPDX-License-Identifier: GPL-2.0

Dual license new bindings.

> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/rockchip/rockchip-vop2.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Rockchip SoC display controller (VOP2)
> +
> +description:
> +  VOP2 (Video Output Processor v2) is the display controller for the Rockchip
> +  series of SoCs which transfers the image data from a video memory
> +  buffer to an external LCD interface.
> +
> +maintainers:
> +  - Sandy Huang <hjc@rock-chips.com>
> +  - Heiko Stuebner <heiko@sntech.de>
> +
> +properties:
> +  compatible:
> +    enum:
> +      - rockchip,rk3566-vop
> +      - rockchip,rk3568-vop
> +
> +  reg:
> +    minItems: 1
> +    items:
> +      - description:
> +          Must contain one entry corresponding to the base address and length
> +          of the register space.
> +      - description:
> +          Can optionally contain a second entry corresponding to
> +          the CRTC gamma LUT address.
> +
> +  interrupts:
> +    maxItems: 1
> +    description:
> +      The VOP interrupt is shared by several interrupt sources, such as
> +      frame start (VSYNC), line flag and other status interrupts.
> +
> +  clocks:
> +    items:
> +      - description: Clock for ddr buffer transfer.
> +      - description: Clock for the ahb bus to R/W the phy regs.
> +      - description: Pixel clock for video port 0.
> +      - description: Pixel clock for video port 1.
> +      - description: Pixel clock for video port 2.
> +
> +  clock-names:
> +    items:
> +      - const: aclk_vop
> +      - const: hclk_vop
> +      - const: dclk_vp0
> +      - const: dclk_vp1
> +      - const: dclk_vp2
> +
> +  port:
> +    $ref: /schemas/graph.yaml#/properties/port

Please describe what the port represents.

> +
> +  assigned-clocks:
> +    maxItems: 2
> +
> +  assigned-clock-rates:
> +    maxItems: 2
> +
> +  iommus:
> +    maxItems: 1
> +
> +  power-domains:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - clock-names
> +  - port
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +        #include <dt-bindings/clock/rk3568-cru.h>
> +        #include <dt-bindings/interrupt-controller/arm-gic.h>
> +        #include <dt-bindings/power/rk3568-power.h>
> +        bus {
> +            #address-cells = <2>;
> +            #size-cells = <2>;
> +            vop: vop@fe040000 {
> +                compatible = "rockchip,rk3568-vop";
> +                reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
> +                interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
> +                clocks = <&cru ACLK_VOP>,
> +                         <&cru HCLK_VOP>,
> +                         <&cru DCLK_VOP0>,
> +                         <&cru DCLK_VOP1>,
> +                         <&cru DCLK_VOP2>;
> +                clock-names = "aclk_vop",
> +                              "hclk_vop",
> +                              "dclk_vp0",
> +                              "dclk_vp1",
> +                              "dclk_vp2";
> +                power-domains = <&power RK3568_PD_VO>;
> +                iommus = <&vop_mmu>;
> +                vop_out: port {
> +                    #address-cells = <1>;
> +                    #size-cells = <0>;
> +                    vp0_out_dsi0: endpoint@0 {
> +                        reg = <0>;
> +                        remote-endpoint = <&dsi0_in_vp0>;
> +                    };
> +                    vp0_out_hdmi: endpoint@1 {
> +                        reg = <1>;
> +                        remote-endpoint = <&hdmi0_in_vp0>;
> +                    };
> +                };
> +            };
> +        };
> -- 
> 2.30.2
> 
> 

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

* Re: [PATCH 10/18] dt-bindings: display: rockchip: Add binding for VOP2
@ 2021-12-15 16:38     ` Rob Herring
  0 siblings, 0 replies; 123+ messages in thread
From: Rob Herring @ 2021-12-15 16:38 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

On Wed, Dec 08, 2021 at 04:12:22PM +0100, Sascha Hauer wrote:
> The VOP2 is found on newer Rockchip SoCs like the rk3568 or the rk3566.
> The binding differs slightly from the existing VOP binding, so add a new
> binding file for it.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../display/rockchip/rockchip-vop2.yaml       | 118 ++++++++++++++++++
>  1 file changed, 118 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> new file mode 100644
> index 0000000000000..6533c4ae4ec3a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> @@ -0,0 +1,118 @@
> +# SPDX-License-Identifier: GPL-2.0

Dual license new bindings.

> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/rockchip/rockchip-vop2.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Rockchip SoC display controller (VOP2)
> +
> +description:
> +  VOP2 (Video Output Processor v2) is the display controller for the Rockchip
> +  series of SoCs which transfers the image data from a video memory
> +  buffer to an external LCD interface.
> +
> +maintainers:
> +  - Sandy Huang <hjc@rock-chips.com>
> +  - Heiko Stuebner <heiko@sntech.de>
> +
> +properties:
> +  compatible:
> +    enum:
> +      - rockchip,rk3566-vop
> +      - rockchip,rk3568-vop
> +
> +  reg:
> +    minItems: 1
> +    items:
> +      - description:
> +          Must contain one entry corresponding to the base address and length
> +          of the register space.
> +      - description:
> +          Can optionally contain a second entry corresponding to
> +          the CRTC gamma LUT address.
> +
> +  interrupts:
> +    maxItems: 1
> +    description:
> +      The VOP interrupt is shared by several interrupt sources, such as
> +      frame start (VSYNC), line flag and other status interrupts.
> +
> +  clocks:
> +    items:
> +      - description: Clock for ddr buffer transfer.
> +      - description: Clock for the ahb bus to R/W the phy regs.
> +      - description: Pixel clock for video port 0.
> +      - description: Pixel clock for video port 1.
> +      - description: Pixel clock for video port 2.
> +
> +  clock-names:
> +    items:
> +      - const: aclk_vop
> +      - const: hclk_vop
> +      - const: dclk_vp0
> +      - const: dclk_vp1
> +      - const: dclk_vp2
> +
> +  port:
> +    $ref: /schemas/graph.yaml#/properties/port

Please describe what the port represents.

> +
> +  assigned-clocks:
> +    maxItems: 2
> +
> +  assigned-clock-rates:
> +    maxItems: 2
> +
> +  iommus:
> +    maxItems: 1
> +
> +  power-domains:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - clock-names
> +  - port
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +        #include <dt-bindings/clock/rk3568-cru.h>
> +        #include <dt-bindings/interrupt-controller/arm-gic.h>
> +        #include <dt-bindings/power/rk3568-power.h>
> +        bus {
> +            #address-cells = <2>;
> +            #size-cells = <2>;
> +            vop: vop@fe040000 {
> +                compatible = "rockchip,rk3568-vop";
> +                reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
> +                interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
> +                clocks = <&cru ACLK_VOP>,
> +                         <&cru HCLK_VOP>,
> +                         <&cru DCLK_VOP0>,
> +                         <&cru DCLK_VOP1>,
> +                         <&cru DCLK_VOP2>;
> +                clock-names = "aclk_vop",
> +                              "hclk_vop",
> +                              "dclk_vp0",
> +                              "dclk_vp1",
> +                              "dclk_vp2";
> +                power-domains = <&power RK3568_PD_VO>;
> +                iommus = <&vop_mmu>;
> +                vop_out: port {
> +                    #address-cells = <1>;
> +                    #size-cells = <0>;
> +                    vp0_out_dsi0: endpoint@0 {
> +                        reg = <0>;
> +                        remote-endpoint = <&dsi0_in_vp0>;
> +                    };
> +                    vp0_out_hdmi: endpoint@1 {
> +                        reg = <1>;
> +                        remote-endpoint = <&hdmi0_in_vp0>;
> +                    };
> +                };
> +            };
> +        };
> -- 
> 2.30.2
> 
> 

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH 10/18] dt-bindings: display: rockchip: Add binding for VOP2
@ 2021-12-15 16:38     ` Rob Herring
  0 siblings, 0 replies; 123+ messages in thread
From: Rob Herring @ 2021-12-15 16:38 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: dri-devel, linux-arm-kernel, linux-rockchip, devicetree, kernel,
	Andy Yan, Benjamin Gaignard, Michael Riesch, Sandy Huang,
	Heiko Stübner, Peter Geis

On Wed, Dec 08, 2021 at 04:12:22PM +0100, Sascha Hauer wrote:
> The VOP2 is found on newer Rockchip SoCs like the rk3568 or the rk3566.
> The binding differs slightly from the existing VOP binding, so add a new
> binding file for it.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  .../display/rockchip/rockchip-vop2.yaml       | 118 ++++++++++++++++++
>  1 file changed, 118 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> new file mode 100644
> index 0000000000000..6533c4ae4ec3a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
> @@ -0,0 +1,118 @@
> +# SPDX-License-Identifier: GPL-2.0

Dual license new bindings.

> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/rockchip/rockchip-vop2.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Rockchip SoC display controller (VOP2)
> +
> +description:
> +  VOP2 (Video Output Processor v2) is the display controller for the Rockchip
> +  series of SoCs which transfers the image data from a video memory
> +  buffer to an external LCD interface.
> +
> +maintainers:
> +  - Sandy Huang <hjc@rock-chips.com>
> +  - Heiko Stuebner <heiko@sntech.de>
> +
> +properties:
> +  compatible:
> +    enum:
> +      - rockchip,rk3566-vop
> +      - rockchip,rk3568-vop
> +
> +  reg:
> +    minItems: 1
> +    items:
> +      - description:
> +          Must contain one entry corresponding to the base address and length
> +          of the register space.
> +      - description:
> +          Can optionally contain a second entry corresponding to
> +          the CRTC gamma LUT address.
> +
> +  interrupts:
> +    maxItems: 1
> +    description:
> +      The VOP interrupt is shared by several interrupt sources, such as
> +      frame start (VSYNC), line flag and other status interrupts.
> +
> +  clocks:
> +    items:
> +      - description: Clock for ddr buffer transfer.
> +      - description: Clock for the ahb bus to R/W the phy regs.
> +      - description: Pixel clock for video port 0.
> +      - description: Pixel clock for video port 1.
> +      - description: Pixel clock for video port 2.
> +
> +  clock-names:
> +    items:
> +      - const: aclk_vop
> +      - const: hclk_vop
> +      - const: dclk_vp0
> +      - const: dclk_vp1
> +      - const: dclk_vp2
> +
> +  port:
> +    $ref: /schemas/graph.yaml#/properties/port

Please describe what the port represents.

> +
> +  assigned-clocks:
> +    maxItems: 2
> +
> +  assigned-clock-rates:
> +    maxItems: 2
> +
> +  iommus:
> +    maxItems: 1
> +
> +  power-domains:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - clock-names
> +  - port
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +        #include <dt-bindings/clock/rk3568-cru.h>
> +        #include <dt-bindings/interrupt-controller/arm-gic.h>
> +        #include <dt-bindings/power/rk3568-power.h>
> +        bus {
> +            #address-cells = <2>;
> +            #size-cells = <2>;
> +            vop: vop@fe040000 {
> +                compatible = "rockchip,rk3568-vop";
> +                reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
> +                interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
> +                clocks = <&cru ACLK_VOP>,
> +                         <&cru HCLK_VOP>,
> +                         <&cru DCLK_VOP0>,
> +                         <&cru DCLK_VOP1>,
> +                         <&cru DCLK_VOP2>;
> +                clock-names = "aclk_vop",
> +                              "hclk_vop",
> +                              "dclk_vp0",
> +                              "dclk_vp1",
> +                              "dclk_vp2";
> +                power-domains = <&power RK3568_PD_VO>;
> +                iommus = <&vop_mmu>;
> +                vop_out: port {
> +                    #address-cells = <1>;
> +                    #size-cells = <0>;
> +                    vp0_out_dsi0: endpoint@0 {
> +                        reg = <0>;
> +                        remote-endpoint = <&dsi0_in_vp0>;
> +                    };
> +                    vp0_out_hdmi: endpoint@1 {
> +                        reg = <1>;
> +                        remote-endpoint = <&hdmi0_in_vp0>;
> +                    };
> +                };
> +            };
> +        };
> -- 
> 2.30.2
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2021-12-15 17:00 UTC | newest]

Thread overview: 123+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-08 15:12 [PATCH v2 00/18] drm/rockchip: RK356x VOP2 support Sascha Hauer
2021-12-08 15:12 ` Sascha Hauer
2021-12-08 15:12 ` Sascha Hauer
2021-12-08 15:12 ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 01/18] drm/rockchip: dw_hdmi: Do not leave clock enabled in error case Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 02/18] drm/rockchip: dw_hdmi: rename vpll clock to reference clock Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 03/18] drm/rockchip: dw_hdmi: add rk3568 support Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 04/18] drm/rockchip: dw_hdmi: add regulator support Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 05/18] dt-bindings: display: rockchip: dw-hdmi: Add compatible for rk3568 HDMI Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 06/18] dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-15 16:27   ` Rob Herring
2021-12-15 16:27     ` Rob Herring
2021-12-15 16:27     ` Rob Herring
2021-12-15 16:27     ` Rob Herring
2021-12-08 15:12 ` [PATCH 07/18] dt-bindings: display: rockchip: dw-hdmi: Allow "ref" as clock name Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-12 22:09   ` Heiko Stuebner
2021-12-12 22:09     ` Heiko Stuebner
2021-12-12 22:09     ` Heiko Stuebner
2021-12-12 22:09     ` Heiko Stuebner
2021-12-13 11:08     ` Sascha Hauer
2021-12-13 11:08       ` Sascha Hauer
2021-12-13 11:08       ` Sascha Hauer
2021-12-13 11:08       ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 08/18] dt-bindings: display: rockchip: dw-hdmi: Add regulator support Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 16:35   ` Robin Murphy
2021-12-08 16:35     ` Robin Murphy
2021-12-08 16:35     ` Robin Murphy
2021-12-08 16:35     ` Robin Murphy
2021-12-08 15:12 ` [PATCH 09/18] arm64: dts: rockchip: rk3399: reorder hmdi clocks Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 10/18] dt-bindings: display: rockchip: Add binding for VOP2 Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-15 16:38   ` Rob Herring
2021-12-15 16:38     ` Rob Herring
2021-12-15 16:38     ` Rob Herring
2021-12-15 16:38     ` Rob Herring
2021-12-08 15:12 ` [PATCH 11/18] arm64: dts: rockchip: rk356x: Add VOP2 nodes Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 12/18] arm64: dts: rockchip: rk356x: Add HDMI nodes Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 13/18] arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 17:30   ` Johan Jonker
2021-12-08 17:30     ` Johan Jonker
2021-12-08 17:30     ` Johan Jonker
2021-12-08 17:30     ` Johan Jonker
2021-12-08 15:12 ` [PATCH 14/18] arm64: dts: rockchip: enable vop2 and hdmi tx on quartz64a Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 15/18] drm/encoder: Add of_graph port to struct drm_encoder Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 16/18] drm/rockchip: Make VOP driver optional Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12 ` [PATCH 17/18] drm: rockchip: Add VOP2 driver Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 16:59   ` Johan Jonker
2021-12-08 16:59     ` Johan Jonker
2021-12-08 16:59     ` Johan Jonker
2021-12-08 16:59     ` Johan Jonker
2021-12-10  8:55     ` Sascha Hauer
2021-12-10  8:55       ` Sascha Hauer
2021-12-10  8:55       ` Sascha Hauer
2021-12-10  8:55       ` Sascha Hauer
2021-12-08 21:50   ` kernel test robot
2021-12-08 21:50     ` kernel test robot
2021-12-08 21:50     ` kernel test robot
2021-12-08 21:50     ` kernel test robot
2021-12-09  0:49   ` kernel test robot
2021-12-09  0:49     ` kernel test robot
2021-12-09  0:49     ` kernel test robot
2021-12-09  0:49     ` kernel test robot
2021-12-08 15:12 ` [PATCH 18/18] [HACK, RFC] clk: rk3568: do not divide dclk_vop0 Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 15:12   ` Sascha Hauer
2021-12-08 16:51   ` Heiko Stübner
2021-12-08 16:51     ` Heiko Stübner
2021-12-08 16:51     ` Heiko Stübner
2021-12-08 16:51     ` Heiko Stübner
2021-12-10  8:51     ` Sascha Hauer
2021-12-10  8:51       ` Sascha Hauer
2021-12-10  8:51       ` Sascha Hauer
2021-12-10  8:51       ` Sascha Hauer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.