linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v8 0/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM
@ 2021-03-02  6:33 Liu Ying
  2021-03-02  6:33 ` [PATCH v8 1/6] dt-bindings: display: imx: Add i.MX8qxp/qm DPU binding Liu Ying
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Liu Ying @ 2021-03-02  6:33 UTC (permalink / raw)
  To: linux-arm-kernel, dri-devel, devicetree, linux-kernel
  Cc: p.zabel, tzimmermann, airlied, festevam, s.hauer,
	maarten.lankhorst, mripard, robh+dt, linux-imx, daniel,
	laurentiu.palcu, guido.gunther, shawnguo, kernel

Hi,


This is the v8 series to introduce i.MX8qm/qxp Display Processing Unit(DPU)
DRM support.

DPU is comprised of a blit engine for 2D graphics, a display controller
and a command sequencer.  Outside of DPU, optional prefetch engines can
fetch data from memory prior to some DPU fetchunits of blit engine and
display controller.  The pre-fetchers support linear formats and Vivante
GPU tile formats.

Reference manual can be found at:
https://www.nxp.com/webapp/Download?colCode=IMX8DQXPRM


This patch set adds kernel modesetting support for the display controller part.
It supports two CRTCs per display controller, several planes, prefetch
engines and some properties of CRTC and plane.  Currently, the registers of
the controller is accessed without command sequencer involved, instead just by
using CPU.  DRM connectors would be created from the DPU KMS driver.


If people want to try this series with i.MX8qxp, clock patches have already
landed in 5.12-rc1, and power domain patches have already landed in 5.11-rc1.

Version2 dropped the device tree patches because we'll use new dt binding
way to support i.MX8qm/qxp clocks.  It depends on the below series to do basic
conversions for the platforms which has not landed yet:
https://www.spinics.net/lists/linux-mmc/msg61965.html


I've sent the below series to add downstream bridges(embedded in i.MX8qm/qxp)
to support LVDS displays:
https://www.spinics.net/lists/arm-kernel/msg876784.html


Patch 1 ~ 3 add dt-bindings for DPU and prefetch engines.
Patch 4 is a minor improvement of a macro to suppress warning as the KMS driver
uses it.
Patch 5 introduces the DPU DRM support.
Patch 6 updates MAINTAINERS.

Welcome comments, thanks.

v7->v8:
* Rebase this series up onto the latest drm-misc-next branch, due to DRM plane
  helper functions API change(atomic_check and atomic_update) from DRM atomic
  core.  So, dpu_plane_atomic_check() and dpu_plane_atomic_update() are updated
  accordingly in patch 5/6.  Also, rename plane->state variables and relevant
  DPU plane state variables in those two functions to reflect they are new
  states, like the patch 'drm: Rename plane->state variables in atomic update
  and disable' recently landed in drm-misc-next.
* Replace drm_gem_fb_prepare_fb() with drm_gem_plane_helper_prepare_fb() in
  patch 5/6, due to DRM core API change.
* Improve DPR burst length for GPU standard tile and 32bpp GPU super tile in
  patch 5/6 to align with the latest version of internal HW documention.

v6->v7:
* Fix return value of dpu_get_irqs() if platform_get_irq() fails. (Laurentiu)
* Use the function array dpu_irq_handler[] to store individual DPU irq handlers.
  (Laurentiu)
* Call get/put() hooks directly to get/put DPU fetchunits for DPU plane groups.
  (Laurentiu)
* Shorten the names of individual DPU irq handlers by using DPU unit abbrev
  names to make writing dpu_irq_handler[] easier.
* Add Rob's R-b tag back on DPU dt-binding patch as change in v6 was reviewed.

v5->v6:
* Use graph schema in the DPU dt-binding.
* Do not use macros where possible in the DPU DRM driver. (Laurentiu)
* Break dpu_plane_atomic_check() into some smaller functions. (Laurentiu)
* Address some minor comments from Laurentiu on the DPU DRM driver.
* Add dpu_crtc_err() helper marco in the DPU DRM driver to tell dmesg
  which CRTC generates error.
* Drop calling dev_set_drvdata() from dpu_drm_bind/unbind() in the DPU DRM
  driver as it is done in dpu_drm_probe().
* Some trivial tweaks.

v4->v5:
* Rebase up onto the latest drm-misc-next branch and remove the hook to
  drm_atomic_helper_legacy_gamma_set() from patch 5/6, because it was dropped
  by the newly landed commit 'drm: automatic legacy gamma support'.
* Remove a redundant blank line from dpu_plane_atomic_update() in patch 5/6.

v3->v4:
* Improve compatible properties in DPU and prefetch engines' dt bindings
  by using enum instead of oneOf+const.
* Add Rob's R-b tags on dt binding patches(patch 1/6, 2/6 and 3/6).
* Add Daniel's A-b tag on patch 4/6.

v2->v3:
* Fix DPU DRM driver build warnings which are
  Reported-by: kernel test robot <lkp@intel.com>.
* Drop DPU DRM driver build dependency on IMX_SCU, as dummy SCU functions have
  been added in header files by the patch 'firmware: imx: add dummy functions'
  which has landed in linux-next/master branch.
* Add a missing blank line in include/drm/drm_atomic.h.

v1->v2:
* Test this patch set also with i.MX8qm LVDS displays.
* Drop the device tree patches because we'll use new dt binding way to
  support i.MX8qm/qxp clocks.  This depends on a not-yet-landed patch set
  to do basic conversions for the platforms.
* Fix dt binding yamllint warnings.
* Require bypass0 and bypass1 clocks for both i.MX8qxp and i.MX8qm in DPU's
  dt binding documentation.
* Use new dt binding way to add clocks in the dt binding examples.
* Address several comments from Laurentiu on the DPU DRM patch.

Liu Ying (6):
  dt-bindings: display: imx: Add i.MX8qxp/qm DPU binding
  dt-bindings: display: imx: Add i.MX8qxp/qm PRG binding
  dt-bindings: display: imx: Add i.MX8qxp/qm DPR channel binding
  drm/atomic: Avoid unused-but-set-variable warning on
    for_each_old_plane_in_state
  drm/imx: Introduce i.MX8qm/qxp DPU DRM
  MAINTAINERS: add maintainer for i.MX8qxp DPU DRM driver

 .../bindings/display/imx/fsl,imx8qxp-dprc.yaml     |   87 ++
 .../bindings/display/imx/fsl,imx8qxp-dpu.yaml      |  387 +++++++
 .../bindings/display/imx/fsl,imx8qxp-prg.yaml      |   60 ++
 MAINTAINERS                                        |    9 +
 drivers/gpu/drm/imx/Kconfig                        |    1 +
 drivers/gpu/drm/imx/Makefile                       |    1 +
 drivers/gpu/drm/imx/dpu/Kconfig                    |   10 +
 drivers/gpu/drm/imx/dpu/Makefile                   |   10 +
 drivers/gpu/drm/imx/dpu/dpu-constframe.c           |  171 ++++
 drivers/gpu/drm/imx/dpu/dpu-core.c                 | 1054 ++++++++++++++++++++
 drivers/gpu/drm/imx/dpu/dpu-crtc.c                 |  967 ++++++++++++++++++
 drivers/gpu/drm/imx/dpu/dpu-crtc.h                 |   66 ++
 drivers/gpu/drm/imx/dpu/dpu-disengcfg.c            |  117 +++
 drivers/gpu/drm/imx/dpu/dpu-dprc.c                 |  722 ++++++++++++++
 drivers/gpu/drm/imx/dpu/dpu-dprc.h                 |   40 +
 drivers/gpu/drm/imx/dpu/dpu-drv.c                  |  292 ++++++
 drivers/gpu/drm/imx/dpu/dpu-drv.h                  |   28 +
 drivers/gpu/drm/imx/dpu/dpu-extdst.c               |  299 ++++++
 drivers/gpu/drm/imx/dpu/dpu-fetchdecode.c          |  294 ++++++
 drivers/gpu/drm/imx/dpu/dpu-fetcheco.c             |  224 +++++
 drivers/gpu/drm/imx/dpu/dpu-fetchlayer.c           |  154 +++
 drivers/gpu/drm/imx/dpu/dpu-fetchunit.c            |  609 +++++++++++
 drivers/gpu/drm/imx/dpu/dpu-fetchunit.h            |  191 ++++
 drivers/gpu/drm/imx/dpu/dpu-fetchwarp.c            |  250 +++++
 drivers/gpu/drm/imx/dpu/dpu-framegen.c             |  395 ++++++++
 drivers/gpu/drm/imx/dpu/dpu-gammacor.c             |  223 +++++
 drivers/gpu/drm/imx/dpu/dpu-hscaler.c              |  275 +++++
 drivers/gpu/drm/imx/dpu/dpu-kms.c                  |  540 ++++++++++
 drivers/gpu/drm/imx/dpu/dpu-kms.h                  |   23 +
 drivers/gpu/drm/imx/dpu/dpu-layerblend.c           |  348 +++++++
 drivers/gpu/drm/imx/dpu/dpu-plane.c                |  802 +++++++++++++++
 drivers/gpu/drm/imx/dpu/dpu-plane.h                |   56 ++
 drivers/gpu/drm/imx/dpu/dpu-prg.c                  |  433 ++++++++
 drivers/gpu/drm/imx/dpu/dpu-prg.h                  |   45 +
 drivers/gpu/drm/imx/dpu/dpu-prv.h                  |  233 +++++
 drivers/gpu/drm/imx/dpu/dpu-tcon.c                 |  250 +++++
 drivers/gpu/drm/imx/dpu/dpu-vscaler.c              |  308 ++++++
 drivers/gpu/drm/imx/dpu/dpu.h                      |  385 +++++++
 include/drm/drm_atomic.h                           |    5 +-
 39 files changed, 10363 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dprc.yaml
 create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dpu.yaml
 create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-prg.yaml
 create mode 100644 drivers/gpu/drm/imx/dpu/Kconfig
 create mode 100644 drivers/gpu/drm/imx/dpu/Makefile
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-constframe.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-core.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-crtc.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-crtc.h
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-disengcfg.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-dprc.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-dprc.h
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-drv.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-drv.h
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-extdst.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchdecode.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetcheco.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchlayer.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchunit.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchunit.h
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchwarp.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-framegen.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-gammacor.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-hscaler.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-kms.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-kms.h
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-layerblend.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-plane.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-plane.h
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-prg.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-prg.h
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-prv.h
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-tcon.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu-vscaler.c
 create mode 100644 drivers/gpu/drm/imx/dpu/dpu.h

-- 
2.7.4


_______________________________________________
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] 8+ messages in thread

* [PATCH v8 1/6] dt-bindings: display: imx: Add i.MX8qxp/qm DPU binding
  2021-03-02  6:33 [PATCH v8 0/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM Liu Ying
@ 2021-03-02  6:33 ` Liu Ying
  2021-03-02  6:33 ` [PATCH v8 2/6] dt-bindings: display: imx: Add i.MX8qxp/qm PRG binding Liu Ying
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Liu Ying @ 2021-03-02  6:33 UTC (permalink / raw)
  To: linux-arm-kernel, dri-devel, devicetree, linux-kernel
  Cc: p.zabel, tzimmermann, airlied, festevam, s.hauer,
	maarten.lankhorst, mripard, robh+dt, linux-imx, daniel,
	laurentiu.palcu, guido.gunther, shawnguo, kernel

This patch adds bindings for i.MX8qxp/qm Display Processing Unit.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
v7->v8:
* No change.

v6->v7:
* Add Rob's R-b tag back.

v5->v6:
* Use graph schema. So, drop Rob's R-b tag as review is needed.

v4->v5:
* No change.

v3->v4:
* Improve compatible property by using enum instead of oneOf+const. (Rob)
* Add Rob's R-b tag.

v2->v3:
* No change.

v1->v2:
* Fix yamllint warnings.
* Require bypass0 and bypass1 clocks for both i.MX8qxp and i.MX8qm, as the
  display controller subsystem spec does say that they exist.
* Use new dt binding way to add clocks in the example.
* Trivial tweaks for the example.

 .../bindings/display/imx/fsl,imx8qxp-dpu.yaml      | 387 +++++++++++++++++++++
 1 file changed, 387 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dpu.yaml

diff --git a/Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dpu.yaml b/Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dpu.yaml
new file mode 100644
index 00000000..9da9560
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dpu.yaml
@@ -0,0 +1,387 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dpu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale i.MX8qm/qxp Display Processing Unit
+
+maintainers:
+  - Liu Ying <victor.liu@nxp.com>
+
+description: |
+  The Freescale i.MX8qm/qxp Display Processing Unit(DPU) is comprised of two
+  main components that include a blit engine for 2D graphics accelerations
+  and a display controller for display output processing, as well as a command
+  sequencer.
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8qxp-dpu
+      - fsl,imx8qm-dpu
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: |
+          store9 shadow load interrupt(blit engine)
+      - description: |
+          store9 frame complete interrupt(blit engine)
+      - description: |
+          store9 sequence complete interrupt(blit engine)
+      - description: |
+          extdst0 shadow load interrupt
+          (display controller, content stream 0)
+      - description: |
+          extdst0 frame complete interrupt
+          (display controller, content stream 0)
+      - description: |
+          extdst0 sequence complete interrupt
+          (display controller, content stream 0)
+      - description: |
+          extdst4 shadow load interrupt
+          (display controller, safety stream 0)
+      - description: |
+          extdst4 frame complete interrupt
+          (display controller, safety stream 0)
+      - description: |
+          extdst4 sequence complete interrupt
+          (display controller, safety stream 0)
+      - description: |
+          extdst1 shadow load interrupt
+          (display controller, content stream 1)
+      - description: |
+          extdst1 frame complete interrupt
+          (display controller, content stream 1)
+      - description: |
+          extdst1 sequence complete interrupt
+          (display controller, content stream 1)
+      - description: |
+          extdst5 shadow load interrupt
+          (display controller, safety stream 1)
+      - description: |
+          extdst5 frame complete interrupt
+          (display controller, safety stream 1)
+      - description: |
+          extdst5 sequence complete interrupt
+          (display controller, safety stream 1)
+      - description: |
+          disengcfg0 shadow load interrupt
+          (display controller, display stream 0)
+      - description: |
+          disengcfg0 frame complete interrupt
+          (display controller, display stream 0)
+      - description: |
+          disengcfg0 sequence complete interrupt
+          (display controller, display stream 0)
+      - description: |
+          framegen0 programmable interrupt0
+          (display controller, display stream 0)
+      - description: |
+          framegen0 programmable interrupt1
+          (display controller, display stream 0)
+      - description: |
+          framegen0 programmable interrupt2
+          (display controller, display stream 0)
+      - description: |
+          framegen0 programmable interrupt3
+          (display controller, display stream 0)
+      - description: |
+          signature0 shadow load interrupt
+          (display controller, display stream 0)
+      - description: |
+          signature0 measurement valid interrupt
+          (display controller, display stream 0)
+      - description: |
+          signature0 error condition interrupt
+          (display controller, display stream 0)
+      - description: |
+          disengcfg1 shadow load interrupt
+          (display controller, display stream 1)
+      - description: |
+          disengcfg1 frame complete interrupt
+          (display controller, display stream 1)
+      - description: |
+          disengcfg1 sequence complete interrupt
+          (display controller, display stream 1)
+      - description: |
+          framegen1 programmable interrupt0
+          (display controller, display stream 1)
+      - description: |
+          framegen1 programmable interrupt1
+          (display controller, display stream 1)
+      - description: |
+          framegen1 programmable interrupt2
+          (display controller, display stream 1)
+      - description: |
+          framegen1 programmable interrupt3
+          (display controller, display stream 1)
+      - description: |
+          signature1 shadow load interrupt
+          (display controller, display stream 1)
+      - description: |
+          signature1 measurement valid interrupt
+          (display controller, display stream 1)
+      - description: |
+          signature1 error condition interrupt
+          (display controller, display stream 1)
+      - description: |
+          command sequencer error condition interrupt(command sequencer)
+      - description: |
+          common control software interrupt0(common control)
+      - description: |
+          common control software interrupt1(common control)
+      - description: |
+          common control software interrupt2(common control)
+      - description: |
+          common control software interrupt3(common control)
+      - description: |
+          framegen0 sychronization status activated interrupt
+          (display controller, safety stream 0)
+      - description: |
+          framegen0 sychronization status deactivated interrupt
+          (display controller, safety stream 0)
+      - description: |
+          framegen0 sychronization status activated interrupt
+          (display controller, content stream 0)
+      - description: |
+          framegen0 sychronization status deactivated interrupt
+          (display controller, content stream 0)
+      - description: |
+          framegen1 sychronization status activated interrupt
+          (display controller, safety stream 1)
+      - description: |
+          framegen1 sychronization status deactivated interrupt
+          (display controller, safety stream 1)
+      - description: |
+          framegen1 sychronization status activated interrupt
+          (display controller, content stream 1)
+      - description: |
+          framegen1 sychronization status deactivated interrupt
+          (display controller, content stream 1)
+
+  interrupt-names:
+    items:
+      - const: store9_shdload
+      - const: store9_framecomplete
+      - const: store9_seqcomplete
+      - const: extdst0_shdload
+      - const: extdst0_framecomplete
+      - const: extdst0_seqcomplete
+      - const: extdst4_shdload
+      - const: extdst4_framecomplete
+      - const: extdst4_seqcomplete
+      - const: extdst1_shdload
+      - const: extdst1_framecomplete
+      - const: extdst1_seqcomplete
+      - const: extdst5_shdload
+      - const: extdst5_framecomplete
+      - const: extdst5_seqcomplete
+      - const: disengcfg_shdload0
+      - const: disengcfg_framecomplete0
+      - const: disengcfg_seqcomplete0
+      - const: framegen0_int0
+      - const: framegen0_int1
+      - const: framegen0_int2
+      - const: framegen0_int3
+      - const: sig0_shdload
+      - const: sig0_valid
+      - const: sig0_error
+      - const: disengcfg_shdload1
+      - const: disengcfg_framecomplete1
+      - const: disengcfg_seqcomplete1
+      - const: framegen1_int0
+      - const: framegen1_int1
+      - const: framegen1_int2
+      - const: framegen1_int3
+      - const: sig1_shdload
+      - const: sig1_valid
+      - const: sig1_error
+      - const: cmdseq_error
+      - const: comctrl_sw0
+      - const: comctrl_sw1
+      - const: comctrl_sw2
+      - const: comctrl_sw3
+      - const: framegen0_primsync_on
+      - const: framegen0_primsync_off
+      - const: framegen0_secsync_on
+      - const: framegen0_secsync_off
+      - const: framegen1_primsync_on
+      - const: framegen1_primsync_off
+      - const: framegen1_secsync_on
+      - const: framegen1_secsync_off
+
+  clocks:
+    maxItems: 8
+
+  clock-names:
+    items:
+      - const: axi
+      - const: cfg
+      - const: pll0
+      - const: pll1
+      - const: bypass0
+      - const: bypass1
+      - const: disp0
+      - const: disp1
+
+  power-domains:
+    items:
+      - description: DC power-domain
+      - description: PLL0 power-domain
+      - description: PLL1 power-domain
+
+  power-domain-names:
+    items:
+      - const: dc
+      - const: pll0
+      - const: pll1
+
+  fsl,dpr-channels:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description: |
+      List of phandle which points to DPR channels associated with
+      this DPU instance.
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port@0:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: The DPU output port node from display stream0.
+
+      port@1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: The DPU output port node from display stream1.
+
+    required:
+      - port@0
+      - port@1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clock-names
+  - power-domains
+  - power-domain-names
+  - fsl,dpr-channels
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8-lpcg.h>
+    #include <dt-bindings/firmware/imx/rsrc.h>
+    dpu@56180000 {
+        compatible = "fsl,imx8qxp-dpu";
+        reg = <0x56180000 0x40000>;
+        interrupt-parent = <&dc0_irqsteer>;
+        interrupts = <448>, <449>, <450>,  <64>,
+                      <65>,  <66>,  <67>,  <68>,
+                      <69>,  <70>, <193>, <194>,
+                     <195>, <196>, <197>,  <72>,
+                      <73>,  <74>,  <75>,  <76>,
+                      <77>,  <78>,  <79>,  <80>,
+                      <81>, <199>, <200>, <201>,
+                     <202>, <203>, <204>, <205>,
+                     <206>, <207>, <208>,   <0>,
+                       <1>,   <2>,   <3>,   <4>,
+                      <82>,  <83>,  <84>,  <85>,
+                     <209>, <210>, <211>, <212>;
+        interrupt-names = "store9_shdload",
+                          "store9_framecomplete",
+                          "store9_seqcomplete",
+                          "extdst0_shdload",
+                          "extdst0_framecomplete",
+                          "extdst0_seqcomplete",
+                          "extdst4_shdload",
+                          "extdst4_framecomplete",
+                          "extdst4_seqcomplete",
+                          "extdst1_shdload",
+                          "extdst1_framecomplete",
+                          "extdst1_seqcomplete",
+                          "extdst5_shdload",
+                          "extdst5_framecomplete",
+                          "extdst5_seqcomplete",
+                          "disengcfg_shdload0",
+                          "disengcfg_framecomplete0",
+                          "disengcfg_seqcomplete0",
+                          "framegen0_int0",
+                          "framegen0_int1",
+                          "framegen0_int2",
+                          "framegen0_int3",
+                          "sig0_shdload",
+                          "sig0_valid",
+                          "sig0_error",
+                          "disengcfg_shdload1",
+                          "disengcfg_framecomplete1",
+                          "disengcfg_seqcomplete1",
+                          "framegen1_int0",
+                          "framegen1_int1",
+                          "framegen1_int2",
+                          "framegen1_int3",
+                          "sig1_shdload",
+                          "sig1_valid",
+                          "sig1_error",
+                          "cmdseq_error",
+                          "comctrl_sw0",
+                          "comctrl_sw1",
+                          "comctrl_sw2",
+                          "comctrl_sw3",
+                          "framegen0_primsync_on",
+                          "framegen0_primsync_off",
+                          "framegen0_secsync_on",
+                          "framegen0_secsync_off",
+                          "framegen1_primsync_on",
+                          "framegen1_primsync_off",
+                          "framegen1_secsync_on",
+                          "framegen1_secsync_off";
+        clocks = <&dc0_dpu_lpcg IMX_LPCG_CLK_5>,
+                 <&dc0_dpu_lpcg IMX_LPCG_CLK_4>,
+                 <&clk IMX_SC_R_DC_0_PLL_0 IMX_SC_PM_CLK_PLL>,
+                 <&clk IMX_SC_R_DC_0_PLL_1 IMX_SC_PM_CLK_PLL>,
+                 <&clk IMX_SC_R_DC_0_VIDEO0 IMX_SC_PM_CLK_BYPASS>,
+                 <&clk IMX_SC_R_DC_0_VIDEO1 IMX_SC_PM_CLK_BYPASS>,
+                 <&dc0_disp_lpcg IMX_LPCG_CLK_0>,
+                 <&dc0_disp_lpcg IMX_LPCG_CLK_1>;
+        clock-names = "axi", "cfg",
+                      "pll0", "pll1", "bypass0", "bypass1",
+                      "disp0", "disp1";
+        power-domains = <&pd IMX_SC_R_DC_0>,
+                        <&pd IMX_SC_R_DC_0_PLL_0>,
+                        <&pd IMX_SC_R_DC_0_PLL_1>;
+        power-domain-names = "dc", "pll0", "pll1";
+        fsl,dpr-channels = <&dc0_dpr1_channel1>,
+                           <&dc0_dpr1_channel2>,
+                           <&dc0_dpr1_channel3>,
+                           <&dc0_dpr2_channel1>,
+                           <&dc0_dpr2_channel2>,
+                           <&dc0_dpr2_channel3>;
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port@0 {
+                reg = <0>;
+                dpu0_disp0_pixel_combiner0_ch0: endpoint {
+                    remote-endpoint = <&pixel_combiner0_ch0_dpu0_disp0>;
+                };
+            };
+
+            port@1 {
+                reg = <1>;
+                dpu0_disp1_pixel_combiner0_ch1: endpoint {
+                    remote-endpoint = <&pixel_combiner0_ch1_dpu0_disp1>;
+                };
+            };
+        };
+    };
-- 
2.7.4


_______________________________________________
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] 8+ messages in thread

* [PATCH v8 2/6] dt-bindings: display: imx: Add i.MX8qxp/qm PRG binding
  2021-03-02  6:33 [PATCH v8 0/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM Liu Ying
  2021-03-02  6:33 ` [PATCH v8 1/6] dt-bindings: display: imx: Add i.MX8qxp/qm DPU binding Liu Ying
@ 2021-03-02  6:33 ` Liu Ying
  2021-03-02  6:33 ` [PATCH v8 3/6] dt-bindings: display: imx: Add i.MX8qxp/qm DPR channel binding Liu Ying
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Liu Ying @ 2021-03-02  6:33 UTC (permalink / raw)
  To: linux-arm-kernel, dri-devel, devicetree, linux-kernel
  Cc: p.zabel, tzimmermann, airlied, festevam, s.hauer,
	maarten.lankhorst, mripard, robh+dt, linux-imx, daniel,
	laurentiu.palcu, guido.gunther, shawnguo, kernel

This patch adds bindings for i.MX8qxp/qm Display Prefetch Resolve Gasket.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
v7->v8:
* No change.

v6->v7:
* No change.

v5->v6:
* No change.

v4->v5:
* No change.

v3->v4:
* Improve compatible property by using enum instead of oneOf+const. (Rob)
* Add Rob's R-b tag.

v2->v3:
* No change.

v1->v2:
* Use new dt binding way to add clocks in the example.

 .../bindings/display/imx/fsl,imx8qxp-prg.yaml      | 60 ++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-prg.yaml

diff --git a/Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-prg.yaml b/Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-prg.yaml
new file mode 100644
index 00000000..3ff46e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-prg.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-prg.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale i.MX8qm/qxp Display Prefetch Resolve Gasket
+
+maintainers:
+  - Liu Ying <victor.liu@nxp.com>
+
+description: |
+  The i.MX8qm/qxp Prefetch Resolve Gasket (PRG) is a gasket interface between
+  RTRAM controller and Display Controller.  The main function is to convert
+  the AXI interface to the RTRAM interface, which includes re-mapping the
+  ARADDR to a RTRAM address.
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8qxp-prg
+      - fsl,imx8qm-prg
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: rtram clock
+      - description: apb clock
+
+  clock-names:
+    items:
+      - const: rtram
+      - const: apb
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8-lpcg.h>
+    #include <dt-bindings/firmware/imx/rsrc.h>
+    prg@56040000 {
+        compatible = "fsl,imx8qxp-prg";
+        reg = <0x56040000 0x10000>;
+        clocks = <&dc0_prg0_lpcg IMX_LPCG_CLK_0>,
+                 <&dc0_prg0_lpcg IMX_LPCG_CLK_4>;
+        clock-names = "rtram", "apb";
+        power-domains = <&pd IMX_SC_R_DC_0>;
+    };
-- 
2.7.4


_______________________________________________
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] 8+ messages in thread

* [PATCH v8 3/6] dt-bindings: display: imx: Add i.MX8qxp/qm DPR channel binding
  2021-03-02  6:33 [PATCH v8 0/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM Liu Ying
  2021-03-02  6:33 ` [PATCH v8 1/6] dt-bindings: display: imx: Add i.MX8qxp/qm DPU binding Liu Ying
  2021-03-02  6:33 ` [PATCH v8 2/6] dt-bindings: display: imx: Add i.MX8qxp/qm PRG binding Liu Ying
@ 2021-03-02  6:33 ` Liu Ying
  2021-03-02  6:33 ` [PATCH v8 4/6] drm/atomic: Avoid unused-but-set-variable warning on for_each_old_plane_in_state Liu Ying
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Liu Ying @ 2021-03-02  6:33 UTC (permalink / raw)
  To: linux-arm-kernel, dri-devel, devicetree, linux-kernel
  Cc: p.zabel, tzimmermann, airlied, festevam, s.hauer,
	maarten.lankhorst, mripard, robh+dt, linux-imx, daniel,
	laurentiu.palcu, guido.gunther, shawnguo, kernel

This patch adds bindings for i.MX8qxp/qm Display Prefetch Resolve Channel.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
v7->v8:
* No change.

v6->v7:
* No change.

v5->v6:
* No change.

v4->v5:
* No change.

v3->v4:
* Improve compatible property by using enum instead of oneOf+const. (Rob)
* Add Rob's R-b tag.

v2->v3:
* No change.

v1->v2:
* Use new dt binding way to add clocks in the example.

 .../bindings/display/imx/fsl,imx8qxp-dprc.yaml     | 87 ++++++++++++++++++++++
 1 file changed, 87 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dprc.yaml

diff --git a/Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dprc.yaml b/Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dprc.yaml
new file mode 100644
index 00000000..9e05c83
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dprc.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dprc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale i.MX8qm/qxp Display Prefetch Resolve Channel
+
+maintainers:
+  - Liu Ying <victor.liu@nxp.com>
+
+description: |
+  The i.MX8qm/qxp Display Prefetch Resolve Channel(DPRC) is an engine which
+  fetches display data before the display pipeline needs the data to drive
+  pixels in the active display region.  This data is transformed, or resolved,
+  from a variety of tiled buffer formats into linear format, if needed.
+  The DPR works with a double bank memory structure.  This memory structure is
+  implemented in the Resolve Tile Memory(RTRAM) and the banks are referred to
+  as A and B.  Each bank is either 4 or 8 lines high depending on the source
+  frame buffer format.
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8qxp-dpr-channel
+      - fsl,imx8qm-dpr-channel
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: apb clock
+      - description: b clock
+      - description: rtram clock
+
+  clock-names:
+    items:
+      - const: apb
+      - const: b
+      - const: rtram
+
+  fsl,sc-resource:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: The SCU resource ID associated with this DPRC instance.
+
+  fsl,prgs:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description: |
+      List of phandle which points to Prefetch Resolve Gaskets(PRGs)
+      associated with this DPRC instance.
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - fsl,sc-resource
+  - fsl,prgs
+  - power-domains
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8-lpcg.h>
+    #include <dt-bindings/firmware/imx/rsrc.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    dpr-channel@56100000 {
+        compatible = "fsl,imx8qxp-dpr-channel";
+        reg = <0x56100000 0x10000>;
+        interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&dc0_dpr1_lpcg IMX_LPCG_CLK_4>,
+                 <&dc0_dpr1_lpcg IMX_LPCG_CLK_5>,
+                 <&dc0_rtram1_lpcg IMX_LPCG_CLK_0>;
+        clock-names = "apb", "b", "rtram";
+        fsl,sc-resource = <IMX_SC_R_DC_0_VIDEO0>;
+        fsl,prgs = <&dc0_prg4>, <&dc0_prg5>;
+        power-domains = <&pd IMX_SC_R_DC_0>;
+    };
-- 
2.7.4


_______________________________________________
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] 8+ messages in thread

* [PATCH v8 4/6] drm/atomic: Avoid unused-but-set-variable warning on for_each_old_plane_in_state
  2021-03-02  6:33 [PATCH v8 0/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM Liu Ying
                   ` (2 preceding siblings ...)
  2021-03-02  6:33 ` [PATCH v8 3/6] dt-bindings: display: imx: Add i.MX8qxp/qm DPR channel binding Liu Ying
@ 2021-03-02  6:33 ` Liu Ying
  2021-03-02  6:33 ` [PATCH v8 6/6] MAINTAINERS: add maintainer for i.MX8qxp DPU DRM driver Liu Ying
       [not found] ` <1614666796-19374-6-git-send-email-victor.liu@nxp.com>
  5 siblings, 0 replies; 8+ messages in thread
From: Liu Ying @ 2021-03-02  6:33 UTC (permalink / raw)
  To: linux-arm-kernel, dri-devel, devicetree, linux-kernel
  Cc: p.zabel, tzimmermann, airlied, festevam, s.hauer,
	maarten.lankhorst, mripard, robh+dt, linux-imx, daniel,
	laurentiu.palcu, guido.gunther, shawnguo, kernel

Artificially use 'plane' and 'old_plane_state' to avoid 'not used' warning.
The precedent has already been set by other macros in the same file.

Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
v7->v8:
* No change.

v6->v7:
* No change.

v5->v6:
* Fix commit message typo - s/Artifically/Artificially/

v4->v5:
* No change.

v3->v4:
* Add Daniel's A-b tag.

v2->v3:
* Add a missing blank line.

v1->v2:
* No change.

 include/drm/drm_atomic.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index ac5a28e..76d8dee 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -912,7 +912,10 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
 	     (__i)++)							\
 		for_each_if ((__state)->planes[__i].ptr &&		\
 			     ((plane) = (__state)->planes[__i].ptr,	\
-			      (old_plane_state) = (__state)->planes[__i].old_state, 1))
+			      (void)(plane) /* Only to avoid unused-but-set-variable warning */, \
+			      (old_plane_state) = (__state)->planes[__i].old_state, \
+			      (void)(old_plane_state) /* Only to avoid unused-but-set-variable warning */, 1))
+
 /**
  * for_each_new_plane_in_state - iterate over all planes in an atomic update
  * @__state: &struct drm_atomic_state pointer
-- 
2.7.4


_______________________________________________
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] 8+ messages in thread

* [PATCH v8 6/6] MAINTAINERS: add maintainer for i.MX8qxp DPU DRM driver
  2021-03-02  6:33 [PATCH v8 0/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM Liu Ying
                   ` (3 preceding siblings ...)
  2021-03-02  6:33 ` [PATCH v8 4/6] drm/atomic: Avoid unused-but-set-variable warning on for_each_old_plane_in_state Liu Ying
@ 2021-03-02  6:33 ` Liu Ying
       [not found] ` <1614666796-19374-6-git-send-email-victor.liu@nxp.com>
  5 siblings, 0 replies; 8+ messages in thread
From: Liu Ying @ 2021-03-02  6:33 UTC (permalink / raw)
  To: linux-arm-kernel, dri-devel, devicetree, linux-kernel
  Cc: p.zabel, tzimmermann, airlied, festevam, s.hauer,
	maarten.lankhorst, mripard, robh+dt, linux-imx, daniel,
	laurentiu.palcu, guido.gunther, shawnguo, kernel

Add myself as the maintainer of the i.MX8qxp DPU DRM driver.

Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
v7->v8:
* No change.

v6->v7:
* No change.

v5->v6:
* No change.

v4->v5:
* No change.

v3->v4:
* No change.

v2->v3:
* No change.

v1->v2:
* No change.

 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 63bd69c..08cd9cd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5892,6 +5892,15 @@ F:	Documentation/devicetree/bindings/display/imx/
 F:	drivers/gpu/drm/imx/
 F:	drivers/gpu/ipu-v3/
 
+DRM DRIVERS FOR FREESCALE i.MX8QXP
+M:	Liu Ying <victor.liu@nxp.com>
+L:	dri-devel@lists.freedesktop.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dprc.yaml
+F:	Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dpu.yaml
+F:	Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-prg.yaml
+F:	drivers/gpu/drm/imx/dpu/
+
 DRM DRIVERS FOR GMA500 (Poulsbo, Moorestown and derivative chipsets)
 M:	Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
 L:	dri-devel@lists.freedesktop.org
-- 
2.7.4


_______________________________________________
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] 8+ messages in thread

* Re: [PATCH v8 5/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM
       [not found] ` <1614666796-19374-6-git-send-email-victor.liu@nxp.com>
@ 2021-03-02 14:36   ` Laurentiu Palcu
  2021-03-03  6:21     ` Liu Ying
  0 siblings, 1 reply; 8+ messages in thread
From: Laurentiu Palcu @ 2021-03-02 14:36 UTC (permalink / raw)
  To: Liu Ying
  Cc: linux-arm-kernel, dri-devel, devicetree, linux-kernel, p.zabel,
	airlied, daniel, shawnguo, s.hauer, kernel, festevam, linux-imx,
	robh+dt, maarten.lankhorst, mripard, tzimmermann, guido.gunther

Hi Liu Ying,

One comment below.

On Tue, Mar 02, 2021 at 02:33:15PM +0800, Liu Ying wrote:
> This patch introduces i.MX8qm/qxp Display Processing Unit(DPU) DRM support.
> 
> DPU is comprised of two main components that include a blit engine for
> 2D graphics accelerations(with composition support) and a display controller
> for display output processing, as well as a command sequencer.  Outside of
> DPU, optional prefetch engines, a.k.a, Prefetch Resolve Gasket(PRG) and
> Display Prefetch Resolve(DPR), can fetch data from memory prior to some DPU
> fetchunits of blit engine and display controller.  The prefetch engines
> support reading linear formats and resolving Vivante GPU tile formats.
> 
> This patch adds kernel modesetting support for the display controller part.
> The driver supports two CRTCs per display controller, planes backed by
> four fetchunits(decode0/1, fetchlayer, fetchwarp), fetchunit allocation
> logic for the two CRTCs, prefetch engines(with tile resolving supported),
> plane upscaling/deinterlacing/yuv2rgb CSC/alpha blending and CRTC gamma
> correction.  The registers of the controller is accessed without command
> sequencer involved, instead just by using CPU.
> 
> Reference manual can be found at:
> https://www.nxp.com/webapp/Download?colCode=IMX8DQXPRM
> 
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
> Laurentiu, I see your R-b tag on this patch of v7.
> As this patch is changed in v8, can you please help review and maybe add your
> R-b tag again?
> 
> v7->v8:
> * Update dpu_plane_atomic_check() and dpu_plane_atomic_update(), due to DRM
>   plane helper functions API change(atomic_check and atomic_update) from DRM
>   atomic core.  Also, rename plane->state variables and relevant DPU plane
>   state variables in those two functions to reflect they are new states, like
>   the patch 'drm: Rename plane->state variables in atomic update and disable'
>   recently landed in drm-misc-next.
> * Replace drm_gem_fb_prepare_fb() with drm_gem_plane_helper_prepare_fb(),
>   due to DRM core API change.
> * Use 256byte DPR burst length for GPU standard tile and 128byte DPR burst
>   length for 32bpp GPU super tile to align with the latest version of internal
>   HW documention.
> 
> v6->v7:
> * Fix return value of dpu_get_irqs() if platform_get_irq() fails. (Laurentiu)
> * Use the function array dpu_irq_handler[] to store individual DPU irq handlers.
>   (Laurentiu)
> * Call get/put() hooks directly to get/put DPU fetchunits for DPU plane groups.
>   (Laurentiu)
> * Shorten the names of individual DPU irq handlers by using DPU unit abbrev
>   names to make writing dpu_irq_handler[] easier.
> 
> v5->v6:
> * Do not use macros where possible. (Laurentiu)
> * Break dpu_plane_atomic_check() into some smaller functions. (Laurentiu)
> * Address some minor comments from Laurentiu.
> * Add dpu_crtc_err() helper marco to tell dmesg which CRTC generates error.
> * Drop calling dev_set_drvdata() from dpu_drm_bind/unbind() as it is done
>   in dpu_drm_probe().
> * Some trivial tweaks.
> 
> v4->v5:
> * Rebase up onto the latest drm-misc-next branch and remove the hook to
>   drm_atomic_helper_legacy_gamma_set(), because it was dropped by the newly
>   landed commit 'drm: automatic legacy gamma support'.
> * Remove a redundant blank line from dpu_plane_atomic_update().
> 
> v3->v4:
> * No change.
> 
> v2->v3:
> * Fix build warnings Reported-by: kernel test robot <lkp@intel.com>.
> * Drop build dependency on IMX_SCU, as dummy SCU functions have been added in
>   header files by the patch 'firmware: imx: add dummy functions' which has
>   landed in linux-next/master branch.
> 
> v1->v2:
> * Add compatible for i.MX8qm DPU, as this is tested with i.MX8qm LVDS displays.
>   (Laurentiu)
> * Fix PRG burst size and stride. (Laurentiu)
> * Put 'ports' OF node to fix the bail-out logic in dpu_drm_probe(). (Laurentiu)
> 
>  drivers/gpu/drm/imx/Kconfig               |    1 +
>  drivers/gpu/drm/imx/Makefile              |    1 +
>  drivers/gpu/drm/imx/dpu/Kconfig           |   10 +
>  drivers/gpu/drm/imx/dpu/Makefile          |   10 +
>  drivers/gpu/drm/imx/dpu/dpu-constframe.c  |  171 +++++
>  drivers/gpu/drm/imx/dpu/dpu-core.c        | 1054 +++++++++++++++++++++++++++++
>  drivers/gpu/drm/imx/dpu/dpu-crtc.c        |  967 ++++++++++++++++++++++++++
>  drivers/gpu/drm/imx/dpu/dpu-crtc.h        |   66 ++
>  drivers/gpu/drm/imx/dpu/dpu-disengcfg.c   |  117 ++++
>  drivers/gpu/drm/imx/dpu/dpu-dprc.c        |  722 ++++++++++++++++++++
>  drivers/gpu/drm/imx/dpu/dpu-dprc.h        |   40 ++
>  drivers/gpu/drm/imx/dpu/dpu-drv.c         |  292 ++++++++
>  drivers/gpu/drm/imx/dpu/dpu-drv.h         |   28 +
>  drivers/gpu/drm/imx/dpu/dpu-extdst.c      |  299 ++++++++
>  drivers/gpu/drm/imx/dpu/dpu-fetchdecode.c |  294 ++++++++
>  drivers/gpu/drm/imx/dpu/dpu-fetcheco.c    |  224 ++++++
>  drivers/gpu/drm/imx/dpu/dpu-fetchlayer.c  |  154 +++++
>  drivers/gpu/drm/imx/dpu/dpu-fetchunit.c   |  609 +++++++++++++++++
>  drivers/gpu/drm/imx/dpu/dpu-fetchunit.h   |  191 ++++++
>  drivers/gpu/drm/imx/dpu/dpu-fetchwarp.c   |  250 +++++++
>  drivers/gpu/drm/imx/dpu/dpu-framegen.c    |  395 +++++++++++
>  drivers/gpu/drm/imx/dpu/dpu-gammacor.c    |  223 ++++++
>  drivers/gpu/drm/imx/dpu/dpu-hscaler.c     |  275 ++++++++
>  drivers/gpu/drm/imx/dpu/dpu-kms.c         |  540 +++++++++++++++
>  drivers/gpu/drm/imx/dpu/dpu-kms.h         |   23 +
>  drivers/gpu/drm/imx/dpu/dpu-layerblend.c  |  348 ++++++++++
>  drivers/gpu/drm/imx/dpu/dpu-plane.c       |  802 ++++++++++++++++++++++
>  drivers/gpu/drm/imx/dpu/dpu-plane.h       |   56 ++
>  drivers/gpu/drm/imx/dpu/dpu-prg.c         |  433 ++++++++++++
>  drivers/gpu/drm/imx/dpu/dpu-prg.h         |   45 ++
>  drivers/gpu/drm/imx/dpu/dpu-prv.h         |  233 +++++++
>  drivers/gpu/drm/imx/dpu/dpu-tcon.c        |  250 +++++++
>  drivers/gpu/drm/imx/dpu/dpu-vscaler.c     |  308 +++++++++
>  drivers/gpu/drm/imx/dpu/dpu.h             |  385 +++++++++++
>  34 files changed, 9816 insertions(+)
>  create mode 100644 drivers/gpu/drm/imx/dpu/Kconfig
>  create mode 100644 drivers/gpu/drm/imx/dpu/Makefile
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-constframe.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-core.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-crtc.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-crtc.h
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-disengcfg.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-dprc.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-dprc.h
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-drv.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-drv.h
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-extdst.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchdecode.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetcheco.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchlayer.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchunit.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchunit.h
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchwarp.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-framegen.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-gammacor.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-hscaler.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-kms.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-kms.h
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-layerblend.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-plane.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-plane.h
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-prg.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-prg.h
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-prv.h
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-tcon.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-vscaler.c
>  create mode 100644 drivers/gpu/drm/imx/dpu/dpu.h
>

[...]

> diff --git a/drivers/gpu/drm/imx/dpu/dpu-plane.c b/drivers/gpu/drm/imx/dpu/dpu-plane.c
> new file mode 100644
> index 00000000..aaf0fe0
> --- /dev/null
> +++ b/drivers/gpu/drm/imx/dpu/dpu-plane.c
> @@ -0,0 +1,802 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright 2017-2020 NXP
> + */
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_color_mgmt.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_atomic_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include "dpu.h"
> +#include "dpu-crtc.h"
> +#include "dpu-dprc.h"
> +#include "dpu-plane.h"
> +
> +#define FRAC_16_16(mult, div)			(((mult) << 16) / (div))
> +
> +#define DPU_PLANE_MAX_PITCH			0x10000
> +#define DPU_PLANE_MAX_PIX_CNT			8192
> +#define DPU_PLANE_MAX_PIX_CNT_WITH_SCALER	2048
> +
> +static const uint32_t dpu_plane_formats[] = {
> +	DRM_FORMAT_ARGB8888,
> +	DRM_FORMAT_XRGB8888,
> +	DRM_FORMAT_ABGR8888,
> +	DRM_FORMAT_XBGR8888,
> +	DRM_FORMAT_RGBA8888,
> +	DRM_FORMAT_RGBX8888,
> +	DRM_FORMAT_BGRA8888,
> +	DRM_FORMAT_BGRX8888,
> +	DRM_FORMAT_RGB565,
> +
> +	DRM_FORMAT_YUYV,
> +	DRM_FORMAT_UYVY,
> +	DRM_FORMAT_NV12,
> +	DRM_FORMAT_NV21,
> +};
> +
> +static const uint64_t dpu_plane_format_modifiers[] = {
> +	DRM_FORMAT_MOD_VIVANTE_TILED,
> +	DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
> +	DRM_FORMAT_MOD_LINEAR,
> +	DRM_FORMAT_MOD_INVALID,
> +};
> +
> +static unsigned int dpu_plane_get_default_zpos(enum drm_plane_type type)
> +{
> +	if (type == DRM_PLANE_TYPE_PRIMARY)
> +		return 0;
> +	else if (type == DRM_PLANE_TYPE_OVERLAY)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static void dpu_plane_destroy(struct drm_plane *plane)
> +{
> +	struct dpu_plane *dpu_plane = to_dpu_plane(plane);
> +
> +	drm_plane_cleanup(plane);
> +	kfree(dpu_plane);
> +}
> +
> +static void dpu_plane_reset(struct drm_plane *plane)
> +{
> +	struct dpu_plane_state *state;
> +
> +	if (plane->state) {
> +		__drm_atomic_helper_plane_destroy_state(plane->state);
> +		kfree(to_dpu_plane_state(plane->state));
> +		plane->state = NULL;
> +	}
> +
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return;
> +
> +	__drm_atomic_helper_plane_reset(plane, &state->base);
> +
> +	plane->state->zpos = dpu_plane_get_default_zpos(plane->type);
> +	plane->state->color_encoding = DRM_COLOR_YCBCR_BT709;
> +	plane->state->color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
> +}
> +
> +static struct drm_plane_state *
> +dpu_drm_atomic_plane_duplicate_state(struct drm_plane *plane)
> +{
> +	struct dpu_plane_state *state, *copy;
> +
> +	if (WARN_ON(!plane->state))
> +		return NULL;
> +
> +	copy = kmalloc(sizeof(*state), GFP_KERNEL);
> +	if (!copy)
> +		return NULL;
> +
> +	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
> +	state = to_dpu_plane_state(plane->state);
> +	copy->stage = state->stage;
> +	copy->source = state->source;
> +	copy->blend = state->blend;
> +	copy->is_top = state->is_top;
> +
> +	return &copy->base;
> +}
> +
> +static void dpu_drm_atomic_plane_destroy_state(struct drm_plane *plane,
> +					       struct drm_plane_state *state)
> +{
> +	__drm_atomic_helper_plane_destroy_state(state);
> +	kfree(to_dpu_plane_state(state));
> +}
> +
> +static bool dpu_drm_plane_format_mod_supported(struct drm_plane *plane,
> +					       uint32_t format,
> +					       uint64_t modifier)
> +{
> +	switch (format) {
> +	case DRM_FORMAT_YUYV:
> +	case DRM_FORMAT_UYVY:
> +	case DRM_FORMAT_NV12:
> +	case DRM_FORMAT_NV21:
> +		return modifier == DRM_FORMAT_MOD_LINEAR;
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_XRGB8888:
> +	case DRM_FORMAT_ABGR8888:
> +	case DRM_FORMAT_XBGR8888:
> +	case DRM_FORMAT_RGBA8888:
> +	case DRM_FORMAT_RGBX8888:
> +	case DRM_FORMAT_BGRA8888:
> +	case DRM_FORMAT_BGRX8888:
> +	case DRM_FORMAT_RGB565:
> +		return modifier == DRM_FORMAT_MOD_LINEAR ||
> +		       modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
> +		       modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static const struct drm_plane_funcs dpu_plane_funcs = {
> +	.update_plane		= drm_atomic_helper_update_plane,
> +	.disable_plane		= drm_atomic_helper_disable_plane,
> +	.destroy		= dpu_plane_destroy,
> +	.reset			= dpu_plane_reset,
> +	.atomic_duplicate_state	= dpu_drm_atomic_plane_duplicate_state,
> +	.atomic_destroy_state	= dpu_drm_atomic_plane_destroy_state,
> +	.format_mod_supported	= dpu_drm_plane_format_mod_supported,
> +};
> +
> +static inline dma_addr_t
> +drm_plane_state_to_baseaddr(struct drm_plane_state *state)
> +{
> +	struct drm_framebuffer *fb = state->fb;
> +	struct drm_gem_cma_object *cma_obj;
> +	unsigned int x = state->src.x1 >> 16;
> +	unsigned int y = state->src.y1 >> 16;
> +
> +	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
> +
> +	if (fb->flags & DRM_MODE_FB_INTERLACED)
> +		y /= 2;
> +
> +	return cma_obj->paddr + fb->offsets[0] + fb->pitches[0] * y +
> +	       fb->format->cpp[0] * x;
> +}
> +
> +static inline dma_addr_t
> +drm_plane_state_to_uvbaseaddr(struct drm_plane_state *state)
> +{
> +	struct drm_framebuffer *fb = state->fb;
> +	struct drm_gem_cma_object *cma_obj;
> +	int x = state->src.x1 >> 16;
> +	int y = state->src.y1 >> 16;
> +
> +	cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
> +
> +	x /= fb->format->hsub;
> +	y /= fb->format->vsub;
> +
> +	if (fb->flags & DRM_MODE_FB_INTERLACED)
> +		y /= 2;
> +
> +	return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y +
> +	       fb->format->cpp[1] * x;
> +}
> +
> +static int dpu_plane_check_no_off_screen(struct drm_plane_state *state,
> +					 struct drm_crtc_state *crtc_state)
> +{
> +	if (state->dst.x1 < 0 || state->dst.y1 < 0 ||
> +	    (state->dst.x2 > crtc_state->adjusted_mode.hdisplay) ||
> +	    (state->dst.y2 > crtc_state->adjusted_mode.vdisplay)) {
> +		dpu_plane_dbg(state->plane, "no off screen\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dpu_plane_check_max_source_resolution(struct drm_plane_state *state)
> +{
> +	u32 src_w = drm_rect_width(&state->src) >> 16;
> +	u32 src_h = drm_rect_height(&state->src) >> 16;
> +	u32 dst_w = drm_rect_width(&state->dst);
> +	u32 dst_h = drm_rect_height(&state->dst);
> +
> +	if (src_w == dst_w || src_h == dst_h) {
> +		/* without scaling */
> +		if (src_w > DPU_PLANE_MAX_PIX_CNT ||
> +		    src_h > DPU_PLANE_MAX_PIX_CNT) {
> +			dpu_plane_dbg(state->plane,
> +				      "invalid source resolution\n");
> +			return -EINVAL;
> +		}
> +	} else {
> +		/* with scaling */
> +		if (src_w > DPU_PLANE_MAX_PIX_CNT_WITH_SCALER ||
> +		    src_h > DPU_PLANE_MAX_PIX_CNT_WITH_SCALER) {
> +			dpu_plane_dbg(state->plane,
> +				      "invalid source resolution with scale\n");
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int dpu_plane_check_source_alignment(struct drm_plane_state *state)
> +{
> +	struct drm_framebuffer *fb = state->fb;
> +	bool fb_is_interlaced = !!(fb->flags & DRM_MODE_FB_INTERLACED);
> +	u32 src_w = drm_rect_width(&state->src) >> 16;
> +	u32 src_h = drm_rect_height(&state->src) >> 16;
> +	u32 src_x = state->src.x1 >> 16;
> +	u32 src_y = state->src.y1 >> 16;
> +
> +	if (fb->format->hsub == 2) {
> +		if (src_w % 2) {
> +			dpu_plane_dbg(state->plane, "bad uv width\n");
> +			return -EINVAL;
> +		}
> +		if (src_x % 2) {
> +			dpu_plane_dbg(state->plane, "bad uv xoffset\n");
> +			return -EINVAL;
> +		}
> +	}
> +	if (fb->format->vsub == 2) {
> +		if (src_h % (fb_is_interlaced ? 4 : 2)) {
> +			dpu_plane_dbg(state->plane, "bad uv height\n");
> +			return -EINVAL;
> +		}
> +		if (src_y % (fb_is_interlaced ? 4 : 2)) {
> +			dpu_plane_dbg(state->plane, "bad uv yoffset\n");
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int dpu_plane_check_fb_modifier(struct drm_plane_state *state)
> +{
> +	struct drm_plane *plane = state->plane;
> +	struct drm_framebuffer *fb = state->fb;
> +
> +	if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
> +	    !plane->funcs->format_mod_supported(plane, fb->format->format,
> +						fb->modifier)) {
> +		dpu_plane_dbg(plane, "invalid modifier 0x%016llx",
> +								fb->modifier);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/* for tile formats, framebuffer has to be tile aligned */
> +static int dpu_plane_check_tiled_fb_alignment(struct drm_plane_state *state)
> +{
> +	struct drm_plane *plane = state->plane;
> +	struct drm_framebuffer *fb = state->fb;
> +
> +	switch (fb->modifier) {
> +	case DRM_FORMAT_MOD_VIVANTE_TILED:
> +		if (fb->width % 4) {
> +			dpu_plane_dbg(plane, "bad fb width for VIVANTE tile\n");
> +			return -EINVAL;
> +		}
> +		if (fb->height % 4) {
> +			dpu_plane_dbg(plane, "bad fb height for VIVANTE tile\n");
> +			return -EINVAL;
> +		}
> +		break;
> +	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
> +		if (fb->width % 64) {
> +			dpu_plane_dbg(plane,
> +				      "bad fb width for VIVANTE super tile\n");
> +			return -EINVAL;
> +		}
> +		if (fb->height % 64) {
> +			dpu_plane_dbg(plane,
> +				      "bad fb height for VIVANTE super tile\n");
> +			return -EINVAL;
> +		}
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dpu_plane_check_no_bt709_full_range(struct drm_plane_state *state)
> +{
> +	if (state->fb->format->is_yuv &&
> +	    state->color_encoding == DRM_COLOR_YCBCR_BT709 &&
> +	    state->color_range == DRM_COLOR_YCBCR_FULL_RANGE) {
> +		dpu_plane_dbg(state->plane, "no BT709 full range support\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dpu_plane_check_fb_plane_1(struct drm_plane_state *state)
> +{
> +	struct drm_plane *plane = state->plane;
> +	struct drm_framebuffer *fb = state->fb;
> +	dma_addr_t baseaddr = drm_plane_state_to_baseaddr(state);
> +	int bpp;
> +
> +	/* base address alignment */
> +	switch (fb->format->format) {
> +	case DRM_FORMAT_YUYV:
> +	case DRM_FORMAT_UYVY:
> +		bpp = 16;
> +		break;
> +	case DRM_FORMAT_NV12:
> +	case DRM_FORMAT_NV21:
> +		bpp = 8;
> +		break;
> +	default:
> +		bpp = fb->format->cpp[0] * 8;
> +		break;
> +	}
> +	if (((bpp == 32) && (baseaddr & 0x3)) ||
> +	    ((bpp == 16) && (baseaddr & 0x1))) {
> +		dpu_plane_dbg(plane, "%dbpp fb bad baddr alignment\n", bpp);
> +		return -EINVAL;
> +	}
> +	switch (bpp) {
> +	case 32:
> +		if (baseaddr & 0x3) {
> +			dpu_plane_dbg(plane, "32bpp fb bad baddr alignment\n");
> +			return -EINVAL;
> +		}
> +		break;
> +	case 16:
> +		if (fb->modifier) {
> +			if (baseaddr & 0x1) {
> +				dpu_plane_dbg(plane,
> +					"16bpp tile fb bad baddr alignment\n");
> +				return -EINVAL;
> +			}
> +		} else {
> +			if (baseaddr & 0x7) {
> +				dpu_plane_dbg(plane,
> +					"16bpp fb bad baddr alignment\n");
> +				return -EINVAL;
> +			}
> +		}
> +		break;
> +	}
> +
> +	/* pitches[0] range */
> +	if (fb->pitches[0] > DPU_PLANE_MAX_PITCH) {
> +		dpu_plane_dbg(plane, "fb pitches[0] is out of range\n");
> +		return -EINVAL;
> +	}
> +
> +	/* pitches[0] alignment */
> +	if (((bpp == 32) && (fb->pitches[0] & 0x3)) ||
> +	    ((bpp == 16) && (fb->pitches[0] & 0x1))) {
> +		dpu_plane_dbg(plane, "%dbpp fb bad pitches[0] alignment\n", bpp);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/* UV planar check, assuming 16bpp */
> +static int dpu_plane_check_fb_plane_2(struct drm_plane_state *state)
> +{
> +	struct drm_plane *plane = state->plane;
> +	struct drm_framebuffer *fb = state->fb;
> +	dma_addr_t uv_baseaddr = drm_plane_state_to_uvbaseaddr(state);
> +
> +	/* base address alignment */
> +	if (uv_baseaddr & 0x7) {
> +		dpu_plane_dbg(plane, "bad uv baddr alignment\n");
> +		return -EINVAL;
> +	}
> +
> +	/* pitches[1] range */
> +	if (fb->pitches[1] > DPU_PLANE_MAX_PITCH) {
> +		dpu_plane_dbg(plane, "fb pitches[1] is out of range\n");
> +		return -EINVAL;
> +	}
> +
> +	/* pitches[1] alignment */
> +	if (fb->pitches[1] & 0x1) {
> +		dpu_plane_dbg(plane, "fb bad pitches[1] alignment\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dpu_plane_check_dprc(struct drm_plane_state *state)
> +{
> +	struct dpu_plane_state *dpstate = to_dpu_plane_state(state);
> +	struct drm_framebuffer *fb = state->fb;
> +	const struct dpu_fetchunit_ops *fu_ops;
> +	struct dpu_dprc *dprc;
> +	dma_addr_t baseaddr, uv_baseaddr = 0;
> +	u32 src_w = drm_rect_width(&state->src) >> 16;
> +	u32 src_x = state->src.x1 >> 16;
> +
> +	fu_ops = dpu_fu_get_ops(dpstate->source);
> +	dprc = fu_ops->get_dprc(dpstate->source);
> +
> +	if (!dpu_dprc_rtram_width_supported(dprc, src_w)) {
> +		dpu_plane_dbg(state->plane, "bad RTRAM width for DPRC\n");
> +		return -EINVAL;
> +	}
> +
> +	baseaddr = drm_plane_state_to_baseaddr(state);
> +	if (fb->format->num_planes > 1)
> +		uv_baseaddr = drm_plane_state_to_uvbaseaddr(state);
> +
> +	if (!dpu_dprc_stride_supported(dprc, fb->pitches[0], fb->pitches[1],
> +				       src_w, src_x, fb->format, fb->modifier,
> +				       baseaddr, uv_baseaddr)) {
> +		dpu_plane_dbg(state->plane, "bad fb pitches for DPRC\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dpu_plane_atomic_check(struct drm_plane *plane,
> +				  struct drm_atomic_state *state)
> +{
> +	struct drm_plane_state *new_plane_state =
> +				drm_atomic_get_new_plane_state(state, plane);
> +	struct dpu_plane_state *new_dpstate =
> +				to_dpu_plane_state(new_plane_state);
> +	struct drm_framebuffer *fb = new_plane_state->fb;
> +	struct drm_crtc_state *crtc_state;
> +	int min_scale, ret;
> +
> +	/* ok to disable */
> +	if (!fb) {
> +		new_dpstate->source = NULL;
> +		new_dpstate->stage.ptr = NULL;
> +		new_dpstate->blend = NULL;
> +		return 0;
> +	}
> +
> +	if (!new_plane_state->crtc) {
> +		dpu_plane_dbg(plane, "no CRTC in plane state\n");
> +		return -EINVAL;
> +	}
> +
> +	crtc_state =
> +		drm_atomic_get_existing_crtc_state(state, new_plane_state->crtc);
> +	if (WARN_ON(!crtc_state))
> +		return -EINVAL;
> +
> +	min_scale = FRAC_16_16(1, DPU_PLANE_MAX_PIX_CNT_WITH_SCALER);
> +	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> +						  min_scale,
> +						  DRM_PLANE_HELPER_NO_SCALING,
> +						  true, false);
> +	if (ret) {
> +		dpu_plane_dbg(plane, "failed to check plane state: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = dpu_plane_check_no_off_screen(new_plane_state, crtc_state);
> +	if (ret)
> +		return ret;
> +
> +	ret = dpu_plane_check_max_source_resolution(new_plane_state);
> +	if (ret)
> +		return ret;
> +
> +	ret = dpu_plane_check_source_alignment(new_plane_state);
> +	if (ret)
> +		return ret;
> +
> +	ret = dpu_plane_check_fb_modifier(new_plane_state);
> +	if (ret)
> +		return ret;
> +
> +	ret = dpu_plane_check_tiled_fb_alignment(new_plane_state);
> +	if (ret)
> +		return ret;
> +
> +	ret = dpu_plane_check_no_bt709_full_range(new_plane_state);
> +	if (ret)
> +		return ret;
> +
> +	ret = dpu_plane_check_fb_plane_1(new_plane_state);
> +	if (ret)
> +		return ret;
> +
> +	if (fb->format->num_planes > 1) {
> +		ret = dpu_plane_check_fb_plane_2(new_plane_state);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return dpu_plane_check_dprc(new_plane_state);
> +}
> +
> +static void dpu_plane_atomic_update(struct drm_plane *plane,
> +				    struct drm_atomic_state *state)
> +{
> +	struct dpu_plane *dplane = to_dpu_plane(plane);
> +	struct drm_plane_state *new_state = plane->state;

I think you want to use the drm_atomic_get_new_plane_state() helper here as
well. See:

37418bf14c13 ("drm: Use state helper instead of the plane state pointer")

Thanks,
laurentiu

> +	struct dpu_plane_state *new_dpstate = to_dpu_plane_state(new_state);
> +	struct dpu_plane_grp *grp = dplane->grp;
> +	struct dpu_crtc *dpu_crtc;
> +	struct drm_framebuffer *fb = new_state->fb;
> +	struct dpu_fetchunit *fu = new_dpstate->source;
> +	struct dpu_layerblend *lb = new_dpstate->blend;
> +	struct dpu_dprc *dprc;
> +	const struct dpu_fetchunit_ops *fu_ops;
> +	dma_addr_t baseaddr, uv_baseaddr;
> +	enum dpu_link_id fu_link;
> +	enum dpu_link_id lb_src_link, stage_link;
> +	enum dpu_link_id vs_link;
> +	unsigned int src_w, src_h, src_x, src_y, dst_w, dst_h;
> +	unsigned int mt_w = 0, mt_h = 0;	/* micro-tile width/height */
> +	int bpp;
> +	bool prefetch_start = false;
> +	bool need_fetcheco = false, need_hscaler = false, need_vscaler = false;
> +	bool need_modeset;
> +	bool fb_is_interlaced;
> +
> +	/*
> +	 * Do nothing since the plane is disabled by
> +	 * crtc_func->atomic_begin/flush.
> +	 */
> +	if (!fb)
> +		return;
> +
> +	/* Do nothing if CRTC is inactive. */
> +	if (!new_state->crtc->state->active)
> +		return;
> +
> +	need_modeset = drm_atomic_crtc_needs_modeset(new_state->crtc->state);
> +
> +	fb_is_interlaced = !!(fb->flags & DRM_MODE_FB_INTERLACED);
> +
> +	src_w = drm_rect_width(&new_state->src) >> 16;
> +	src_h = drm_rect_height(&new_state->src) >> 16;
> +	src_x = new_state->src.x1 >> 16;
> +	src_y = new_state->src.y1 >> 16;
> +	dst_w = drm_rect_width(&new_state->dst);
> +	dst_h = drm_rect_height(&new_state->dst);
> +
> +	switch (fb->format->format) {
> +	case DRM_FORMAT_YUYV:
> +	case DRM_FORMAT_UYVY:
> +		bpp = 16;
> +		break;
> +	case DRM_FORMAT_NV12:
> +	case DRM_FORMAT_NV21:
> +		bpp = 8;
> +		break;
> +	default:
> +		bpp = fb->format->cpp[0] * 8;
> +		break;
> +	}
> +
> +	switch (fb->modifier) {
> +	case DRM_FORMAT_MOD_VIVANTE_TILED:
> +	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
> +		mt_w = (bpp == 16) ? 8 : 4;
> +		mt_h = 4;
> +		break;
> +	}
> +
> +	if (fb->format->num_planes > 1)
> +		need_fetcheco = true;
> +
> +	if (src_w != dst_w)
> +		need_hscaler = true;
> +
> +	if ((src_h != dst_h) || fb_is_interlaced)
> +		need_vscaler = true;
> +
> +	baseaddr = drm_plane_state_to_baseaddr(new_state);
> +	if (need_fetcheco)
> +		uv_baseaddr = drm_plane_state_to_uvbaseaddr(new_state);
> +
> +	dpu_crtc = to_dpu_crtc(new_state->crtc);
> +
> +	fu_ops = dpu_fu_get_ops(fu);
> +
> +	if (!fu_ops->has_stream_id(fu) || need_modeset)
> +		prefetch_start = true;
> +
> +	fu_ops->set_layerblend(fu, lb);
> +
> +	fu_ops->set_burstlength(fu, src_x, mt_w, bpp, baseaddr);
> +	fu_ops->set_src_stride(fu, src_w, src_w, mt_w, bpp, fb->pitches[0],
> +			       baseaddr);
> +	fu_ops->set_src_buf_dimensions(fu, src_w, src_h, fb->format,
> +				       fb_is_interlaced);
> +	fu_ops->set_fmt(fu, fb->format, new_state->color_encoding,
> +			new_state->color_range, fb_is_interlaced);
> +	fu_ops->set_pixel_blend_mode(fu, new_state->pixel_blend_mode,
> +				     new_state->alpha, fb->format->has_alpha);
> +	fu_ops->enable_src_buf(fu);
> +	fu_ops->set_framedimensions(fu, src_w, src_h, fb_is_interlaced);
> +	fu_ops->set_baseaddress(fu, src_w, src_x, src_y, mt_w, mt_h, bpp,
> +				baseaddr);
> +	fu_ops->set_stream_id(fu, dpu_crtc->stream_id);
> +
> +	fu_link = fu_ops->get_link_id(fu);
> +	lb_src_link = fu_link;
> +
> +	dpu_plane_dbg(plane, "uses %s\n", fu_ops->get_name(fu));
> +
> +	if (need_fetcheco) {
> +		struct dpu_fetchunit *fe = fu_ops->get_fetcheco(fu);
> +		const struct dpu_fetchunit_ops *fe_ops;
> +
> +		fe_ops = dpu_fu_get_ops(fe);
> +
> +		fu_ops->set_pec_dynamic_src_sel(fu, fe_ops->get_link_id(fe));
> +
> +		fe_ops->set_burstlength(fe, src_x, mt_w, bpp, uv_baseaddr);
> +		fe_ops->set_src_stride(fe, src_w, src_x, mt_w, bpp,
> +				       fb->pitches[1], uv_baseaddr);
> +		fe_ops->set_fmt(fe, fb->format, new_state->color_encoding,
> +				new_state->color_range, fb_is_interlaced);
> +		fe_ops->set_src_buf_dimensions(fe, src_w, src_h,
> +					       fb->format, fb_is_interlaced);
> +		fe_ops->set_framedimensions(fe, src_w, src_h, fb_is_interlaced);
> +		fe_ops->set_baseaddress(fe, src_w, src_x, src_y / 2,
> +					mt_w, mt_h, bpp, uv_baseaddr);
> +		fe_ops->enable_src_buf(fe);
> +
> +		dpu_plane_dbg(plane, "uses %s\n", fe_ops->get_name(fe));
> +	} else {
> +		if (fu_ops->set_pec_dynamic_src_sel)
> +			fu_ops->set_pec_dynamic_src_sel(fu, LINK_ID_NONE);
> +	}
> +
> +	/* VScaler comes first */
> +	if (need_vscaler) {
> +		struct dpu_vscaler *vs = fu_ops->get_vscaler(fu);
> +
> +		dpu_vs_pec_dynamic_src_sel(vs, fu_link);
> +		dpu_vs_pec_clken(vs, CLKEN_AUTOMATIC);
> +		dpu_vs_setup1(vs, src_h, new_state->crtc_h, fb_is_interlaced);
> +		dpu_vs_setup2(vs, fb_is_interlaced);
> +		dpu_vs_setup3(vs, fb_is_interlaced);
> +		dpu_vs_output_size(vs, dst_h);
> +		dpu_vs_field_mode(vs, fb_is_interlaced ?
> +						SCALER_ALWAYS0 : SCALER_INPUT);
> +		dpu_vs_filter_mode(vs, SCALER_LINEAR);
> +		dpu_vs_scale_mode(vs, SCALER_UPSCALE);
> +		dpu_vs_mode(vs, SCALER_ACTIVE);
> +
> +		vs_link = dpu_vs_get_link_id(vs);
> +		lb_src_link = vs_link;
> +
> +		dpu_plane_dbg(plane, "uses VScaler%u\n", dpu_vs_get_id(vs));
> +	}
> +
> +	/* and then, HScaler */
> +	if (need_hscaler) {
> +		struct dpu_hscaler *hs = fu_ops->get_hscaler(fu);
> +
> +		dpu_hs_pec_dynamic_src_sel(hs, need_vscaler ? vs_link : fu_link);
> +		dpu_hs_pec_clken(hs, CLKEN_AUTOMATIC);
> +		dpu_hs_setup1(hs, src_w, dst_w);
> +		dpu_hs_output_size(hs, dst_w);
> +		dpu_hs_filter_mode(hs, SCALER_LINEAR);
> +		dpu_hs_scale_mode(hs, SCALER_UPSCALE);
> +		dpu_hs_mode(hs, SCALER_ACTIVE);
> +
> +		lb_src_link = dpu_hs_get_link_id(hs);
> +
> +		dpu_plane_dbg(plane, "uses HScaler%u\n", dpu_hs_get_id(hs));
> +	}
> +
> +	dprc = fu_ops->get_dprc(fu);
> +
> +	dpu_dprc_configure(dprc, dpu_crtc->stream_id,
> +			   src_w, src_h, src_x, src_y,
> +			   fb->pitches[0], fb->format, fb->modifier,
> +			   baseaddr, uv_baseaddr,
> +			   prefetch_start, fb_is_interlaced);
> +
> +	if (new_state->normalized_zpos == 0)
> +		stage_link = dpu_cf_get_link_id(new_dpstate->stage.cf);
> +	else
> +		stage_link = dpu_lb_get_link_id(new_dpstate->stage.lb);
> +
> +	dpu_lb_pec_dynamic_prim_sel(lb, stage_link);
> +	dpu_lb_pec_dynamic_sec_sel(lb, lb_src_link);
> +	dpu_lb_mode(lb, LB_BLEND);
> +	dpu_lb_blendcontrol(lb, new_state->normalized_zpos,
> +			    new_state->pixel_blend_mode, new_state->alpha);
> +	dpu_lb_pec_clken(lb, CLKEN_AUTOMATIC);
> +	dpu_lb_position(lb, new_state->dst.x1, new_state->dst.y1);
> +
> +	dpu_plane_dbg(plane, "uses LayerBlend%u\n", dpu_lb_get_id(lb));
> +
> +	if (new_dpstate->is_top)
> +		dpu_ed_pec_src_sel(grp->ed[dpu_crtc->stream_id],
> +				   dpu_lb_get_link_id(lb));
> +}
> +
> +static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
> +	.prepare_fb	= drm_gem_plane_helper_prepare_fb,
> +	.atomic_check	= dpu_plane_atomic_check,
> +	.atomic_update	= dpu_plane_atomic_update,
> +};
> +
> +struct dpu_plane *dpu_plane_initialize(struct drm_device *drm,
> +				       unsigned int possible_crtcs,
> +				       struct dpu_plane_grp *grp,
> +				       enum drm_plane_type type)
> +{
> +	struct dpu_plane *dpu_plane;
> +	struct drm_plane *plane;
> +	unsigned int zpos = dpu_plane_get_default_zpos(type);
> +	int ret;
> +
> +	dpu_plane = kzalloc(sizeof(*dpu_plane), GFP_KERNEL);
> +	if (!dpu_plane)
> +		return ERR_PTR(-ENOMEM);
> +
> +	dpu_plane->grp = grp;
> +
> +	plane = &dpu_plane->base;
> +
> +	ret = drm_universal_plane_init(drm, plane, possible_crtcs,
> +				       &dpu_plane_funcs,
> +				       dpu_plane_formats,
> +				       ARRAY_SIZE(dpu_plane_formats),
> +				       dpu_plane_format_modifiers, type, NULL);
> +	if (ret) {
> +		/*
> +		 * The plane is not added to the global plane list, so
> +		 * free it manually.
> +		 */
> +		kfree(dpu_plane);
> +		return ERR_PTR(ret);
> +	}
> +
> +	drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
> +
> +	ret = drm_plane_create_zpos_property(plane,
> +					     zpos, 0, grp->hw_plane_cnt - 1);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	ret = drm_plane_create_alpha_property(plane);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	ret = drm_plane_create_blend_mode_property(plane,
> +					BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> +					BIT(DRM_MODE_BLEND_PREMULTI) |
> +					BIT(DRM_MODE_BLEND_COVERAGE));
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	ret = drm_plane_create_color_properties(plane,
> +					BIT(DRM_COLOR_YCBCR_BT601) |
> +					BIT(DRM_COLOR_YCBCR_BT709),
> +					BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
> +					BIT(DRM_COLOR_YCBCR_FULL_RANGE),
> +					DRM_COLOR_YCBCR_BT709,
> +					DRM_COLOR_YCBCR_LIMITED_RANGE);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return dpu_plane;
> +}
> diff --git a/drivers/gpu/drm/imx/dpu/dpu-plane.h b/drivers/gpu/drm/imx/dpu/dpu-plane.h
> new file mode 100644
> index 00000000..7bdd867
> --- /dev/null
> +++ b/drivers/gpu/drm/imx/dpu/dpu-plane.h
> @@ -0,0 +1,56 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +/*
> + * Copyright 2017-2020 NXP
> + */
> +
> +#ifndef __DPU_PLANE_H__
> +#define __DPU_PLANE_H__
> +
> +#include <linux/kernel.h>
> +
> +#include <drm/drm_device.h>
> +#include <drm/drm_plane.h>
> +#include <drm/drm_print.h>
> +
> +#include "dpu.h"
> +
> +#define dpu_plane_dbg(plane, fmt, ...)					\
> +	drm_dbg_kms((plane)->dev, "[PLANE:%d:%s] " fmt,			\
> +		    (plane)->base.id, (plane)->name, ##__VA_ARGS__)
> +
> +struct dpu_plane {
> +	struct drm_plane	base;
> +	struct dpu_plane_grp	*grp;
> +};
> +
> +union dpu_plane_stage {
> +	struct dpu_constframe	*cf;
> +	struct dpu_layerblend	*lb;
> +	void			*ptr;
> +};
> +
> +struct dpu_plane_state {
> +	struct drm_plane_state	base;
> +	union dpu_plane_stage	stage;
> +	struct dpu_fetchunit	*source;
> +	struct dpu_layerblend	*blend;
> +	bool			is_top;
> +};
> +
> +static inline struct dpu_plane *to_dpu_plane(struct drm_plane *plane)
> +{
> +	return container_of(plane, struct dpu_plane, base);
> +}
> +
> +static inline struct dpu_plane_state *
> +to_dpu_plane_state(struct drm_plane_state *plane_state)
> +{
> +	return container_of(plane_state, struct dpu_plane_state, base);
> +}
> +
> +struct dpu_plane *dpu_plane_initialize(struct drm_device *drm,
> +				       unsigned int possible_crtcs,
> +				       struct dpu_plane_grp *grp,
> +				       enum drm_plane_type type);
> +#endif /* __DPU_PLANE_H__ */
> diff --git a/drivers/gpu/drm/imx/dpu/dpu-prg.c b/drivers/gpu/drm/imx/dpu/dpu-prg.c
> new file mode 100644
> index 00000000..33a1a3e
> --- /dev/null
> +++ b/drivers/gpu/drm/imx/dpu/dpu-prg.c
> @@ -0,0 +1,433 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright 2017-2020 NXP
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +
> +#include "dpu-prg.h"
> +
> +#define SET			0x4
> +#define CLR			0x8
> +#define TOG			0xc
> +
> +#define PRG_CTRL		0x00
> +#define  BYPASS			BIT(0)
> +#define  SC_DATA_TYPE_8BIT	0
> +#define  SC_DATA_TYPE_10BIT	BIT(2)
> +#define  UV_EN			BIT(3)
> +#define  HANDSHAKE_MODE_4LINES	0
> +#define  HANDSHAKE_MODE_8LINES	BIT(4)
> +#define  SHADOW_LOAD_MODE	BIT(5)
> +#define  DES_DATA_TYPE_32BPP	(0 << 16)
> +#define  DES_DATA_TYPE_24BPP	(1 << 16)
> +#define  DES_DATA_TYPE_16BPP	(2 << 16)
> +#define  DES_DATA_TYPE_8BPP	(3 << 16)
> +#define  SOFTRST		BIT(30)
> +#define  SHADOW_EN		BIT(31)
> +
> +#define PRG_STATUS		0x10
> +#define  BUFFER_VALID_B		BIT(1)
> +#define  BUFFER_VALID_A		BIT(0)
> +
> +#define PRG_REG_UPDATE		0x20
> +#define  REG_UPDATE		BIT(0)
> +
> +#define PRG_STRIDE		0x30
> +#define  STRIDE(n)		(((n) - 1) & 0xffff)
> +
> +#define PRG_HEIGHT		0x40
> +#define  HEIGHT(n)		(((n) - 1) & 0xffff)
> +
> +#define PRG_BADDR		0x50
> +
> +#define PRG_OFFSET		0x60
> +#define  Y(n)			(((n) & 0x7) << 16)
> +#define  X(n)			((n) & 0xffff)
> +
> +#define PRG_WIDTH		0x70
> +#define  WIDTH(n)		(((n) - 1) & 0xffff)
> +
> +#define DPU_PRG_MAX_STRIDE	0x10000
> +
> +struct dpu_prg {
> +	struct device *dev;
> +	void __iomem *base;
> +	struct list_head list;
> +	struct clk *clk_apb;
> +	struct clk *clk_rtram;
> +	bool is_auxiliary;
> +};
> +
> +static DEFINE_MUTEX(dpu_prg_list_mutex);
> +static LIST_HEAD(dpu_prg_list);
> +
> +static inline u32 dpu_prg_read(struct dpu_prg *prg, unsigned int offset)
> +{
> +	return readl(prg->base + offset);
> +}
> +
> +static inline void
> +dpu_prg_write(struct dpu_prg *prg, unsigned int offset, u32 value)
> +{
> +	writel(value, prg->base + offset);
> +}
> +
> +static void dpu_prg_reset(struct dpu_prg *prg)
> +{
> +	usleep_range(10, 20);
> +	dpu_prg_write(prg, PRG_CTRL + SET, SOFTRST);
> +	usleep_range(10, 20);
> +	dpu_prg_write(prg, PRG_CTRL + CLR, SOFTRST);
> +}
> +
> +void dpu_prg_enable(struct dpu_prg *prg)
> +{
> +	dpu_prg_write(prg, PRG_CTRL + CLR, BYPASS);
> +}
> +
> +void dpu_prg_disable(struct dpu_prg *prg)
> +{
> +	dpu_prg_write(prg, PRG_CTRL, BYPASS);
> +}
> +
> +static int dpu_prg_mod_to_mt_w(struct dpu_prg *prg, u64 modifier,
> +			       unsigned int bits_per_pixel, unsigned int *mt_w)
> +{
> +	switch (modifier) {
> +	case DRM_FORMAT_MOD_NONE:
> +		*mt_w = 0;
> +		break;
> +	case DRM_FORMAT_MOD_VIVANTE_TILED:
> +	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
> +		*mt_w = (bits_per_pixel == 16) ? 8 : 4;
> +		break;
> +	default:
> +		dev_err(prg->dev, "unsupported modifier 0x%016llx\n", modifier);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dpu_prg_mod_to_mt_h(struct dpu_prg *prg, u64 modifier,
> +			       unsigned int *mt_h)
> +{
> +	switch (modifier) {
> +	case DRM_FORMAT_MOD_NONE:
> +		*mt_h = 0;
> +		break;
> +	case DRM_FORMAT_MOD_VIVANTE_TILED:
> +	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
> +		*mt_h = 4;
> +		break;
> +	default:
> +		dev_err(prg->dev, "unsupported modifier 0x%016llx\n", modifier);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/* address TKT343664: base address has to align to burst size */
> +static unsigned int dpu_prg_burst_size_fixup(dma_addr_t baddr)
> +{
> +	unsigned int burst_size;
> +
> +	burst_size = 1 << __ffs(baddr);
> +	burst_size = round_up(burst_size, 8);
> +	burst_size = min(burst_size, 128U);
> +
> +	return burst_size;
> +}
> +
> +/* address TKT339017: mismatch between burst size and stride */
> +static unsigned int dpu_prg_stride_fixup(unsigned int stride,
> +					 unsigned int burst_size,
> +					 dma_addr_t baddr, u64 modifier)
> +{
> +	if (modifier)
> +		stride = round_up(stride + round_up(baddr % 8, 8), burst_size);
> +	else
> +		stride = round_up(stride, burst_size);
> +
> +	return stride;
> +}
> +
> +void dpu_prg_configure(struct dpu_prg *prg,
> +		       unsigned int width, unsigned int height,
> +		       unsigned int x_offset, unsigned int y_offset,
> +		       unsigned int stride, unsigned int bits_per_pixel,
> +		       dma_addr_t baddr,
> +		       const struct drm_format_info *format, u64 modifier,
> +		       bool start)
> +{
> +	unsigned int mt_w, mt_h;	/* micro-tile width/height */
> +	unsigned int burst_size;
> +	dma_addr_t _baddr;
> +	u32 val;
> +	int ret;
> +
> +	ret = dpu_prg_mod_to_mt_w(prg, modifier, bits_per_pixel, &mt_w);
> +	ret |= dpu_prg_mod_to_mt_h(prg, modifier, &mt_h);
> +	if (ret)
> +		return;
> +
> +	if (modifier) {
> +		x_offset %= mt_w;
> +		y_offset %= mt_h;
> +
> +		/* consider x offset to calculate stride */
> +		_baddr = baddr + (x_offset * (bits_per_pixel / 8));
> +	} else {
> +		x_offset = 0;
> +		y_offset = 0;
> +		_baddr = baddr;
> +	}
> +
> +	burst_size = dpu_prg_burst_size_fixup(_baddr);
> +
> +	stride = dpu_prg_stride_fixup(stride, burst_size, _baddr, modifier);
> +
> +	/*
> +	 * address TKT342628(part 1):
> +	 * when prg stride is less or equals to burst size,
> +	 * the auxiliary prg height needs to be a half
> +	 */
> +	if (prg->is_auxiliary && stride <= burst_size) {
> +		height /= 2;
> +		if (modifier)
> +			y_offset /= 2;
> +	}
> +
> +	dpu_prg_write(prg, PRG_STRIDE, STRIDE(stride));
> +	dpu_prg_write(prg, PRG_WIDTH, WIDTH(width));
> +	dpu_prg_write(prg, PRG_HEIGHT, HEIGHT(height));
> +	dpu_prg_write(prg, PRG_OFFSET, X(x_offset) | Y(y_offset));
> +	dpu_prg_write(prg, PRG_BADDR, baddr);
> +
> +	val = SHADOW_LOAD_MODE | SC_DATA_TYPE_8BIT | BYPASS;
> +	if (format->format == DRM_FORMAT_NV21 ||
> +	    format->format == DRM_FORMAT_NV12) {
> +		val |= HANDSHAKE_MODE_8LINES;
> +		/*
> +		 * address TKT342628(part 2):
> +		 * when prg stride is less or equals to burst size,
> +		 * we disable UV_EN bit for the auxiliary prg
> +		 */
> +		if (prg->is_auxiliary && stride > burst_size)
> +			val |= UV_EN;
> +	} else {
> +		val |= HANDSHAKE_MODE_4LINES;
> +	}
> +	switch (bits_per_pixel) {
> +	case 32:
> +		val |= DES_DATA_TYPE_32BPP;
> +		break;
> +	case 24:
> +		val |= DES_DATA_TYPE_24BPP;
> +		break;
> +	case 16:
> +		val |= DES_DATA_TYPE_16BPP;
> +		break;
> +	case 8:
> +		val |= DES_DATA_TYPE_8BPP;
> +		break;
> +	}
> +	/* no shadow for the first frame */
> +	if (!start)
> +		val |= SHADOW_EN;
> +	dpu_prg_write(prg, PRG_CTRL, val);
> +}
> +
> +void dpu_prg_reg_update(struct dpu_prg *prg)
> +{
> +	dpu_prg_write(prg, PRG_REG_UPDATE, REG_UPDATE);
> +}
> +
> +void dpu_prg_shadow_enable(struct dpu_prg *prg)
> +{
> +	dpu_prg_write(prg, PRG_CTRL + SET, SHADOW_EN);
> +}
> +
> +bool dpu_prg_stride_supported(struct dpu_prg *prg,
> +			      unsigned int x_offset,
> +			      unsigned int bits_per_pixel, u64 modifier,
> +			      unsigned int stride, dma_addr_t baddr)
> +{
> +	unsigned int mt_w;	/* micro-tile width */
> +	unsigned int burst_size;
> +	int ret;
> +
> +	ret = dpu_prg_mod_to_mt_w(prg, modifier, bits_per_pixel, &mt_w);
> +	if (ret)
> +		return false;
> +
> +	if (modifier) {
> +		x_offset %= mt_w;
> +
> +		/* consider x offset to calculate stride */
> +		baddr += (x_offset * (bits_per_pixel / 8));
> +	}
> +
> +	burst_size = dpu_prg_burst_size_fixup(baddr);
> +
> +	stride = dpu_prg_stride_fixup(stride, burst_size, baddr, modifier);
> +
> +	if (stride > DPU_PRG_MAX_STRIDE)
> +		return false;
> +
> +	return true;
> +}
> +
> +void dpu_prg_set_auxiliary(struct dpu_prg *prg)
> +{
> +	prg->is_auxiliary = true;
> +}
> +
> +void dpu_prg_set_primary(struct dpu_prg *prg)
> +{
> +	prg->is_auxiliary = false;
> +}
> +
> +struct dpu_prg *
> +dpu_prg_lookup_by_phandle(struct device *dev, const char *name, int index)
> +{
> +	struct device_node *prg_node = of_parse_phandle(dev->of_node,
> +							name, index);
> +	struct dpu_prg *prg;
> +
> +	mutex_lock(&dpu_prg_list_mutex);
> +	list_for_each_entry(prg, &dpu_prg_list, list) {
> +		if (prg_node == prg->dev->of_node) {
> +			mutex_unlock(&dpu_prg_list_mutex);
> +			device_link_add(dev, prg->dev,
> +					DL_FLAG_PM_RUNTIME |
> +					DL_FLAG_AUTOREMOVE_CONSUMER);
> +			return prg;
> +		}
> +	}
> +	mutex_unlock(&dpu_prg_list_mutex);
> +
> +	return NULL;
> +}
> +
> +static const struct of_device_id dpu_prg_dt_ids[] = {
> +	{ .compatible = "fsl,imx8qm-prg", },
> +	{ .compatible = "fsl,imx8qxp-prg", },
> +	{ /* sentinel */ },
> +};
> +
> +static int dpu_prg_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct resource *res;
> +	struct dpu_prg *prg;
> +	int ret;
> +
> +	prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
> +	if (!prg)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	prg->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(prg->base))
> +		return PTR_ERR(prg->base);
> +
> +	prg->clk_apb = devm_clk_get(dev, "apb");
> +	if (IS_ERR(prg->clk_apb)) {
> +		ret = PTR_ERR(prg->clk_apb);
> +		dev_err_probe(dev, ret, "failed to get apb clock\n");
> +		return ret;
> +	}
> +
> +	prg->clk_rtram = devm_clk_get(dev, "rtram");
> +	if (IS_ERR(prg->clk_rtram)) {
> +		ret = PTR_ERR(prg->clk_rtram);
> +		dev_err_probe(dev, ret, "failed to get rtram clock\n");
> +		return ret;
> +	}
> +
> +	prg->dev = dev;
> +	platform_set_drvdata(pdev, prg);
> +
> +	pm_runtime_enable(dev);
> +
> +	mutex_lock(&dpu_prg_list_mutex);
> +	list_add(&prg->list, &dpu_prg_list);
> +	mutex_unlock(&dpu_prg_list_mutex);
> +
> +	return 0;
> +}
> +
> +static int dpu_prg_remove(struct platform_device *pdev)
> +{
> +	struct dpu_prg *prg = platform_get_drvdata(pdev);
> +
> +	mutex_lock(&dpu_prg_list_mutex);
> +	list_del(&prg->list);
> +	mutex_unlock(&dpu_prg_list_mutex);
> +
> +	pm_runtime_disable(&pdev->dev);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused dpu_prg_runtime_suspend(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct dpu_prg *prg = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(prg->clk_rtram);
> +	clk_disable_unprepare(prg->clk_apb);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused dpu_prg_runtime_resume(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct dpu_prg *prg = platform_get_drvdata(pdev);
> +	int ret;
> +
> +	ret = clk_prepare_enable(prg->clk_apb);
> +	if (ret) {
> +		dev_err(dev, "failed to enable apb clock: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(prg->clk_rtram);
> +	if (ret) {
> +		dev_err(dev, "failed to enable rtramclock: %d\n", ret);
> +		return ret;
> +	}
> +
> +	dpu_prg_reset(prg);
> +
> +	return ret;
> +}
> +
> +static const struct dev_pm_ops dpu_prg_pm_ops = {
> +	SET_RUNTIME_PM_OPS(dpu_prg_runtime_suspend,
> +			   dpu_prg_runtime_resume, NULL)
> +};
> +
> +struct platform_driver dpu_prg_driver = {
> +	.probe = dpu_prg_probe,
> +	.remove = dpu_prg_remove,
> +	.driver = {
> +		.pm = &dpu_prg_pm_ops,
> +		.name = "dpu-prg",
> +		.of_match_table = dpu_prg_dt_ids,
> +	},
> +};
> diff --git a/drivers/gpu/drm/imx/dpu/dpu-prg.h b/drivers/gpu/drm/imx/dpu/dpu-prg.h
> new file mode 100644
> index 00000000..550e350
> --- /dev/null
> +++ b/drivers/gpu/drm/imx/dpu/dpu-prg.h
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +/*
> + * Copyright 2017-2020 NXP
> + */
> +
> +#ifndef _DPU_PRG_H_
> +#define _DPU_PRG_H_
> +
> +#include <linux/device.h>
> +#include <linux/types.h>
> +
> +#include <drm/drm_fourcc.h>
> +
> +struct dpu_prg;
> +
> +void dpu_prg_enable(struct dpu_prg *prg);
> +
> +void dpu_prg_disable(struct dpu_prg *prg);
> +
> +void dpu_prg_configure(struct dpu_prg *prg,
> +		       unsigned int width, unsigned int height,
> +		       unsigned int x_offset, unsigned int y_offset,
> +		       unsigned int stride, unsigned int bits_per_pixel,
> +		       dma_addr_t baddr,
> +		       const struct drm_format_info *format, u64 modifier,
> +		       bool start);
> +
> +void dpu_prg_reg_update(struct dpu_prg *prg);
> +
> +void dpu_prg_shadow_enable(struct dpu_prg *prg);
> +
> +bool dpu_prg_stride_supported(struct dpu_prg *prg,
> +			      unsigned int x_offset,
> +			      unsigned int bits_per_pixel, u64 modifier,
> +			      unsigned int stride, dma_addr_t baddr);
> +
> +void dpu_prg_set_auxiliary(struct dpu_prg *prg);
> +
> +void dpu_prg_set_primary(struct dpu_prg *prg);
> +
> +struct dpu_prg *
> +dpu_prg_lookup_by_phandle(struct device *dev, const char *name, int index);
> +
> +#endif
> diff --git a/drivers/gpu/drm/imx/dpu/dpu-prv.h b/drivers/gpu/drm/imx/dpu/dpu-prv.h
> new file mode 100644
> index 00000000..8931af7
> --- /dev/null
> +++ b/drivers/gpu/drm/imx/dpu/dpu-prv.h
> @@ -0,0 +1,233 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + * Copyright 2017-2020 NXP
> + */
> +
> +#ifndef __DPU_PRV_H__
> +#define __DPU_PRV_H__
> +
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/irqdomain.h>
> +
> +#include "dpu.h"
> +
> +/* DPU common control registers */
> +#define DPU_COMCTRL_REG(offset)		(offset)
> +
> +#define IPIDENTIFIER			DPU_COMCTRL_REG(0x0)
> +#define LOCKUNLOCK			DPU_COMCTRL_REG(0x40)
> +#define LOCKSTATUS			DPU_COMCTRL_REG(0x44)
> +#define USERINTERRUPTMASK(n)		DPU_COMCTRL_REG(0x48 + 4 * (n))
> +#define INTERRUPTENABLE(n)		DPU_COMCTRL_REG(0x50 + 4 * (n))
> +#define INTERRUPTPRESET(n)		DPU_COMCTRL_REG(0x58 + 4 * (n))
> +#define INTERRUPTCLEAR(n)		DPU_COMCTRL_REG(0x60 + 4 * (n))
> +#define INTERRUPTSTATUS(n)		DPU_COMCTRL_REG(0x68 + 4 * (n))
> +#define USERINTERRUPTENABLE(n)		DPU_COMCTRL_REG(0x80 + 4 * (n))
> +#define USERINTERRUPTPRESET(n)		DPU_COMCTRL_REG(0x88 + 4 * (n))
> +#define USERINTERRUPTCLEAR(n)		DPU_COMCTRL_REG(0x90 + 4 * (n))
> +#define USERINTERRUPTSTATUS(n)		DPU_COMCTRL_REG(0x98 + 4 * (n))
> +#define GENERALPURPOSE			DPU_COMCTRL_REG(0x100)
> +
> +#define DPU_SAFETY_STREAM_OFFSET	4
> +
> +/* shadow enable bit for several DPU units */
> +#define SHDEN				BIT(0)
> +
> +/* Pixel Engine Configuration register fields */
> +#define CLKEN_MASK_SHIFT		24
> +#define CLKEN_MASK			(0x3 << CLKEN_MASK_SHIFT)
> +#define CLKEN(n)			((n) << CLKEN_MASK_SHIFT)
> +
> +/* H/Vscaler register fields */
> +#define SCALE_FACTOR_MASK		0xfffff
> +#define SCALE_FACTOR(n)			((n) & 0xfffff)
> +#define PHASE_OFFSET_MASK		0x1fffff
> +#define PHASE_OFFSET(n)			((n) & 0x1fffff)
> +#define OUTPUT_SIZE_MASK		0x3fff0000
> +#define OUTPUT_SIZE(n)			((((n) - 1) << 16) & OUTPUT_SIZE_MASK)
> +#define FILTER_MODE_MASK		0x100
> +#define FILTER_MODE(n)			((n) << 8)
> +#define SCALE_MODE_MASK			0x10
> +#define SCALE_MODE(n)			((n) << 4)
> +
> +enum dpu_irq {
> +	DPU_IRQ_STORE9_SHDLOAD		 = 0,
> +	DPU_IRQ_STORE9_FRAMECOMPLETE	 = 1,
> +	DPU_IRQ_STORE9_SEQCOMPLETE	 = 2,
> +	DPU_IRQ_EXTDST0_SHDLOAD		 = 3,
> +	DPU_IRQ_EXTDST0_FRAMECOMPLETE	 = 4,
> +	DPU_IRQ_EXTDST0_SEQCOMPLETE	 = 5,
> +	DPU_IRQ_EXTDST4_SHDLOAD		 = 6,
> +	DPU_IRQ_EXTDST4_FRAMECOMPLETE	 = 7,
> +	DPU_IRQ_EXTDST4_SEQCOMPLETE	 = 8,
> +	DPU_IRQ_EXTDST1_SHDLOAD		 = 9,
> +	DPU_IRQ_EXTDST1_FRAMECOMPLETE	 = 10,
> +	DPU_IRQ_EXTDST1_SEQCOMPLETE	 = 11,
> +	DPU_IRQ_EXTDST5_SHDLOAD		 = 12,
> +	DPU_IRQ_EXTDST5_FRAMECOMPLETE	 = 13,
> +	DPU_IRQ_EXTDST5_SEQCOMPLETE	 = 14,
> +	DPU_IRQ_DISENGCFG_SHDLOAD0	 = 15,
> +	DPU_IRQ_DISENGCFG_FRAMECOMPLETE0 = 16,
> +	DPU_IRQ_DISENGCFG_SEQCOMPLETE0	 = 17,
> +	DPU_IRQ_FRAMEGEN0_INT0		 = 18,
> +	DPU_IRQ_FRAMEGEN0_INT1		 = 19,
> +	DPU_IRQ_FRAMEGEN0_INT2		 = 20,
> +	DPU_IRQ_FRAMEGEN0_INT3		 = 21,
> +	DPU_IRQ_SIG0_SHDLOAD		 = 22,
> +	DPU_IRQ_SIG0_VALID		 = 23,
> +	DPU_IRQ_SIG0_ERROR		 = 24,
> +	DPU_IRQ_DISENGCFG_SHDLOAD1	 = 25,
> +	DPU_IRQ_DISENGCFG_FRAMECOMPLETE1 = 26,
> +	DPU_IRQ_DISENGCFG_SEQCOMPLETE1	 = 27,
> +	DPU_IRQ_FRAMEGEN1_INT0		 = 28,
> +	DPU_IRQ_FRAMEGEN1_INT1		 = 29,
> +	DPU_IRQ_FRAMEGEN1_INT2		 = 30,
> +	DPU_IRQ_FRAMEGEN1_INT3		 = 31,
> +	DPU_IRQ_SIG1_SHDLOAD		 = 32,
> +	DPU_IRQ_SIG1_VALID		 = 33,
> +	DPU_IRQ_SIG1_ERROR		 = 34,
> +	DPU_IRQ_RESERVED		 = 35,
> +	DPU_IRQ_CMDSEQ_ERROR		 = 36,
> +	DPU_IRQ_COMCTRL_SW0		 = 37,
> +	DPU_IRQ_COMCTRL_SW1		 = 38,
> +	DPU_IRQ_COMCTRL_SW2		 = 39,
> +	DPU_IRQ_COMCTRL_SW3		 = 40,
> +	DPU_IRQ_FRAMEGEN0_PRIMSYNC_ON	 = 41,
> +	DPU_IRQ_FRAMEGEN0_PRIMSYNC_OFF	 = 42,
> +	DPU_IRQ_FRAMEGEN0_SECSYNC_ON	 = 43,
> +	DPU_IRQ_FRAMEGEN0_SECSYNC_OFF	 = 44,
> +	DPU_IRQ_FRAMEGEN1_PRIMSYNC_ON	 = 45,
> +	DPU_IRQ_FRAMEGEN1_PRIMSYNC_OFF	 = 46,
> +	DPU_IRQ_FRAMEGEN1_SECSYNC_ON	 = 47,
> +	DPU_IRQ_FRAMEGEN1_SECSYNC_OFF	 = 48,
> +	DPU_IRQ_COUNT			 = 49,
> +};
> +
> +enum dpu_unit_type {
> +	DPU_DISP,
> +	DPU_BLIT,
> +};
> +
> +struct dpu_soc {
> +	struct device		*dev;
> +
> +	struct device		*pd_dc_dev;
> +	struct device		*pd_pll0_dev;
> +	struct device		*pd_pll1_dev;
> +	struct device_link	*pd_dc_link;
> +	struct device_link	*pd_pll0_link;
> +	struct device_link	*pd_pll1_link;
> +
> +	void __iomem		*comctrl_reg;
> +
> +	struct clk		*clk_cfg;
> +	struct clk		*clk_axi;
> +
> +	int			id;
> +
> +	int			irq[DPU_IRQ_COUNT];
> +
> +	struct irq_domain	*domain;
> +
> +	struct dpu_constframe	*cf_priv[4];
> +	struct dpu_disengcfg	*dec_priv[2];
> +	struct dpu_extdst	*ed_priv[4];
> +	struct dpu_fetchunit	*fd_priv[3];
> +	struct dpu_fetchunit	*fe_priv[4];
> +	struct dpu_framegen	*fg_priv[2];
> +	struct dpu_fetchunit	*fl_priv[1];
> +	struct dpu_fetchunit	*fw_priv[2];
> +	struct dpu_gammacor	*gc_priv[2];
> +	struct dpu_hscaler	*hs_priv[3];
> +	struct dpu_layerblend	*lb_priv[4];
> +	struct dpu_tcon		*tcon_priv[2];
> +	struct dpu_vscaler	*vs_priv[3];
> +};
> +
> +struct dpu_units {
> +	const unsigned int *ids;
> +	const enum dpu_unit_type *types;
> +	const unsigned long *ofss;
> +	const unsigned long *pec_ofss;	/* Pixel Engine Configuration */
> +	const unsigned int cnt;
> +	const char *name;
> +
> +	/* software initialization */
> +	int (*init)(struct dpu_soc *dpu, unsigned int index,
> +		    unsigned int id, enum dpu_unit_type type,
> +		    unsigned long pec_base, unsigned long base);
> +
> +	/* hardware initialization */
> +	void (*hw_init)(struct dpu_soc *dpu, unsigned int index);
> +};
> +
> +void dpu_cf_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_dec_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_ed_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_fd_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_fe_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_fg_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_fl_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_fw_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_gc_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_hs_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_lb_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_tcon_hw_init(struct dpu_soc *dpu, unsigned int index);
> +void dpu_vs_hw_init(struct dpu_soc *dpu, unsigned int index);
> +
> +int dpu_cf_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long pec_base, unsigned long base);
> +
> +int dpu_dec_init(struct dpu_soc *dpu, unsigned int index,
> +		 unsigned int id, enum dpu_unit_type type,
> +		 unsigned long unused, unsigned long base);
> +
> +int dpu_ed_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long pec_base, unsigned long base);
> +
> +int dpu_fd_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long pec_base, unsigned long base);
> +
> +int dpu_fe_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long pec_base, unsigned long base);
> +
> +int dpu_fg_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long unused, unsigned long base);
> +
> +int dpu_fl_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long pec_base, unsigned long base);
> +
> +int dpu_fw_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long pec_base, unsigned long base);
> +
> +int dpu_gc_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long unused, unsigned long base);
> +
> +int dpu_hs_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long pec_base, unsigned long base);
> +
> +int dpu_lb_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long pec_base, unsigned long base);
> +
> +int dpu_tcon_init(struct dpu_soc *dpu, unsigned int index,
> +		  unsigned int id, enum dpu_unit_type type,
> +		  unsigned long unused, unsigned long base);
> +
> +int dpu_vs_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long pec_base, unsigned long base);
> +
> +#endif /* __DPU_PRV_H__ */
> diff --git a/drivers/gpu/drm/imx/dpu/dpu-tcon.c b/drivers/gpu/drm/imx/dpu/dpu-tcon.c
> new file mode 100644
> index 00000000..143f51f
> --- /dev/null
> +++ b/drivers/gpu/drm/imx/dpu/dpu-tcon.c
> @@ -0,0 +1,250 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + * Copyright 2017-2020 NXP
> + */
> +
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mutex.h>
> +#include <linux/sizes.h>
> +
> +#include "dpu.h"
> +#include "dpu-prv.h"
> +
> +#define SSQCNTS			0x0
> +#define SSQCYCLE		0x408
> +#define SWRESET			0x40c
> +
> +#define TCON_CTRL		0x410
> +#define  CTRL_RST_VAL		0x01401408
> +#define  BYPASS			BIT(3)
> +
> +#define RSDSINVCTRL		0x414
> +
> +/* red: MAPBIT 29-20, green: MAPBIT 19-10, blue: MAPBIT 9-0 */
> +#define MAPBIT3_0		0x418
> +#define MAPBIT7_4		0x41c
> +#define MAPBIT11_8		0x420
> +#define MAPBIT15_12		0x424
> +#define MAPBIT19_16		0x428
> +#define MAPBIT23_20		0x42c
> +#define MAPBIT27_24		0x430
> +#define MAPBIT31_28		0x434
> +#define MAPBIT34_32		0x438
> +#define MAPBIT3_0_DUAL		0x43c
> +#define MAPBIT7_4_DUAL		0x440
> +#define MAPBIT11_8_DUAL		0x444
> +#define MAPBIT15_12_DUAL	0x448
> +#define MAPBIT19_16_DUAL	0x44c
> +#define MAPBIT23_20_DUAL	0x450
> +#define MAPBIT27_24_DUAL	0x454
> +#define MAPBIT31_28_DUAL	0x458
> +#define MAPBIT34_32_DUAL	0x45c
> +
> +#define SPGPOSON(n)		(0x460 + (n) * 16)
> +#define SPGMASKON(n)		(0x464 + (n) * 16)
> +#define SPGPOSOFF(n)		(0x468 + (n) * 16)
> +#define SPGMASKOFF(n)		(0x46c + (n) * 16)
> +#define  X(n)			(((n) & 0x7fff) << 16)
> +#define  Y(n)			((n) & 0x7fff)
> +
> +#define SMXSIGS(n)		(0x520 + (n) * 8)
> +#define SMXFCTTABLE(n)		(0x524 + (n) * 8)
> +#define RESET_OVER_UNFERFLOW	0x580
> +#define DUAL_DEBUG		0x584
> +
> +struct dpu_tcon {
> +	void __iomem *base;
> +	struct mutex mutex;
> +	unsigned int id;
> +	unsigned int index;
> +	bool inuse;
> +	struct dpu_soc *dpu;
> +};
> +
> +static inline u32 dpu_tcon_read(struct dpu_tcon *tcon, unsigned int offset)
> +{
> +	return readl(tcon->base + offset);
> +}
> +
> +static inline void dpu_tcon_write(struct dpu_tcon *tcon,
> +				  unsigned int offset, u32 value)
> +{
> +	writel(value, tcon->base + offset);
> +}
> +
> +static inline void dpu_tcon_write_mask(struct dpu_tcon *tcon,
> +				       unsigned int offset, u32 mask, u32 value)
> +{
> +	u32 tmp;
> +
> +	tmp = dpu_tcon_read(tcon, offset);
> +	tmp &= ~mask;
> +	dpu_tcon_write(tcon, offset, tmp | value);
> +}
> +
> +void dpu_tcon_set_fmt(struct dpu_tcon *tcon)
> +{
> +	/*
> +	 * The pixels reach TCON are always in 30-bit BGR format.
> +	 * The first bridge always receives pixels in 30-bit RGB format.
> +	 * So, map the format to MEDIA_BUS_FMT_RGB101010_1X30.
> +	 */
> +	dpu_tcon_write(tcon, MAPBIT3_0,   0x17161514);
> +	dpu_tcon_write(tcon, MAPBIT7_4,   0x1b1a1918);
> +	dpu_tcon_write(tcon, MAPBIT11_8,  0x0b0a1d1c);
> +	dpu_tcon_write(tcon, MAPBIT15_12, 0x0f0e0d0c);
> +	dpu_tcon_write(tcon, MAPBIT19_16, 0x13121110);
> +	dpu_tcon_write(tcon, MAPBIT23_20, 0x03020100);
> +	dpu_tcon_write(tcon, MAPBIT27_24, 0x07060504);
> +	dpu_tcon_write(tcon, MAPBIT31_28, 0x00000908);
> +}
> +
> +void dpu_tcon_set_operation_mode(struct dpu_tcon *tcon)
> +{
> +	dpu_tcon_write_mask(tcon, TCON_CTRL, BYPASS, 0);
> +}
> +
> +void dpu_tcon_cfg_videomode(struct dpu_tcon *tcon, struct drm_display_mode *m)
> +{
> +	int hdisplay, hsync_start, hsync_end;
> +	int vdisplay, vsync_start, vsync_end;
> +	int y;
> +
> +	hdisplay = m->hdisplay;
> +	vdisplay = m->vdisplay;
> +	hsync_start = m->hsync_start;
> +	vsync_start = m->vsync_start;
> +	hsync_end = m->hsync_end;
> +	vsync_end = m->vsync_end;
> +
> +	/*
> +	 * TKT320590:
> +	 * Turn TCON into operation mode later after the first dumb frame is
> +	 * generated by DPU.  This makes DPR/PRG be able to evade the frame.
> +	 */
> +	dpu_tcon_write_mask(tcon, TCON_CTRL, BYPASS, BYPASS);
> +
> +	/* dsp_control[0]: hsync */
> +	dpu_tcon_write(tcon, SPGPOSON(0), X(hsync_start));
> +	dpu_tcon_write(tcon, SPGMASKON(0), 0xffff);
> +
> +	dpu_tcon_write(tcon, SPGPOSOFF(0), X(hsync_end));
> +	dpu_tcon_write(tcon, SPGMASKOFF(0), 0xffff);
> +
> +	dpu_tcon_write(tcon, SMXSIGS(0), 0x2);
> +	dpu_tcon_write(tcon, SMXFCTTABLE(0), 0x1);
> +
> +	/* dsp_control[1]: vsync */
> +	dpu_tcon_write(tcon, SPGPOSON(1), X(hsync_start) | Y(vsync_start - 1));
> +	dpu_tcon_write(tcon, SPGMASKON(1), 0x0);
> +
> +	dpu_tcon_write(tcon, SPGPOSOFF(1), X(hsync_start) | Y(vsync_end - 1));
> +	dpu_tcon_write(tcon, SPGMASKOFF(1), 0x0);
> +
> +	dpu_tcon_write(tcon, SMXSIGS(1), 0x3);
> +	dpu_tcon_write(tcon, SMXFCTTABLE(1), 0x1);
> +
> +	/* dsp_control[2]: data enable */
> +	/* horizontal */
> +	dpu_tcon_write(tcon, SPGPOSON(2), 0x0);
> +	dpu_tcon_write(tcon, SPGMASKON(2), 0xffff);
> +
> +	dpu_tcon_write(tcon, SPGPOSOFF(2), X(hdisplay));
> +	dpu_tcon_write(tcon, SPGMASKOFF(2), 0xffff);
> +
> +	/* vertical */
> +	dpu_tcon_write(tcon, SPGPOSON(3), 0x0);
> +	dpu_tcon_write(tcon, SPGMASKON(3), 0x7fff0000);
> +
> +	dpu_tcon_write(tcon, SPGPOSOFF(3), Y(vdisplay));
> +	dpu_tcon_write(tcon, SPGMASKOFF(3), 0x7fff0000);
> +
> +	dpu_tcon_write(tcon, SMXSIGS(2), 0x2c);
> +	dpu_tcon_write(tcon, SMXFCTTABLE(2), 0x8);
> +
> +	/* dsp_control[3]: kachuck */
> +	y = vdisplay + 1;
> +
> +	dpu_tcon_write(tcon, SPGPOSON(4), X(0x0) | Y(y));
> +	dpu_tcon_write(tcon, SPGMASKON(4), 0x0);
> +
> +	dpu_tcon_write(tcon, SPGPOSOFF(4), X(0x20) | Y(y));
> +	dpu_tcon_write(tcon, SPGMASKOFF(4), 0x0);
> +
> +	dpu_tcon_write(tcon, SMXSIGS(3), 0x6);
> +	dpu_tcon_write(tcon, SMXFCTTABLE(3), 0x2);
> +}
> +
> +struct dpu_tcon *dpu_tcon_get(struct dpu_soc *dpu, unsigned int id)
> +{
> +	struct dpu_tcon *tcon;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(dpu->tcon_priv); i++) {
> +		tcon = dpu->tcon_priv[i];
> +		if (tcon->id == id)
> +			break;
> +	}
> +
> +	if (i == ARRAY_SIZE(dpu->tcon_priv))
> +		return ERR_PTR(-EINVAL);
> +
> +	mutex_lock(&tcon->mutex);
> +
> +	if (tcon->inuse) {
> +		mutex_unlock(&tcon->mutex);
> +		return ERR_PTR(-EBUSY);
> +	}
> +
> +	tcon->inuse = true;
> +
> +	mutex_unlock(&tcon->mutex);
> +
> +	return tcon;
> +}
> +
> +void dpu_tcon_put(struct dpu_tcon *tcon)
> +{
> +	if (IS_ERR_OR_NULL(tcon))
> +		return;
> +
> +	mutex_lock(&tcon->mutex);
> +
> +	tcon->inuse = false;
> +
> +	mutex_unlock(&tcon->mutex);
> +}
> +
> +void dpu_tcon_hw_init(struct dpu_soc *dpu, unsigned int index)
> +{
> +	/* reset TCON_CTRL to POR default so that TCON works in bypass mode */
> +	dpu_tcon_write(dpu->tcon_priv[index], TCON_CTRL, CTRL_RST_VAL);
> +}
> +
> +int dpu_tcon_init(struct dpu_soc *dpu, unsigned int index,
> +		  unsigned int id, enum dpu_unit_type type,
> +		  unsigned long unused, unsigned long base)
> +{
> +	struct dpu_tcon *tcon;
> +
> +	tcon = devm_kzalloc(dpu->dev, sizeof(*tcon), GFP_KERNEL);
> +	if (!tcon)
> +		return -ENOMEM;
> +
> +	dpu->tcon_priv[index] = tcon;
> +
> +	tcon->base = devm_ioremap(dpu->dev, base, SZ_2K);
> +	if (!tcon->base)
> +		return -ENOMEM;
> +
> +	tcon->dpu = dpu;
> +	tcon->id = id;
> +	tcon->index = index;
> +
> +	mutex_init(&tcon->mutex);
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/imx/dpu/dpu-vscaler.c b/drivers/gpu/drm/imx/dpu/dpu-vscaler.c
> new file mode 100644
> index 00000000..bdef0cd
> --- /dev/null
> +++ b/drivers/gpu/drm/imx/dpu/dpu-vscaler.c
> @@ -0,0 +1,308 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright 2017-2020 NXP
> + */
> +
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mutex.h>
> +#include <linux/sizes.h>
> +
> +#include "dpu.h"
> +#include "dpu-prv.h"
> +
> +#define PIXENGCFG_DYNAMIC		0x8
> +#define  PIXENGCFG_DYNAMIC_SRC_SEL_MASK	0x3f
> +
> +#define STATICCONTROL			0x8
> +
> +#define SETUP(n)			(0xc + ((n) - 1) * 0x4)
> +
> +#define CONTROL				0x20
> +#define  FIELD_MODE_MASK		0x3000
> +#define  FIELD_MODE(n)			((n) << 12)
> +#define  CTRL_MODE_MASK			BIT(0)
> +
> +struct dpu_vscaler {
> +	void __iomem *pec_base;
> +	void __iomem *base;
> +	struct mutex mutex;
> +	unsigned int id;
> +	unsigned int index;
> +	enum dpu_link_id link_id;
> +	bool inuse;
> +	struct dpu_soc *dpu;
> +};
> +
> +static const enum dpu_link_id dpu_vs_link_id[] = {
> +	LINK_ID_VSCALER4, LINK_ID_VSCALER5, LINK_ID_VSCALER9
> +};
> +
> +static const enum dpu_link_id src_sels[3][4] = {
> +	{
> +		LINK_ID_NONE,
> +		LINK_ID_FETCHDECODE0,
> +		LINK_ID_MATRIX4,
> +		LINK_ID_HSCALER4,
> +	}, {
> +		LINK_ID_NONE,
> +		LINK_ID_FETCHDECODE1,
> +		LINK_ID_MATRIX5,
> +		LINK_ID_HSCALER5,
> +	}, {
> +		LINK_ID_NONE,
> +		LINK_ID_MATRIX9,
> +		LINK_ID_HSCALER9,
> +	},
> +};
> +
> +static inline u32 dpu_pec_vs_read(struct dpu_vscaler *vs,
> +				  unsigned int offset)
> +{
> +	return readl(vs->pec_base + offset);
> +}
> +
> +static inline void dpu_pec_vs_write(struct dpu_vscaler *vs,
> +				    unsigned int offset, u32 value)
> +{
> +	writel(value, vs->pec_base + offset);
> +}
> +
> +static inline void dpu_pec_vs_write_mask(struct dpu_vscaler *vs,
> +					 unsigned int offset,
> +					 u32 mask, u32 value)
> +{
> +	u32 tmp;
> +
> +	tmp = dpu_pec_vs_read(vs, offset);
> +	tmp &= ~mask;
> +	dpu_pec_vs_write(vs, offset, tmp | value);
> +}
> +
> +static inline u32 dpu_vs_read(struct dpu_vscaler *vs, unsigned int offset)
> +{
> +	return readl(vs->base + offset);
> +}
> +
> +static inline void dpu_vs_write(struct dpu_vscaler *vs,
> +				unsigned int offset, u32 value)
> +{
> +	writel(value, vs->base + offset);
> +}
> +
> +static inline void dpu_vs_write_mask(struct dpu_vscaler *vs,
> +				     unsigned int offset, u32 mask, u32 value)
> +{
> +	u32 tmp;
> +
> +	tmp = dpu_vs_read(vs, offset);
> +	tmp &= ~mask;
> +	dpu_vs_write(vs, offset, tmp | value);
> +}
> +
> +enum dpu_link_id dpu_vs_get_link_id(struct dpu_vscaler *vs)
> +{
> +	return vs->link_id;
> +}
> +
> +void dpu_vs_pec_dynamic_src_sel(struct dpu_vscaler *vs, enum dpu_link_id src)
> +{
> +	struct dpu_soc *dpu = vs->dpu;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(src_sels[vs->index]); i++) {
> +		if (src_sels[vs->index][i] == src) {
> +			dpu_pec_vs_write_mask(vs, PIXENGCFG_DYNAMIC,
> +					      PIXENGCFG_DYNAMIC_SRC_SEL_MASK,
> +					      src);
> +			return;
> +		}
> +	}
> +
> +	dev_err(dpu->dev, "VScaler%u - invalid source 0x%02x\n", vs->id, src);
> +}
> +
> +void dpu_vs_pec_clken(struct dpu_vscaler *vs, enum dpu_pec_clken clken)
> +{
> +	dpu_pec_vs_write_mask(vs, PIXENGCFG_DYNAMIC, CLKEN_MASK, CLKEN(clken));
> +}
> +
> +static void dpu_vs_enable_shden(struct dpu_vscaler *vs)
> +{
> +	dpu_vs_write_mask(vs, STATICCONTROL, SHDEN, SHDEN);
> +}
> +
> +void dpu_vs_setup1(struct dpu_vscaler *vs,
> +		   unsigned int src_w, unsigned int dst_w, bool deinterlace)
> +{
> +	struct dpu_soc *dpu = vs->dpu;
> +	u32 scale_factor;
> +	u64 tmp64;
> +
> +	if (deinterlace)
> +		dst_w *= 2;
> +
> +	if (src_w == dst_w) {
> +		scale_factor = 0x80000;
> +	} else {
> +		if (src_w > dst_w) {
> +			tmp64 = (u64)((u64)dst_w * 0x80000);
> +			do_div(tmp64, src_w);
> +
> +		} else {
> +			tmp64 = (u64)((u64)src_w * 0x80000);
> +			do_div(tmp64, dst_w);
> +		}
> +		scale_factor = (u32)tmp64;
> +	}
> +
> +	if (scale_factor > 0x80000) {
> +		dev_err(dpu->dev, "VScaler%u - invalid scale factor 0x%08x\n",
> +							vs->id, scale_factor);
> +		return;
> +	}
> +
> +	dpu_vs_write(vs, SETUP(1), SCALE_FACTOR(scale_factor));
> +
> +	dev_dbg(dpu->dev, "VScaler%u - scale factor 0x%08x\n",
> +							vs->id, scale_factor);
> +}
> +
> +void dpu_vs_setup2(struct dpu_vscaler *vs, bool deinterlace)
> +{
> +	/* 0x20000: +0.25 phase offset for deinterlace */
> +	u32 phase_offset = deinterlace ? 0x20000 : 0;
> +
> +	dpu_vs_write(vs, SETUP(2), PHASE_OFFSET(phase_offset));
> +}
> +
> +void dpu_vs_setup3(struct dpu_vscaler *vs, bool deinterlace)
> +{
> +	/* 0x1e0000: -0.25 phase offset for deinterlace */
> +	u32 phase_offset = deinterlace ? 0x1e0000 : 0;
> +
> +	dpu_vs_write(vs, SETUP(3), PHASE_OFFSET(phase_offset));
> +}
> +
> +void dpu_vs_setup4(struct dpu_vscaler *vs, u32 phase_offset)
> +{
> +	dpu_vs_write(vs, SETUP(4), PHASE_OFFSET(phase_offset));
> +}
> +
> +void dpu_vs_setup5(struct dpu_vscaler *vs, u32 phase_offset)
> +{
> +	dpu_vs_write(vs, SETUP(5), PHASE_OFFSET(phase_offset));
> +}
> +
> +void dpu_vs_output_size(struct dpu_vscaler *vs, u32 line_num)
> +{
> +	dpu_vs_write_mask(vs, CONTROL, OUTPUT_SIZE_MASK, OUTPUT_SIZE(line_num));
> +}
> +
> +void dpu_vs_field_mode(struct dpu_vscaler *vs, enum dpu_scaler_field_mode m)
> +{
> +	dpu_vs_write_mask(vs, CONTROL, FIELD_MODE_MASK, FIELD_MODE(m));
> +}
> +
> +void dpu_vs_filter_mode(struct dpu_vscaler *vs, enum dpu_scaler_filter_mode m)
> +{
> +	dpu_vs_write_mask(vs, CONTROL, FILTER_MODE_MASK, FILTER_MODE(m));
> +}
> +
> +void dpu_vs_scale_mode(struct dpu_vscaler *vs, enum dpu_scaler_scale_mode m)
> +{
> +	dpu_vs_write_mask(vs, CONTROL, SCALE_MODE_MASK, SCALE_MODE(m));
> +}
> +
> +void dpu_vs_mode(struct dpu_vscaler *vs, enum dpu_scaler_mode m)
> +{
> +	dpu_vs_write_mask(vs, CONTROL, CTRL_MODE_MASK, m);
> +}
> +
> +unsigned int dpu_vs_get_id(struct dpu_vscaler *vs)
> +{
> +	return vs->id;
> +}
> +
> +struct dpu_vscaler *dpu_vs_get(struct dpu_soc *dpu, unsigned int id)
> +{
> +	struct dpu_vscaler *vs;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(dpu->vs_priv); i++) {
> +		vs = dpu->vs_priv[i];
> +		if (vs->id == id)
> +			break;
> +	}
> +
> +	if (i == ARRAY_SIZE(dpu->vs_priv))
> +		return ERR_PTR(-EINVAL);
> +
> +	mutex_lock(&vs->mutex);
> +
> +	if (vs->inuse) {
> +		mutex_unlock(&vs->mutex);
> +		return ERR_PTR(-EBUSY);
> +	}
> +
> +	vs->inuse = true;
> +
> +	mutex_unlock(&vs->mutex);
> +
> +	return vs;
> +}
> +
> +void dpu_vs_put(struct dpu_vscaler *vs)
> +{
> +	if (IS_ERR_OR_NULL(vs))
> +		return;
> +
> +	mutex_lock(&vs->mutex);
> +
> +	vs->inuse = false;
> +
> +	mutex_unlock(&vs->mutex);
> +}
> +
> +void dpu_vs_hw_init(struct dpu_soc *dpu, unsigned int index)
> +{
> +	struct dpu_vscaler *vs = dpu->vs_priv[index];
> +
> +	dpu_vs_enable_shden(vs);
> +	dpu_vs_setup2(vs, false);
> +	dpu_vs_setup3(vs, false);
> +	dpu_vs_setup4(vs, 0);
> +	dpu_vs_setup5(vs, 0);
> +	dpu_vs_pec_dynamic_src_sel(vs, LINK_ID_NONE);
> +}
> +
> +int dpu_vs_init(struct dpu_soc *dpu, unsigned int index,
> +		unsigned int id, enum dpu_unit_type type,
> +		unsigned long pec_base, unsigned long base)
> +{
> +	struct dpu_vscaler *vs;
> +
> +	vs = devm_kzalloc(dpu->dev, sizeof(*vs), GFP_KERNEL);
> +	if (!vs)
> +		return -ENOMEM;
> +
> +	dpu->vs_priv[index] = vs;
> +
> +	vs->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
> +	if (!vs->pec_base)
> +		return -ENOMEM;
> +
> +	vs->base = devm_ioremap(dpu->dev, base, SZ_32);
> +	if (!vs->base)
> +		return -ENOMEM;
> +
> +	vs->dpu = dpu;
> +	vs->id = id;
> +	vs->index = index;
> +	vs->link_id = dpu_vs_link_id[index];
> +
> +	mutex_init(&vs->mutex);
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/imx/dpu/dpu.h b/drivers/gpu/drm/imx/dpu/dpu.h
> new file mode 100644
> index 00000000..ef012e2
> --- /dev/null
> +++ b/drivers/gpu/drm/imx/dpu/dpu.h
> @@ -0,0 +1,385 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +/*
> + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> + * Copyright 2017-2020 NXP
> + */
> +
> +#ifndef __DPU_H__
> +#define __DPU_H__
> +
> +#include <linux/of.h>
> +#include <linux/types.h>
> +
> +#include <drm/drm_color_mgmt.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_modes.h>
> +
> +#define DPU_FRAMEGEN_MAX_FRAME_INDEX	0x3ffff
> +#define DPU_FRAMEGEN_MAX_CLOCK		300000	/* in KHz */
> +
> +#define DPU_FETCHUNIT_CAP_USE_FETCHECO	BIT(0)
> +#define DPU_FETCHUNIT_CAP_USE_SCALER	BIT(1)
> +#define DPU_FETCHUNIT_CAP_PACKED_YUV422	BIT(2)
> +
> +struct dpu_dprc;
> +struct dpu_fetchunit;
> +struct dpu_soc;
> +
> +enum dpu_link_id {
> +	LINK_ID_NONE		= 0x00,
> +	LINK_ID_FETCHDECODE9	= 0x01,
> +	LINK_ID_FETCHWARP9	= 0x02,
> +	LINK_ID_FETCHECO9	= 0x03,
> +	LINK_ID_ROP9		= 0x04,
> +	LINK_ID_CLUT9		= 0x05,
> +	LINK_ID_MATRIX9		= 0x06,
> +	LINK_ID_HSCALER9	= 0x07,
> +	LINK_ID_VSCALER9	= 0x08,
> +	LINK_ID_FILTER9		= 0x09,
> +	LINK_ID_BLITBLEND9	= 0x0a,
> +	LINK_ID_CONSTFRAME0	= 0x0c,
> +	LINK_ID_CONSTFRAME4	= 0x0e,
> +	LINK_ID_CONSTFRAME1	= 0x10,
> +	LINK_ID_CONSTFRAME5	= 0x12,
> +	LINK_ID_FETCHWARP2	= 0x14,
> +	LINK_ID_FETCHECO2	= 0x15,
> +	LINK_ID_FETCHDECODE0	= 0x16,
> +	LINK_ID_FETCHECO0	= 0x17,
> +	LINK_ID_FETCHDECODE1	= 0x18,
> +	LINK_ID_FETCHECO1	= 0x19,
> +	LINK_ID_FETCHLAYER0	= 0x1a,
> +	LINK_ID_MATRIX4		= 0x1b,
> +	LINK_ID_HSCALER4	= 0x1c,
> +	LINK_ID_VSCALER4	= 0x1d,
> +	LINK_ID_MATRIX5		= 0x1e,
> +	LINK_ID_HSCALER5	= 0x1f,
> +	LINK_ID_VSCALER5	= 0x20,
> +	LINK_ID_LAYERBLEND0	= 0x21,
> +	LINK_ID_LAYERBLEND1	= 0x22,
> +	LINK_ID_LAYERBLEND2	= 0x23,
> +	LINK_ID_LAYERBLEND3	= 0x24,
> +};
> +
> +enum dpu_fg_syncmode {
> +	FG_SYNCMODE_OFF,	/* No side-by-side synchronization. */
> +	FG_SYNCMODE_MASTER,	/* Framegen is master. */
> +	FG_SYNCMODE_SLAVE_CYC,	/* Runs in cyclic synchronization mode. */
> +	FG_SYNCMODE_SLAVE_ONCE,	/* Runs in one time synchronization mode. */
> +};
> +
> +enum dpu_fg_dm {
> +	FG_DM_BLACK,
> +	FG_DM_CONSTCOL,	/* Constant Color Background is shown. */
> +	FG_DM_PRIM,
> +	FG_DM_SEC,
> +	FG_DM_PRIM_ON_TOP,
> +	FG_DM_SEC_ON_TOP,
> +	FG_DM_TEST,	/* White color background with test pattern is shown. */
> +};
> +
> +enum dpu_gc_mode {
> +	GC_NEUTRAL,	/* Input data is bypassed to the output. */
> +	GC_GAMMACOR,
> +};
> +
> +enum dpu_lb_mode {
> +	LB_NEUTRAL,	/* Output is same as primary input. */
> +	LB_BLEND,
> +};
> +
> +enum dpu_scaler_field_mode {
> +	/* Constant 0 indicates frame or top field. */
> +	SCALER_ALWAYS0,
> +	/* Constant 1 indicates bottom field. */
> +	SCALER_ALWAYS1,
> +	/* Output field polarity is taken from input field polarity. */
> +	SCALER_INPUT,
> +	/* Output field polarity toggles, starting with 0 after reset. */
> +	SCALER_TOGGLE,
> +};
> +
> +enum dpu_scaler_filter_mode {
> +	SCALER_NEAREST,	/* pointer-sampling */
> +	SCALER_LINEAR,	/* box filter */
> +};
> +
> +enum dpu_scaler_scale_mode {
> +	SCALER_DOWNSCALE,
> +	SCALER_UPSCALE,
> +};
> +
> +enum dpu_scaler_mode {
> +	/* Pixel by-pass the scaler, all other settings are ignored. */
> +	SCALER_NEUTRAL,
> +	/* Scaler is active. */
> +	SCALER_ACTIVE,
> +};
> +
> +enum dpu_pec_clken {
> +	CLKEN_DISABLE = 0x0,
> +	CLKEN_AUTOMATIC = 0x1,
> +	CLKEN_FULL = 0x3,
> +};
> +
> +int dpu_map_irq(struct dpu_soc *dpu, int irq);
> +
> +/* Constant Frame Unit */
> +struct dpu_constframe;
> +enum dpu_link_id dpu_cf_get_link_id(struct dpu_constframe *cf);
> +void dpu_cf_framedimensions(struct dpu_constframe *cf, unsigned int w,
> +			    unsigned int h);
> +void dpu_cf_constantcolor_black(struct dpu_constframe *cf);
> +void dpu_cf_constantcolor_blue(struct dpu_constframe *cf);
> +struct dpu_constframe *dpu_cf_safe_get(struct dpu_soc *dpu,
> +				       unsigned int stream_id);
> +void dpu_cf_safe_put(struct dpu_constframe *cf);
> +struct dpu_constframe *dpu_cf_cont_get(struct dpu_soc *dpu,
> +				       unsigned int stream_id);
> +void dpu_cf_cont_put(struct dpu_constframe *cf);
> +
> +/* Display Engine Configuration Unit */
> +struct dpu_disengcfg;
> +struct dpu_disengcfg *dpu_dec_get(struct dpu_soc *dpu, unsigned int id);
> +void dpu_dec_put(struct dpu_disengcfg *dec);
> +
> +/* External Destination Unit */
> +struct dpu_extdst;
> +void dpu_ed_pec_poweron(struct dpu_extdst *ed);
> +void dpu_ed_pec_src_sel(struct dpu_extdst *ed, enum dpu_link_id src);
> +void dpu_ed_pec_sync_trigger(struct dpu_extdst *ed);
> +struct dpu_extdst *dpu_ed_safe_get(struct dpu_soc *dpu,
> +				   unsigned int stream_id);
> +void dpu_ed_safe_put(struct dpu_extdst *ed);
> +struct dpu_extdst *dpu_ed_cont_get(struct dpu_soc *dpu,
> +				   unsigned int stream_id);
> +void dpu_ed_cont_put(struct dpu_extdst *ed);
> +
> +/* Fetch Decode Unit */
> +struct dpu_fetchunit *dpu_fd_get(struct dpu_soc *dpu, unsigned int id);
> +void dpu_fd_put(struct dpu_fetchunit *fu);
> +
> +/* Fetch ECO Unit */
> +struct dpu_fetchunit *dpu_fe_get(struct dpu_soc *dpu, unsigned int id);
> +void dpu_fe_put(struct dpu_fetchunit *fu);
> +
> +/* Fetch Layer Unit */
> +struct dpu_fetchunit *dpu_fl_get(struct dpu_soc *dpu, unsigned int id);
> +void dpu_fl_put(struct dpu_fetchunit *fu);
> +
> +/* Fetch Warp Unit */
> +struct dpu_fetchunit *dpu_fw_get(struct dpu_soc *dpu, unsigned int id);
> +void dpu_fw_put(struct dpu_fetchunit *fu);
> +
> +/* Frame Generator Unit */
> +struct dpu_framegen;
> +void dpu_fg_syncmode(struct dpu_framegen *fg, enum dpu_fg_syncmode mode);
> +void dpu_fg_cfg_videomode(struct dpu_framegen *fg, struct drm_display_mode *m);
> +void dpu_fg_displaymode(struct dpu_framegen *fg, enum dpu_fg_dm mode);
> +void dpu_fg_panic_displaymode(struct dpu_framegen *fg, enum dpu_fg_dm mode);
> +void dpu_fg_enable(struct dpu_framegen *fg);
> +void dpu_fg_disable(struct dpu_framegen *fg);
> +void dpu_fg_shdtokgen(struct dpu_framegen *fg);
> +u32 dpu_fg_get_frame_index(struct dpu_framegen *fg);
> +int dpu_fg_get_line_index(struct dpu_framegen *fg);
> +int dpu_fg_wait_for_frame_counter_moving(struct dpu_framegen *fg);
> +bool dpu_fg_secondary_requests_to_read_empty_fifo(struct dpu_framegen *fg);
> +void dpu_fg_secondary_clear_channel_status(struct dpu_framegen *fg);
> +int dpu_fg_wait_for_secondary_syncup(struct dpu_framegen *fg);
> +void dpu_fg_enable_clock(struct dpu_framegen *fg);
> +void dpu_fg_disable_clock(struct dpu_framegen *fg);
> +struct dpu_framegen *dpu_fg_get(struct dpu_soc *dpu, unsigned int id);
> +void dpu_fg_put(struct dpu_framegen *fg);
> +
> +/* Gamma Correction Unit */
> +struct dpu_gammacor;
> +void dpu_gc_enable_rgb_write(struct dpu_gammacor *gc);
> +void dpu_gc_disable_rgb_write(struct dpu_gammacor *gc);
> +void dpu_gc_start_rgb(struct dpu_gammacor *gc, const struct drm_color_lut *lut);
> +void dpu_gc_delta_rgb(struct dpu_gammacor *gc, const struct drm_color_lut *lut);
> +void dpu_gc_mode(struct dpu_gammacor *gc, enum dpu_gc_mode mode);
> +struct dpu_gammacor *dpu_gc_get(struct dpu_soc *dpu, unsigned int id);
> +void dpu_gc_put(struct dpu_gammacor *gc);
> +
> +/* Horizontal Scaler Unit */
> +struct dpu_hscaler;
> +enum dpu_link_id dpu_hs_get_link_id(struct dpu_hscaler *hs);
> +void dpu_hs_pec_dynamic_src_sel(struct dpu_hscaler *hs, enum dpu_link_id src);
> +void dpu_hs_pec_clken(struct dpu_hscaler *hs, enum dpu_pec_clken clken);
> +void dpu_hs_setup1(struct dpu_hscaler *hs,
> +		   unsigned int src_w, unsigned int dst_w);
> +void dpu_hs_setup2(struct dpu_hscaler *hs, u32 phase_offset);
> +void dpu_hs_output_size(struct dpu_hscaler *hs, u32 line_num);
> +void dpu_hs_filter_mode(struct dpu_hscaler *hs, enum dpu_scaler_filter_mode m);
> +void dpu_hs_scale_mode(struct dpu_hscaler *hs, enum dpu_scaler_scale_mode m);
> +void dpu_hs_mode(struct dpu_hscaler *hs, enum dpu_scaler_mode m);
> +unsigned int dpu_hs_get_id(struct dpu_hscaler *hs);
> +struct dpu_hscaler *dpu_hs_get(struct dpu_soc *dpu, unsigned int id);
> +void dpu_hs_put(struct dpu_hscaler *hs);
> +
> +/* Layer Blend Unit */
> +struct dpu_layerblend;
> +enum dpu_link_id dpu_lb_get_link_id(struct dpu_layerblend *lb);
> +void dpu_lb_pec_dynamic_prim_sel(struct dpu_layerblend *lb,
> +				 enum dpu_link_id prim);
> +void dpu_lb_pec_dynamic_sec_sel(struct dpu_layerblend *lb,
> +				enum dpu_link_id sec);
> +void dpu_lb_pec_clken(struct dpu_layerblend *lb, enum dpu_pec_clken clken);
> +void dpu_lb_mode(struct dpu_layerblend *lb, enum dpu_lb_mode mode);
> +void dpu_lb_blendcontrol(struct dpu_layerblend *lb, unsigned int zpos,
> +			 unsigned int pixel_blend_mode, u16 alpha);
> +void dpu_lb_position(struct dpu_layerblend *lb, int x, int y);
> +unsigned int dpu_lb_get_id(struct dpu_layerblend *lb);
> +struct dpu_layerblend *dpu_lb_get(struct dpu_soc *dpu, unsigned int id);
> +void dpu_lb_put(struct dpu_layerblend *lb);
> +
> +/* Timing Controller Unit */
> +struct dpu_tcon;
> +void dpu_tcon_set_fmt(struct dpu_tcon *tcon);
> +void dpu_tcon_set_operation_mode(struct dpu_tcon *tcon);
> +void dpu_tcon_cfg_videomode(struct dpu_tcon *tcon, struct drm_display_mode *m);
> +struct dpu_tcon *dpu_tcon_get(struct dpu_soc *dpu, unsigned int id);
> +void dpu_tcon_put(struct dpu_tcon *tcon);
> +
> +/* Vertical Scaler Unit */
> +struct dpu_vscaler;
> +enum dpu_link_id dpu_vs_get_link_id(struct dpu_vscaler *vs);
> +void dpu_vs_pec_dynamic_src_sel(struct dpu_vscaler *vs, enum dpu_link_id src);
> +void dpu_vs_pec_clken(struct dpu_vscaler *vs, enum dpu_pec_clken clken);
> +void dpu_vs_setup1(struct dpu_vscaler *vs,
> +		   unsigned int src_w, unsigned int dst_w, bool deinterlace);
> +void dpu_vs_setup2(struct dpu_vscaler *vs, bool deinterlace);
> +void dpu_vs_setup3(struct dpu_vscaler *vs, bool deinterlace);
> +void dpu_vs_setup4(struct dpu_vscaler *vs, u32 phase_offset);
> +void dpu_vs_setup5(struct dpu_vscaler *vs, u32 phase_offset);
> +void dpu_vs_output_size(struct dpu_vscaler *vs, u32 line_num);
> +void dpu_vs_field_mode(struct dpu_vscaler *vs, enum dpu_scaler_field_mode m);
> +void dpu_vs_filter_mode(struct dpu_vscaler *vs, enum dpu_scaler_filter_mode m);
> +void dpu_vs_scale_mode(struct dpu_vscaler *vs, enum dpu_scaler_scale_mode m);
> +void dpu_vs_mode(struct dpu_vscaler *vs, enum dpu_scaler_mode m);
> +unsigned int dpu_vs_get_id(struct dpu_vscaler *vs);
> +struct dpu_vscaler *dpu_vs_get(struct dpu_soc *dpu, unsigned int id);
> +void dpu_vs_put(struct dpu_vscaler *vs);
> +
> +/* Fetch Units */
> +struct dpu_fetchunit_ops {
> +	void (*set_pec_dynamic_src_sel)(struct dpu_fetchunit *fu,
> +					enum dpu_link_id src);
> +
> +	bool (*is_enabled)(struct dpu_fetchunit *fu);
> +
> +	void (*set_stream_id)(struct dpu_fetchunit *fu, unsigned int stream_id);
> +
> +	unsigned int (*get_stream_id)(struct dpu_fetchunit *fu);
> +
> +	void (*set_no_stream_id)(struct dpu_fetchunit *fu);
> +
> +	bool (*has_stream_id)(struct dpu_fetchunit *fu);
> +
> +	void (*set_numbuffers)(struct dpu_fetchunit *fu, unsigned int num);
> +
> +	void (*set_burstlength)(struct dpu_fetchunit *fu,
> +				unsigned int x_offset, unsigned int mt_w,
> +				int bpp, dma_addr_t baddr);
> +
> +	void (*set_baseaddress)(struct dpu_fetchunit *fu, unsigned int width,
> +				unsigned int x_offset, unsigned int y_offset,
> +				unsigned int mt_w, unsigned int mt_h,
> +				int bpp, dma_addr_t baddr);
> +
> +	void (*set_src_stride)(struct dpu_fetchunit *fu,
> +			       unsigned int width, unsigned int x_offset,
> +			       unsigned int mt_w, int bpp, unsigned int stride,
> +			       dma_addr_t baddr);
> +
> +	void (*set_src_buf_dimensions)(struct dpu_fetchunit *fu,
> +				       unsigned int w, unsigned int h,
> +				       const struct drm_format_info *format,
> +				       bool deinterlace);
> +
> +	void (*set_fmt)(struct dpu_fetchunit *fu,
> +			const struct drm_format_info *format,
> +			enum drm_color_encoding color_encoding,
> +			enum drm_color_range color_range,
> +			bool deinterlace);
> +
> +	void (*set_pixel_blend_mode)(struct dpu_fetchunit *fu,
> +				     unsigned int pixel_blend_mode, u16 alpha,
> +				     bool fb_format_has_alpha);
> +
> +	void (*enable_src_buf)(struct dpu_fetchunit *fu);
> +	void (*disable_src_buf)(struct dpu_fetchunit *fu);
> +
> +	void (*set_framedimensions)(struct dpu_fetchunit *fu,
> +				    unsigned int w, unsigned int h,
> +				    bool deinterlace);
> +
> +	struct dpu_dprc *(*get_dprc)(struct dpu_fetchunit *fu);
> +	struct dpu_fetchunit *(*get_fetcheco)(struct dpu_fetchunit *fu);
> +	struct dpu_hscaler *(*get_hscaler)(struct dpu_fetchunit *fu);
> +	struct dpu_vscaler *(*get_vscaler)(struct dpu_fetchunit *fu);
> +
> +	void (*set_layerblend)(struct dpu_fetchunit *fu,
> +			       struct dpu_layerblend *lb);
> +
> +	bool (*is_available)(struct dpu_fetchunit *fu);
> +	void (*set_available)(struct dpu_fetchunit *fu);
> +	void (*set_inavailable)(struct dpu_fetchunit *fu);
> +
> +	enum dpu_link_id (*get_link_id)(struct dpu_fetchunit *fu);
> +
> +	u32 (*get_cap_mask)(struct dpu_fetchunit *fu);
> +
> +	const char *(*get_name)(struct dpu_fetchunit *fu);
> +};
> +
> +const struct dpu_fetchunit_ops *dpu_fu_get_ops(struct dpu_fetchunit *fu);
> +struct dpu_fetchunit *dpu_fu_get_from_list(struct list_head *l);
> +void dpu_fu_add_to_list(struct dpu_fetchunit *fu, struct list_head *l);
> +
> +/* HW resources for a plane group */
> +struct dpu_plane_res {
> +	struct dpu_fetchunit	**fd;
> +	struct dpu_fetchunit	**fe;
> +	struct dpu_fetchunit	**fl;
> +	struct dpu_fetchunit	**fw;
> +	struct dpu_layerblend	**lb;
> +	unsigned int		fd_cnt;
> +	unsigned int		fe_cnt;
> +	unsigned int		fl_cnt;
> +	unsigned int		fw_cnt;
> +	unsigned int		lb_cnt;
> +};
> +
> +/*
> + * fetchunit/scaler/layerblend resources of a plane group are
> + * shared by the two CRTCs in a CRTC group
> + */
> +struct dpu_plane_grp {
> +	struct dpu_plane_res	res;
> +	struct list_head	node;
> +	struct list_head	fu_list;
> +	unsigned int		hw_plane_cnt;
> +	struct dpu_constframe	*cf[2];
> +	struct dpu_extdst	*ed[2];
> +};
> +
> +/* the two CRTCs of one DPU are in a CRTC group */
> +struct dpu_crtc_grp {
> +	u32			crtc_mask;
> +	struct dpu_plane_grp	*plane_grp;
> +};
> +
> +struct dpu_client_platformdata {
> +	const unsigned int	stream_id;
> +	const unsigned int	dec_frame_complete_irq;
> +	const unsigned int	dec_seq_complete_irq;
> +	const unsigned int	dec_shdld_irq;
> +	const unsigned int	ed_cont_shdld_irq;
> +	const unsigned int	ed_safe_shdld_irq;
> +	struct dpu_crtc_grp	*crtc_grp;
> +
> +	struct device_node	*of_node;
> +};
> +
> +#endif /* __DPU_H__ */
> -- 
> 2.7.4
> 

_______________________________________________
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] 8+ messages in thread

* Re: [PATCH v8 5/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM
  2021-03-02 14:36   ` [PATCH v8 5/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM Laurentiu Palcu
@ 2021-03-03  6:21     ` Liu Ying
  0 siblings, 0 replies; 8+ messages in thread
From: Liu Ying @ 2021-03-03  6:21 UTC (permalink / raw)
  To: Laurentiu Palcu
  Cc: linux-arm-kernel, dri-devel, devicetree, linux-kernel, p.zabel,
	airlied, daniel, shawnguo, s.hauer, kernel, festevam, linux-imx,
	robh+dt, maarten.lankhorst, mripard, tzimmermann, guido.gunther

On Tue, 2021-03-02 at 16:36 +0200, Laurentiu Palcu wrote:
> Hi Liu Ying,
> 
> One comment below.
> 
> On Tue, Mar 02, 2021 at 02:33:15PM +0800, Liu Ying wrote:
> > This patch introduces i.MX8qm/qxp Display Processing Unit(DPU) DRM support.
> > 
> > DPU is comprised of two main components that include a blit engine for
> > 2D graphics accelerations(with composition support) and a display controller
> > for display output processing, as well as a command sequencer.  Outside of
> > DPU, optional prefetch engines, a.k.a, Prefetch Resolve Gasket(PRG) and
> > Display Prefetch Resolve(DPR), can fetch data from memory prior to some DPU
> > fetchunits of blit engine and display controller.  The prefetch engines
> > support reading linear formats and resolving Vivante GPU tile formats.
> > 
> > This patch adds kernel modesetting support for the display controller part.
> > The driver supports two CRTCs per display controller, planes backed by
> > four fetchunits(decode0/1, fetchlayer, fetchwarp), fetchunit allocation
> > logic for the two CRTCs, prefetch engines(with tile resolving supported),
> > plane upscaling/deinterlacing/yuv2rgb CSC/alpha blending and CRTC gamma
> > correction.  The registers of the controller is accessed without command
> > sequencer involved, instead just by using CPU.
> > 
> > Reference manual can be found at:
> > https://www.nxp.com/webapp/Download?colCode=IMX8DQXPRM
> > 
> > Signed-off-by: Liu Ying <victor.liu@nxp.com>
> > ---
> > Laurentiu, I see your R-b tag on this patch of v7.
> > As this patch is changed in v8, can you please help review and maybe add your
> > R-b tag again?
> > 
> > v7->v8:
> > * Update dpu_plane_atomic_check() and dpu_plane_atomic_update(), due to DRM
> >   plane helper functions API change(atomic_check and atomic_update) from DRM
> >   atomic core.  Also, rename plane->state variables and relevant DPU plane
> >   state variables in those two functions to reflect they are new states, like
> >   the patch 'drm: Rename plane->state variables in atomic update and disable'
> >   recently landed in drm-misc-next.
> > * Replace drm_gem_fb_prepare_fb() with drm_gem_plane_helper_prepare_fb(),
> >   due to DRM core API change.
> > * Use 256byte DPR burst length for GPU standard tile and 128byte DPR burst
> >   length for 32bpp GPU super tile to align with the latest version of internal
> >   HW documention.
> > 
> > v6->v7:
> > * Fix return value of dpu_get_irqs() if platform_get_irq() fails. (Laurentiu)
> > * Use the function array dpu_irq_handler[] to store individual DPU irq handlers.
> >   (Laurentiu)
> > * Call get/put() hooks directly to get/put DPU fetchunits for DPU plane groups.
> >   (Laurentiu)
> > * Shorten the names of individual DPU irq handlers by using DPU unit abbrev
> >   names to make writing dpu_irq_handler[] easier.
> > 
> > v5->v6:
> > * Do not use macros where possible. (Laurentiu)
> > * Break dpu_plane_atomic_check() into some smaller functions. (Laurentiu)
> > * Address some minor comments from Laurentiu.
> > * Add dpu_crtc_err() helper marco to tell dmesg which CRTC generates error.
> > * Drop calling dev_set_drvdata() from dpu_drm_bind/unbind() as it is done
> >   in dpu_drm_probe().
> > * Some trivial tweaks.
> > 
> > v4->v5:
> > * Rebase up onto the latest drm-misc-next branch and remove the hook to
> >   drm_atomic_helper_legacy_gamma_set(), because it was dropped by the newly
> >   landed commit 'drm: automatic legacy gamma support'.
> > * Remove a redundant blank line from dpu_plane_atomic_update().
> > 
> > v3->v4:
> > * No change.
> > 
> > v2->v3:
> > * Fix build warnings Reported-by: kernel test robot <lkp@intel.com>.
> > * Drop build dependency on IMX_SCU, as dummy SCU functions have been added in
> >   header files by the patch 'firmware: imx: add dummy functions' which has
> >   landed in linux-next/master branch.
> > 
> > v1->v2:
> > * Add compatible for i.MX8qm DPU, as this is tested with i.MX8qm LVDS displays.
> >   (Laurentiu)
> > * Fix PRG burst size and stride. (Laurentiu)
> > * Put 'ports' OF node to fix the bail-out logic in dpu_drm_probe(). (Laurentiu)
> > 
> >  drivers/gpu/drm/imx/Kconfig               |    1 +
> >  drivers/gpu/drm/imx/Makefile              |    1 +
> >  drivers/gpu/drm/imx/dpu/Kconfig           |   10 +
> >  drivers/gpu/drm/imx/dpu/Makefile          |   10 +
> >  drivers/gpu/drm/imx/dpu/dpu-constframe.c  |  171 +++++
> >  drivers/gpu/drm/imx/dpu/dpu-core.c        | 1054 +++++++++++++++++++++++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-crtc.c        |  967 ++++++++++++++++++++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-crtc.h        |   66 ++
> >  drivers/gpu/drm/imx/dpu/dpu-disengcfg.c   |  117 ++++
> >  drivers/gpu/drm/imx/dpu/dpu-dprc.c        |  722 ++++++++++++++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-dprc.h        |   40 ++
> >  drivers/gpu/drm/imx/dpu/dpu-drv.c         |  292 ++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-drv.h         |   28 +
> >  drivers/gpu/drm/imx/dpu/dpu-extdst.c      |  299 ++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-fetchdecode.c |  294 ++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-fetcheco.c    |  224 ++++++
> >  drivers/gpu/drm/imx/dpu/dpu-fetchlayer.c  |  154 +++++
> >  drivers/gpu/drm/imx/dpu/dpu-fetchunit.c   |  609 +++++++++++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-fetchunit.h   |  191 ++++++
> >  drivers/gpu/drm/imx/dpu/dpu-fetchwarp.c   |  250 +++++++
> >  drivers/gpu/drm/imx/dpu/dpu-framegen.c    |  395 +++++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-gammacor.c    |  223 ++++++
> >  drivers/gpu/drm/imx/dpu/dpu-hscaler.c     |  275 ++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-kms.c         |  540 +++++++++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-kms.h         |   23 +
> >  drivers/gpu/drm/imx/dpu/dpu-layerblend.c  |  348 ++++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-plane.c       |  802 ++++++++++++++++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-plane.h       |   56 ++
> >  drivers/gpu/drm/imx/dpu/dpu-prg.c         |  433 ++++++++++++
> >  drivers/gpu/drm/imx/dpu/dpu-prg.h         |   45 ++
> >  drivers/gpu/drm/imx/dpu/dpu-prv.h         |  233 +++++++
> >  drivers/gpu/drm/imx/dpu/dpu-tcon.c        |  250 +++++++
> >  drivers/gpu/drm/imx/dpu/dpu-vscaler.c     |  308 +++++++++
> >  drivers/gpu/drm/imx/dpu/dpu.h             |  385 +++++++++++
> >  34 files changed, 9816 insertions(+)
> >  create mode 100644 drivers/gpu/drm/imx/dpu/Kconfig
> >  create mode 100644 drivers/gpu/drm/imx/dpu/Makefile
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-constframe.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-core.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-crtc.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-crtc.h
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-disengcfg.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-dprc.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-dprc.h
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-drv.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-drv.h
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-extdst.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchdecode.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetcheco.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchlayer.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchunit.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchunit.h
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-fetchwarp.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-framegen.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-gammacor.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-hscaler.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-kms.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-kms.h
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-layerblend.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-plane.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-plane.h
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-prg.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-prg.h
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-prv.h
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-tcon.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu-vscaler.c
> >  create mode 100644 drivers/gpu/drm/imx/dpu/dpu.h
> > 
> 
> [...]
> 
> > diff --git a/drivers/gpu/drm/imx/dpu/dpu-plane.c b/drivers/gpu/drm/imx/dpu/dpu-plane.c
> > new file mode 100644
> > index 00000000..aaf0fe0
> > --- /dev/null
> > +++ b/drivers/gpu/drm/imx/dpu/dpu-plane.c
> > @@ -0,0 +1,802 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +
> > +/*
> > + * Copyright 2017-2020 NXP
> > + */
> > +
> > +#include <drm/drm_atomic.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_atomic_state_helper.h>
> > +#include <drm/drm_color_mgmt.h>
> > +#include <drm/drm_fb_cma_helper.h>
> > +#include <drm/drm_gem_atomic_helper.h>
> > +#include <drm/drm_gem_cma_helper.h>
> > +#include <drm/drm_plane_helper.h>
> > +
> > +#include "dpu.h"
> > +#include "dpu-crtc.h"
> > +#include "dpu-dprc.h"
> > +#include "dpu-plane.h"
> > +
> > +#define FRAC_16_16(mult, div)			(((mult) << 16) / (div))
> > +
> > +#define DPU_PLANE_MAX_PITCH			0x10000
> > +#define DPU_PLANE_MAX_PIX_CNT			8192
> > +#define DPU_PLANE_MAX_PIX_CNT_WITH_SCALER	2048
> > +
> > +static const uint32_t dpu_plane_formats[] = {
> > +	DRM_FORMAT_ARGB8888,
> > +	DRM_FORMAT_XRGB8888,
> > +	DRM_FORMAT_ABGR8888,
> > +	DRM_FORMAT_XBGR8888,
> > +	DRM_FORMAT_RGBA8888,
> > +	DRM_FORMAT_RGBX8888,
> > +	DRM_FORMAT_BGRA8888,
> > +	DRM_FORMAT_BGRX8888,
> > +	DRM_FORMAT_RGB565,
> > +
> > +	DRM_FORMAT_YUYV,
> > +	DRM_FORMAT_UYVY,
> > +	DRM_FORMAT_NV12,
> > +	DRM_FORMAT_NV21,
> > +};
> > +
> > +static const uint64_t dpu_plane_format_modifiers[] = {
> > +	DRM_FORMAT_MOD_VIVANTE_TILED,
> > +	DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
> > +	DRM_FORMAT_MOD_LINEAR,
> > +	DRM_FORMAT_MOD_INVALID,
> > +};
> > +
> > +static unsigned int dpu_plane_get_default_zpos(enum drm_plane_type type)
> > +{
> > +	if (type == DRM_PLANE_TYPE_PRIMARY)
> > +		return 0;
> > +	else if (type == DRM_PLANE_TYPE_OVERLAY)
> > +		return 1;
> > +
> > +	return 0;
> > +}
> > +
> > +static void dpu_plane_destroy(struct drm_plane *plane)
> > +{
> > +	struct dpu_plane *dpu_plane = to_dpu_plane(plane);
> > +
> > +	drm_plane_cleanup(plane);
> > +	kfree(dpu_plane);
> > +}
> > +
> > +static void dpu_plane_reset(struct drm_plane *plane)
> > +{
> > +	struct dpu_plane_state *state;
> > +
> > +	if (plane->state) {
> > +		__drm_atomic_helper_plane_destroy_state(plane->state);
> > +		kfree(to_dpu_plane_state(plane->state));
> > +		plane->state = NULL;
> > +	}
> > +
> > +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> > +	if (!state)
> > +		return;
> > +
> > +	__drm_atomic_helper_plane_reset(plane, &state->base);
> > +
> > +	plane->state->zpos = dpu_plane_get_default_zpos(plane->type);
> > +	plane->state->color_encoding = DRM_COLOR_YCBCR_BT709;
> > +	plane->state->color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
> > +}
> > +
> > +static struct drm_plane_state *
> > +dpu_drm_atomic_plane_duplicate_state(struct drm_plane *plane)
> > +{
> > +	struct dpu_plane_state *state, *copy;
> > +
> > +	if (WARN_ON(!plane->state))
> > +		return NULL;
> > +
> > +	copy = kmalloc(sizeof(*state), GFP_KERNEL);
> > +	if (!copy)
> > +		return NULL;
> > +
> > +	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
> > +	state = to_dpu_plane_state(plane->state);
> > +	copy->stage = state->stage;
> > +	copy->source = state->source;
> > +	copy->blend = state->blend;
> > +	copy->is_top = state->is_top;
> > +
> > +	return &copy->base;
> > +}
> > +
> > +static void dpu_drm_atomic_plane_destroy_state(struct drm_plane *plane,
> > +					       struct drm_plane_state *state)
> > +{
> > +	__drm_atomic_helper_plane_destroy_state(state);
> > +	kfree(to_dpu_plane_state(state));
> > +}
> > +
> > +static bool dpu_drm_plane_format_mod_supported(struct drm_plane *plane,
> > +					       uint32_t format,
> > +					       uint64_t modifier)
> > +{
> > +	switch (format) {
> > +	case DRM_FORMAT_YUYV:
> > +	case DRM_FORMAT_UYVY:
> > +	case DRM_FORMAT_NV12:
> > +	case DRM_FORMAT_NV21:
> > +		return modifier == DRM_FORMAT_MOD_LINEAR;
> > +	case DRM_FORMAT_ARGB8888:
> > +	case DRM_FORMAT_XRGB8888:
> > +	case DRM_FORMAT_ABGR8888:
> > +	case DRM_FORMAT_XBGR8888:
> > +	case DRM_FORMAT_RGBA8888:
> > +	case DRM_FORMAT_RGBX8888:
> > +	case DRM_FORMAT_BGRA8888:
> > +	case DRM_FORMAT_BGRX8888:
> > +	case DRM_FORMAT_RGB565:
> > +		return modifier == DRM_FORMAT_MOD_LINEAR ||
> > +		       modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
> > +		       modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
> > +	default:
> > +		return false;
> > +	}
> > +}
> > +
> > +static const struct drm_plane_funcs dpu_plane_funcs = {
> > +	.update_plane		= drm_atomic_helper_update_plane,
> > +	.disable_plane		= drm_atomic_helper_disable_plane,
> > +	.destroy		= dpu_plane_destroy,
> > +	.reset			= dpu_plane_reset,
> > +	.atomic_duplicate_state	= dpu_drm_atomic_plane_duplicate_state,
> > +	.atomic_destroy_state	= dpu_drm_atomic_plane_destroy_state,
> > +	.format_mod_supported	= dpu_drm_plane_format_mod_supported,
> > +};
> > +
> > +static inline dma_addr_t
> > +drm_plane_state_to_baseaddr(struct drm_plane_state *state)
> > +{
> > +	struct drm_framebuffer *fb = state->fb;
> > +	struct drm_gem_cma_object *cma_obj;
> > +	unsigned int x = state->src.x1 >> 16;
> > +	unsigned int y = state->src.y1 >> 16;
> > +
> > +	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
> > +
> > +	if (fb->flags & DRM_MODE_FB_INTERLACED)
> > +		y /= 2;
> > +
> > +	return cma_obj->paddr + fb->offsets[0] + fb->pitches[0] * y +
> > +	       fb->format->cpp[0] * x;
> > +}
> > +
> > +static inline dma_addr_t
> > +drm_plane_state_to_uvbaseaddr(struct drm_plane_state *state)
> > +{
> > +	struct drm_framebuffer *fb = state->fb;
> > +	struct drm_gem_cma_object *cma_obj;
> > +	int x = state->src.x1 >> 16;
> > +	int y = state->src.y1 >> 16;
> > +
> > +	cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
> > +
> > +	x /= fb->format->hsub;
> > +	y /= fb->format->vsub;
> > +
> > +	if (fb->flags & DRM_MODE_FB_INTERLACED)
> > +		y /= 2;
> > +
> > +	return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y +
> > +	       fb->format->cpp[1] * x;
> > +}
> > +
> > +static int dpu_plane_check_no_off_screen(struct drm_plane_state *state,
> > +					 struct drm_crtc_state *crtc_state)
> > +{
> > +	if (state->dst.x1 < 0 || state->dst.y1 < 0 ||
> > +	    (state->dst.x2 > crtc_state->adjusted_mode.hdisplay) ||
> > +	    (state->dst.y2 > crtc_state->adjusted_mode.vdisplay)) {
> > +		dpu_plane_dbg(state->plane, "no off screen\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int dpu_plane_check_max_source_resolution(struct drm_plane_state *state)
> > +{
> > +	u32 src_w = drm_rect_width(&state->src) >> 16;
> > +	u32 src_h = drm_rect_height(&state->src) >> 16;
> > +	u32 dst_w = drm_rect_width(&state->dst);
> > +	u32 dst_h = drm_rect_height(&state->dst);
> > +
> > +	if (src_w == dst_w || src_h == dst_h) {
> > +		/* without scaling */
> > +		if (src_w > DPU_PLANE_MAX_PIX_CNT ||
> > +		    src_h > DPU_PLANE_MAX_PIX_CNT) {
> > +			dpu_plane_dbg(state->plane,
> > +				      "invalid source resolution\n");
> > +			return -EINVAL;
> > +		}
> > +	} else {
> > +		/* with scaling */
> > +		if (src_w > DPU_PLANE_MAX_PIX_CNT_WITH_SCALER ||
> > +		    src_h > DPU_PLANE_MAX_PIX_CNT_WITH_SCALER) {
> > +			dpu_plane_dbg(state->plane,
> > +				      "invalid source resolution with scale\n");
> > +			return -EINVAL;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int dpu_plane_check_source_alignment(struct drm_plane_state *state)
> > +{
> > +	struct drm_framebuffer *fb = state->fb;
> > +	bool fb_is_interlaced = !!(fb->flags & DRM_MODE_FB_INTERLACED);
> > +	u32 src_w = drm_rect_width(&state->src) >> 16;
> > +	u32 src_h = drm_rect_height(&state->src) >> 16;
> > +	u32 src_x = state->src.x1 >> 16;
> > +	u32 src_y = state->src.y1 >> 16;
> > +
> > +	if (fb->format->hsub == 2) {
> > +		if (src_w % 2) {
> > +			dpu_plane_dbg(state->plane, "bad uv width\n");
> > +			return -EINVAL;
> > +		}
> > +		if (src_x % 2) {
> > +			dpu_plane_dbg(state->plane, "bad uv xoffset\n");
> > +			return -EINVAL;
> > +		}
> > +	}
> > +	if (fb->format->vsub == 2) {
> > +		if (src_h % (fb_is_interlaced ? 4 : 2)) {
> > +			dpu_plane_dbg(state->plane, "bad uv height\n");
> > +			return -EINVAL;
> > +		}
> > +		if (src_y % (fb_is_interlaced ? 4 : 2)) {
> > +			dpu_plane_dbg(state->plane, "bad uv yoffset\n");
> > +			return -EINVAL;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int dpu_plane_check_fb_modifier(struct drm_plane_state *state)
> > +{
> > +	struct drm_plane *plane = state->plane;
> > +	struct drm_framebuffer *fb = state->fb;
> > +
> > +	if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
> > +	    !plane->funcs->format_mod_supported(plane, fb->format->format,
> > +						fb->modifier)) {
> > +		dpu_plane_dbg(plane, "invalid modifier 0x%016llx",
> > +								fb->modifier);
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/* for tile formats, framebuffer has to be tile aligned */
> > +static int dpu_plane_check_tiled_fb_alignment(struct drm_plane_state *state)
> > +{
> > +	struct drm_plane *plane = state->plane;
> > +	struct drm_framebuffer *fb = state->fb;
> > +
> > +	switch (fb->modifier) {
> > +	case DRM_FORMAT_MOD_VIVANTE_TILED:
> > +		if (fb->width % 4) {
> > +			dpu_plane_dbg(plane, "bad fb width for VIVANTE tile\n");
> > +			return -EINVAL;
> > +		}
> > +		if (fb->height % 4) {
> > +			dpu_plane_dbg(plane, "bad fb height for VIVANTE tile\n");
> > +			return -EINVAL;
> > +		}
> > +		break;
> > +	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
> > +		if (fb->width % 64) {
> > +			dpu_plane_dbg(plane,
> > +				      "bad fb width for VIVANTE super tile\n");
> > +			return -EINVAL;
> > +		}
> > +		if (fb->height % 64) {
> > +			dpu_plane_dbg(plane,
> > +				      "bad fb height for VIVANTE super tile\n");
> > +			return -EINVAL;
> > +		}
> > +		break;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int dpu_plane_check_no_bt709_full_range(struct drm_plane_state *state)
> > +{
> > +	if (state->fb->format->is_yuv &&
> > +	    state->color_encoding == DRM_COLOR_YCBCR_BT709 &&
> > +	    state->color_range == DRM_COLOR_YCBCR_FULL_RANGE) {
> > +		dpu_plane_dbg(state->plane, "no BT709 full range support\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int dpu_plane_check_fb_plane_1(struct drm_plane_state *state)
> > +{
> > +	struct drm_plane *plane = state->plane;
> > +	struct drm_framebuffer *fb = state->fb;
> > +	dma_addr_t baseaddr = drm_plane_state_to_baseaddr(state);
> > +	int bpp;
> > +
> > +	/* base address alignment */
> > +	switch (fb->format->format) {
> > +	case DRM_FORMAT_YUYV:
> > +	case DRM_FORMAT_UYVY:
> > +		bpp = 16;
> > +		break;
> > +	case DRM_FORMAT_NV12:
> > +	case DRM_FORMAT_NV21:
> > +		bpp = 8;
> > +		break;
> > +	default:
> > +		bpp = fb->format->cpp[0] * 8;
> > +		break;
> > +	}
> > +	if (((bpp == 32) && (baseaddr & 0x3)) ||
> > +	    ((bpp == 16) && (baseaddr & 0x1))) {
> > +		dpu_plane_dbg(plane, "%dbpp fb bad baddr alignment\n", bpp);
> > +		return -EINVAL;
> > +	}
> > +	switch (bpp) {
> > +	case 32:
> > +		if (baseaddr & 0x3) {
> > +			dpu_plane_dbg(plane, "32bpp fb bad baddr alignment\n");
> > +			return -EINVAL;
> > +		}
> > +		break;
> > +	case 16:
> > +		if (fb->modifier) {
> > +			if (baseaddr & 0x1) {
> > +				dpu_plane_dbg(plane,
> > +					"16bpp tile fb bad baddr alignment\n");
> > +				return -EINVAL;
> > +			}
> > +		} else {
> > +			if (baseaddr & 0x7) {
> > +				dpu_plane_dbg(plane,
> > +					"16bpp fb bad baddr alignment\n");
> > +				return -EINVAL;
> > +			}
> > +		}
> > +		break;
> > +	}
> > +
> > +	/* pitches[0] range */
> > +	if (fb->pitches[0] > DPU_PLANE_MAX_PITCH) {
> > +		dpu_plane_dbg(plane, "fb pitches[0] is out of range\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* pitches[0] alignment */
> > +	if (((bpp == 32) && (fb->pitches[0] & 0x3)) ||
> > +	    ((bpp == 16) && (fb->pitches[0] & 0x1))) {
> > +		dpu_plane_dbg(plane, "%dbpp fb bad pitches[0] alignment\n", bpp);
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/* UV planar check, assuming 16bpp */
> > +static int dpu_plane_check_fb_plane_2(struct drm_plane_state *state)
> > +{
> > +	struct drm_plane *plane = state->plane;
> > +	struct drm_framebuffer *fb = state->fb;
> > +	dma_addr_t uv_baseaddr = drm_plane_state_to_uvbaseaddr(state);
> > +
> > +	/* base address alignment */
> > +	if (uv_baseaddr & 0x7) {
> > +		dpu_plane_dbg(plane, "bad uv baddr alignment\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* pitches[1] range */
> > +	if (fb->pitches[1] > DPU_PLANE_MAX_PITCH) {
> > +		dpu_plane_dbg(plane, "fb pitches[1] is out of range\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* pitches[1] alignment */
> > +	if (fb->pitches[1] & 0x1) {
> > +		dpu_plane_dbg(plane, "fb bad pitches[1] alignment\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int dpu_plane_check_dprc(struct drm_plane_state *state)
> > +{
> > +	struct dpu_plane_state *dpstate = to_dpu_plane_state(state);
> > +	struct drm_framebuffer *fb = state->fb;
> > +	const struct dpu_fetchunit_ops *fu_ops;
> > +	struct dpu_dprc *dprc;
> > +	dma_addr_t baseaddr, uv_baseaddr = 0;
> > +	u32 src_w = drm_rect_width(&state->src) >> 16;
> > +	u32 src_x = state->src.x1 >> 16;
> > +
> > +	fu_ops = dpu_fu_get_ops(dpstate->source);
> > +	dprc = fu_ops->get_dprc(dpstate->source);
> > +
> > +	if (!dpu_dprc_rtram_width_supported(dprc, src_w)) {
> > +		dpu_plane_dbg(state->plane, "bad RTRAM width for DPRC\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	baseaddr = drm_plane_state_to_baseaddr(state);
> > +	if (fb->format->num_planes > 1)
> > +		uv_baseaddr = drm_plane_state_to_uvbaseaddr(state);
> > +
> > +	if (!dpu_dprc_stride_supported(dprc, fb->pitches[0], fb->pitches[1],
> > +				       src_w, src_x, fb->format, fb->modifier,
> > +				       baseaddr, uv_baseaddr)) {
> > +		dpu_plane_dbg(state->plane, "bad fb pitches for DPRC\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int dpu_plane_atomic_check(struct drm_plane *plane,
> > +				  struct drm_atomic_state *state)
> > +{
> > +	struct drm_plane_state *new_plane_state =
> > +				drm_atomic_get_new_plane_state(state, plane);
> > +	struct dpu_plane_state *new_dpstate =
> > +				to_dpu_plane_state(new_plane_state);
> > +	struct drm_framebuffer *fb = new_plane_state->fb;
> > +	struct drm_crtc_state *crtc_state;
> > +	int min_scale, ret;
> > +
> > +	/* ok to disable */
> > +	if (!fb) {
> > +		new_dpstate->source = NULL;
> > +		new_dpstate->stage.ptr = NULL;
> > +		new_dpstate->blend = NULL;
> > +		return 0;
> > +	}
> > +
> > +	if (!new_plane_state->crtc) {
> > +		dpu_plane_dbg(plane, "no CRTC in plane state\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	crtc_state =
> > +		drm_atomic_get_existing_crtc_state(state, new_plane_state->crtc);
> > +	if (WARN_ON(!crtc_state))
> > +		return -EINVAL;
> > +
> > +	min_scale = FRAC_16_16(1, DPU_PLANE_MAX_PIX_CNT_WITH_SCALER);
> > +	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> > +						  min_scale,
> > +						  DRM_PLANE_HELPER_NO_SCALING,
> > +						  true, false);
> > +	if (ret) {
> > +		dpu_plane_dbg(plane, "failed to check plane state: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	ret = dpu_plane_check_no_off_screen(new_plane_state, crtc_state);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = dpu_plane_check_max_source_resolution(new_plane_state);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = dpu_plane_check_source_alignment(new_plane_state);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = dpu_plane_check_fb_modifier(new_plane_state);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = dpu_plane_check_tiled_fb_alignment(new_plane_state);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = dpu_plane_check_no_bt709_full_range(new_plane_state);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = dpu_plane_check_fb_plane_1(new_plane_state);
> > +	if (ret)
> > +		return ret;
> > +
> > +	if (fb->format->num_planes > 1) {
> > +		ret = dpu_plane_check_fb_plane_2(new_plane_state);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	return dpu_plane_check_dprc(new_plane_state);
> > +}
> > +
> > +static void dpu_plane_atomic_update(struct drm_plane *plane,
> > +				    struct drm_atomic_state *state)
> > +{
> > +	struct dpu_plane *dplane = to_dpu_plane(plane);
> > +	struct drm_plane_state *new_state = plane->state;
> 
> I think you want to use the drm_atomic_get_new_plane_state() helper here as
> well. See:

I think you are right.  I'll wait a period of time to see if I can
receive more comments on this series or not, and then send a next
version with this comment addressed.

Thanks,
Liu Ying

> 
> 37418bf14c13 ("drm: Use state helper instead of the plane state pointer")
> 
> Thanks,
> laurentiu
> 
> > +	struct dpu_plane_state *new_dpstate = to_dpu_plane_state(new_state);
> > +	struct dpu_plane_grp *grp = dplane->grp;
> > +	struct dpu_crtc *dpu_crtc;
> > +	struct drm_framebuffer *fb = new_state->fb;
> > +	struct dpu_fetchunit *fu = new_dpstate->source;
> > +	struct dpu_layerblend *lb = new_dpstate->blend;
> > +	struct dpu_dprc *dprc;
> > +	const struct dpu_fetchunit_ops *fu_ops;
> > +	dma_addr_t baseaddr, uv_baseaddr;
> > +	enum dpu_link_id fu_link;
> > +	enum dpu_link_id lb_src_link, stage_link;
> > +	enum dpu_link_id vs_link;
> > +	unsigned int src_w, src_h, src_x, src_y, dst_w, dst_h;
> > +	unsigned int mt_w = 0, mt_h = 0;	/* micro-tile width/height */
> > +	int bpp;
> > +	bool prefetch_start = false;
> > +	bool need_fetcheco = false, need_hscaler = false, need_vscaler = false;
> > +	bool need_modeset;
> > +	bool fb_is_interlaced;
> > +
> > +	/*
> > +	 * Do nothing since the plane is disabled by
> > +	 * crtc_func->atomic_begin/flush.
> > +	 */
> > +	if (!fb)
> > +		return;
> > +
> > +	/* Do nothing if CRTC is inactive. */
> > +	if (!new_state->crtc->state->active)
> > +		return;
> > +
> > +	need_modeset = drm_atomic_crtc_needs_modeset(new_state->crtc->state);
> > +
> > +	fb_is_interlaced = !!(fb->flags & DRM_MODE_FB_INTERLACED);
> > +
> > +	src_w = drm_rect_width(&new_state->src) >> 16;
> > +	src_h = drm_rect_height(&new_state->src) >> 16;
> > +	src_x = new_state->src.x1 >> 16;
> > +	src_y = new_state->src.y1 >> 16;
> > +	dst_w = drm_rect_width(&new_state->dst);
> > +	dst_h = drm_rect_height(&new_state->dst);
> > +
> > +	switch (fb->format->format) {
> > +	case DRM_FORMAT_YUYV:
> > +	case DRM_FORMAT_UYVY:
> > +		bpp = 16;
> > +		break;
> > +	case DRM_FORMAT_NV12:
> > +	case DRM_FORMAT_NV21:
> > +		bpp = 8;
> > +		break;
> > +	default:
> > +		bpp = fb->format->cpp[0] * 8;
> > +		break;
> > +	}
> > +
> > +	switch (fb->modifier) {
> > +	case DRM_FORMAT_MOD_VIVANTE_TILED:
> > +	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
> > +		mt_w = (bpp == 16) ? 8 : 4;
> > +		mt_h = 4;
> > +		break;
> > +	}
> > +
> > +	if (fb->format->num_planes > 1)
> > +		need_fetcheco = true;
> > +
> > +	if (src_w != dst_w)
> > +		need_hscaler = true;
> > +
> > +	if ((src_h != dst_h) || fb_is_interlaced)
> > +		need_vscaler = true;
> > +
> > +	baseaddr = drm_plane_state_to_baseaddr(new_state);
> > +	if (need_fetcheco)
> > +		uv_baseaddr = drm_plane_state_to_uvbaseaddr(new_state);
> > +
> > +	dpu_crtc = to_dpu_crtc(new_state->crtc);
> > +
> > +	fu_ops = dpu_fu_get_ops(fu);
> > +
> > +	if (!fu_ops->has_stream_id(fu) || need_modeset)
> > +		prefetch_start = true;
> > +
> > +	fu_ops->set_layerblend(fu, lb);
> > +
> > +	fu_ops->set_burstlength(fu, src_x, mt_w, bpp, baseaddr);
> > +	fu_ops->set_src_stride(fu, src_w, src_w, mt_w, bpp, fb->pitches[0],
> > +			       baseaddr);
> > +	fu_ops->set_src_buf_dimensions(fu, src_w, src_h, fb->format,
> > +				       fb_is_interlaced);
> > +	fu_ops->set_fmt(fu, fb->format, new_state->color_encoding,
> > +			new_state->color_range, fb_is_interlaced);
> > +	fu_ops->set_pixel_blend_mode(fu, new_state->pixel_blend_mode,
> > +				     new_state->alpha, fb->format->has_alpha);
> > +	fu_ops->enable_src_buf(fu);
> > +	fu_ops->set_framedimensions(fu, src_w, src_h, fb_is_interlaced);
> > +	fu_ops->set_baseaddress(fu, src_w, src_x, src_y, mt_w, mt_h, bpp,
> > +				baseaddr);
> > +	fu_ops->set_stream_id(fu, dpu_crtc->stream_id);
> > +
> > +	fu_link = fu_ops->get_link_id(fu);
> > +	lb_src_link = fu_link;
> > +
> > +	dpu_plane_dbg(plane, "uses %s\n", fu_ops->get_name(fu));
> > +
> > +	if (need_fetcheco) {
> > +		struct dpu_fetchunit *fe = fu_ops->get_fetcheco(fu);
> > +		const struct dpu_fetchunit_ops *fe_ops;
> > +
> > +		fe_ops = dpu_fu_get_ops(fe);
> > +
> > +		fu_ops->set_pec_dynamic_src_sel(fu, fe_ops->get_link_id(fe));
> > +
> > +		fe_ops->set_burstlength(fe, src_x, mt_w, bpp, uv_baseaddr);
> > +		fe_ops->set_src_stride(fe, src_w, src_x, mt_w, bpp,
> > +				       fb->pitches[1], uv_baseaddr);
> > +		fe_ops->set_fmt(fe, fb->format, new_state->color_encoding,
> > +				new_state->color_range, fb_is_interlaced);
> > +		fe_ops->set_src_buf_dimensions(fe, src_w, src_h,
> > +					       fb->format, fb_is_interlaced);
> > +		fe_ops->set_framedimensions(fe, src_w, src_h, fb_is_interlaced);
> > +		fe_ops->set_baseaddress(fe, src_w, src_x, src_y / 2,
> > +					mt_w, mt_h, bpp, uv_baseaddr);
> > +		fe_ops->enable_src_buf(fe);
> > +
> > +		dpu_plane_dbg(plane, "uses %s\n", fe_ops->get_name(fe));
> > +	} else {
> > +		if (fu_ops->set_pec_dynamic_src_sel)
> > +			fu_ops->set_pec_dynamic_src_sel(fu, LINK_ID_NONE);
> > +	}
> > +
> > +	/* VScaler comes first */
> > +	if (need_vscaler) {
> > +		struct dpu_vscaler *vs = fu_ops->get_vscaler(fu);
> > +
> > +		dpu_vs_pec_dynamic_src_sel(vs, fu_link);
> > +		dpu_vs_pec_clken(vs, CLKEN_AUTOMATIC);
> > +		dpu_vs_setup1(vs, src_h, new_state->crtc_h, fb_is_interlaced);
> > +		dpu_vs_setup2(vs, fb_is_interlaced);
> > +		dpu_vs_setup3(vs, fb_is_interlaced);
> > +		dpu_vs_output_size(vs, dst_h);
> > +		dpu_vs_field_mode(vs, fb_is_interlaced ?
> > +						SCALER_ALWAYS0 : SCALER_INPUT);
> > +		dpu_vs_filter_mode(vs, SCALER_LINEAR);
> > +		dpu_vs_scale_mode(vs, SCALER_UPSCALE);
> > +		dpu_vs_mode(vs, SCALER_ACTIVE);
> > +
> > +		vs_link = dpu_vs_get_link_id(vs);
> > +		lb_src_link = vs_link;
> > +
> > +		dpu_plane_dbg(plane, "uses VScaler%u\n", dpu_vs_get_id(vs));
> > +	}
> > +
> > +	/* and then, HScaler */
> > +	if (need_hscaler) {
> > +		struct dpu_hscaler *hs = fu_ops->get_hscaler(fu);
> > +
> > +		dpu_hs_pec_dynamic_src_sel(hs, need_vscaler ? vs_link : fu_link);
> > +		dpu_hs_pec_clken(hs, CLKEN_AUTOMATIC);
> > +		dpu_hs_setup1(hs, src_w, dst_w);
> > +		dpu_hs_output_size(hs, dst_w);
> > +		dpu_hs_filter_mode(hs, SCALER_LINEAR);
> > +		dpu_hs_scale_mode(hs, SCALER_UPSCALE);
> > +		dpu_hs_mode(hs, SCALER_ACTIVE);
> > +
> > +		lb_src_link = dpu_hs_get_link_id(hs);
> > +
> > +		dpu_plane_dbg(plane, "uses HScaler%u\n", dpu_hs_get_id(hs));
> > +	}
> > +
> > +	dprc = fu_ops->get_dprc(fu);
> > +
> > +	dpu_dprc_configure(dprc, dpu_crtc->stream_id,
> > +			   src_w, src_h, src_x, src_y,
> > +			   fb->pitches[0], fb->format, fb->modifier,
> > +			   baseaddr, uv_baseaddr,
> > +			   prefetch_start, fb_is_interlaced);
> > +
> > +	if (new_state->normalized_zpos == 0)
> > +		stage_link = dpu_cf_get_link_id(new_dpstate->stage.cf);
> > +	else
> > +		stage_link = dpu_lb_get_link_id(new_dpstate->stage.lb);
> > +
> > +	dpu_lb_pec_dynamic_prim_sel(lb, stage_link);
> > +	dpu_lb_pec_dynamic_sec_sel(lb, lb_src_link);
> > +	dpu_lb_mode(lb, LB_BLEND);
> > +	dpu_lb_blendcontrol(lb, new_state->normalized_zpos,
> > +			    new_state->pixel_blend_mode, new_state->alpha);
> > +	dpu_lb_pec_clken(lb, CLKEN_AUTOMATIC);
> > +	dpu_lb_position(lb, new_state->dst.x1, new_state->dst.y1);
> > +
> > +	dpu_plane_dbg(plane, "uses LayerBlend%u\n", dpu_lb_get_id(lb));
> > +
> > +	if (new_dpstate->is_top)
> > +		dpu_ed_pec_src_sel(grp->ed[dpu_crtc->stream_id],
> > +				   dpu_lb_get_link_id(lb));
> > +}
> > +
> > +static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
> > +	.prepare_fb	= drm_gem_plane_helper_prepare_fb,
> > +	.atomic_check	= dpu_plane_atomic_check,
> > +	.atomic_update	= dpu_plane_atomic_update,
> > +};
> > +
> > +struct dpu_plane *dpu_plane_initialize(struct drm_device *drm,
> > +				       unsigned int possible_crtcs,
> > +				       struct dpu_plane_grp *grp,
> > +				       enum drm_plane_type type)
> > +{
> > +	struct dpu_plane *dpu_plane;
> > +	struct drm_plane *plane;
> > +	unsigned int zpos = dpu_plane_get_default_zpos(type);
> > +	int ret;
> > +
> > +	dpu_plane = kzalloc(sizeof(*dpu_plane), GFP_KERNEL);
> > +	if (!dpu_plane)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	dpu_plane->grp = grp;
> > +
> > +	plane = &dpu_plane->base;
> > +
> > +	ret = drm_universal_plane_init(drm, plane, possible_crtcs,
> > +				       &dpu_plane_funcs,
> > +				       dpu_plane_formats,
> > +				       ARRAY_SIZE(dpu_plane_formats),
> > +				       dpu_plane_format_modifiers, type, NULL);
> > +	if (ret) {
> > +		/*
> > +		 * The plane is not added to the global plane list, so
> > +		 * free it manually.
> > +		 */
> > +		kfree(dpu_plane);
> > +		return ERR_PTR(ret);
> > +	}
> > +
> > +	drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
> > +
> > +	ret = drm_plane_create_zpos_property(plane,
> > +					     zpos, 0, grp->hw_plane_cnt - 1);
> > +	if (ret)
> > +		return ERR_PTR(ret);
> > +
> > +	ret = drm_plane_create_alpha_property(plane);
> > +	if (ret)
> > +		return ERR_PTR(ret);
> > +
> > +	ret = drm_plane_create_blend_mode_property(plane,
> > +					BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> > +					BIT(DRM_MODE_BLEND_PREMULTI) |
> > +					BIT(DRM_MODE_BLEND_COVERAGE));
> > +	if (ret)
> > +		return ERR_PTR(ret);
> > +
> > +	ret = drm_plane_create_color_properties(plane,
> > +					BIT(DRM_COLOR_YCBCR_BT601) |
> > +					BIT(DRM_COLOR_YCBCR_BT709),
> > +					BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
> > +					BIT(DRM_COLOR_YCBCR_FULL_RANGE),
> > +					DRM_COLOR_YCBCR_BT709,
> > +					DRM_COLOR_YCBCR_LIMITED_RANGE);
> > +	if (ret)
> > +		return ERR_PTR(ret);
> > +
> > +	return dpu_plane;
> > +}
> > diff --git a/drivers/gpu/drm/imx/dpu/dpu-plane.h b/drivers/gpu/drm/imx/dpu/dpu-plane.h
> > new file mode 100644
> > index 00000000..7bdd867
> > --- /dev/null
> > +++ b/drivers/gpu/drm/imx/dpu/dpu-plane.h
> > @@ -0,0 +1,56 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +
> > +/*
> > + * Copyright 2017-2020 NXP
> > + */
> > +
> > +#ifndef __DPU_PLANE_H__
> > +#define __DPU_PLANE_H__
> > +
> > +#include <linux/kernel.h>
> > +
> > +#include <drm/drm_device.h>
> > +#include <drm/drm_plane.h>
> > +#include <drm/drm_print.h>
> > +
> > +#include "dpu.h"
> > +
> > +#define dpu_plane_dbg(plane, fmt, ...)					\
> > +	drm_dbg_kms((plane)->dev, "[PLANE:%d:%s] " fmt,			\
> > +		    (plane)->base.id, (plane)->name, ##__VA_ARGS__)
> > +
> > +struct dpu_plane {
> > +	struct drm_plane	base;
> > +	struct dpu_plane_grp	*grp;
> > +};
> > +
> > +union dpu_plane_stage {
> > +	struct dpu_constframe	*cf;
> > +	struct dpu_layerblend	*lb;
> > +	void			*ptr;
> > +};
> > +
> > +struct dpu_plane_state {
> > +	struct drm_plane_state	base;
> > +	union dpu_plane_stage	stage;
> > +	struct dpu_fetchunit	*source;
> > +	struct dpu_layerblend	*blend;
> > +	bool			is_top;
> > +};
> > +
> > +static inline struct dpu_plane *to_dpu_plane(struct drm_plane *plane)
> > +{
> > +	return container_of(plane, struct dpu_plane, base);
> > +}
> > +
> > +static inline struct dpu_plane_state *
> > +to_dpu_plane_state(struct drm_plane_state *plane_state)
> > +{
> > +	return container_of(plane_state, struct dpu_plane_state, base);
> > +}
> > +
> > +struct dpu_plane *dpu_plane_initialize(struct drm_device *drm,
> > +				       unsigned int possible_crtcs,
> > +				       struct dpu_plane_grp *grp,
> > +				       enum drm_plane_type type);
> > +#endif /* __DPU_PLANE_H__ */
> > diff --git a/drivers/gpu/drm/imx/dpu/dpu-prg.c b/drivers/gpu/drm/imx/dpu/dpu-prg.c
> > new file mode 100644
> > index 00000000..33a1a3e
> > --- /dev/null
> > +++ b/drivers/gpu/drm/imx/dpu/dpu-prg.c
> > @@ -0,0 +1,433 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +
> > +/*
> > + * Copyright 2017-2020 NXP
> > + */
> > +
> > +#include <linux/bitops.h>
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_device.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm_runtime.h>
> > +
> > +#include "dpu-prg.h"
> > +
> > +#define SET			0x4
> > +#define CLR			0x8
> > +#define TOG			0xc
> > +
> > +#define PRG_CTRL		0x00
> > +#define  BYPASS			BIT(0)
> > +#define  SC_DATA_TYPE_8BIT	0
> > +#define  SC_DATA_TYPE_10BIT	BIT(2)
> > +#define  UV_EN			BIT(3)
> > +#define  HANDSHAKE_MODE_4LINES	0
> > +#define  HANDSHAKE_MODE_8LINES	BIT(4)
> > +#define  SHADOW_LOAD_MODE	BIT(5)
> > +#define  DES_DATA_TYPE_32BPP	(0 << 16)
> > +#define  DES_DATA_TYPE_24BPP	(1 << 16)
> > +#define  DES_DATA_TYPE_16BPP	(2 << 16)
> > +#define  DES_DATA_TYPE_8BPP	(3 << 16)
> > +#define  SOFTRST		BIT(30)
> > +#define  SHADOW_EN		BIT(31)
> > +
> > +#define PRG_STATUS		0x10
> > +#define  BUFFER_VALID_B		BIT(1)
> > +#define  BUFFER_VALID_A		BIT(0)
> > +
> > +#define PRG_REG_UPDATE		0x20
> > +#define  REG_UPDATE		BIT(0)
> > +
> > +#define PRG_STRIDE		0x30
> > +#define  STRIDE(n)		(((n) - 1) & 0xffff)
> > +
> > +#define PRG_HEIGHT		0x40
> > +#define  HEIGHT(n)		(((n) - 1) & 0xffff)
> > +
> > +#define PRG_BADDR		0x50
> > +
> > +#define PRG_OFFSET		0x60
> > +#define  Y(n)			(((n) & 0x7) << 16)
> > +#define  X(n)			((n) & 0xffff)
> > +
> > +#define PRG_WIDTH		0x70
> > +#define  WIDTH(n)		(((n) - 1) & 0xffff)
> > +
> > +#define DPU_PRG_MAX_STRIDE	0x10000
> > +
> > +struct dpu_prg {
> > +	struct device *dev;
> > +	void __iomem *base;
> > +	struct list_head list;
> > +	struct clk *clk_apb;
> > +	struct clk *clk_rtram;
> > +	bool is_auxiliary;
> > +};
> > +
> > +static DEFINE_MUTEX(dpu_prg_list_mutex);
> > +static LIST_HEAD(dpu_prg_list);
> > +
> > +static inline u32 dpu_prg_read(struct dpu_prg *prg, unsigned int offset)
> > +{
> > +	return readl(prg->base + offset);
> > +}
> > +
> > +static inline void
> > +dpu_prg_write(struct dpu_prg *prg, unsigned int offset, u32 value)
> > +{
> > +	writel(value, prg->base + offset);
> > +}
> > +
> > +static void dpu_prg_reset(struct dpu_prg *prg)
> > +{
> > +	usleep_range(10, 20);
> > +	dpu_prg_write(prg, PRG_CTRL + SET, SOFTRST);
> > +	usleep_range(10, 20);
> > +	dpu_prg_write(prg, PRG_CTRL + CLR, SOFTRST);
> > +}
> > +
> > +void dpu_prg_enable(struct dpu_prg *prg)
> > +{
> > +	dpu_prg_write(prg, PRG_CTRL + CLR, BYPASS);
> > +}
> > +
> > +void dpu_prg_disable(struct dpu_prg *prg)
> > +{
> > +	dpu_prg_write(prg, PRG_CTRL, BYPASS);
> > +}
> > +
> > +static int dpu_prg_mod_to_mt_w(struct dpu_prg *prg, u64 modifier,
> > +			       unsigned int bits_per_pixel, unsigned int *mt_w)
> > +{
> > +	switch (modifier) {
> > +	case DRM_FORMAT_MOD_NONE:
> > +		*mt_w = 0;
> > +		break;
> > +	case DRM_FORMAT_MOD_VIVANTE_TILED:
> > +	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
> > +		*mt_w = (bits_per_pixel == 16) ? 8 : 4;
> > +		break;
> > +	default:
> > +		dev_err(prg->dev, "unsupported modifier 0x%016llx\n", modifier);
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int dpu_prg_mod_to_mt_h(struct dpu_prg *prg, u64 modifier,
> > +			       unsigned int *mt_h)
> > +{
> > +	switch (modifier) {
> > +	case DRM_FORMAT_MOD_NONE:
> > +		*mt_h = 0;
> > +		break;
> > +	case DRM_FORMAT_MOD_VIVANTE_TILED:
> > +	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
> > +		*mt_h = 4;
> > +		break;
> > +	default:
> > +		dev_err(prg->dev, "unsupported modifier 0x%016llx\n", modifier);
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/* address TKT343664: base address has to align to burst size */
> > +static unsigned int dpu_prg_burst_size_fixup(dma_addr_t baddr)
> > +{
> > +	unsigned int burst_size;
> > +
> > +	burst_size = 1 << __ffs(baddr);
> > +	burst_size = round_up(burst_size, 8);
> > +	burst_size = min(burst_size, 128U);
> > +
> > +	return burst_size;
> > +}
> > +
> > +/* address TKT339017: mismatch between burst size and stride */
> > +static unsigned int dpu_prg_stride_fixup(unsigned int stride,
> > +					 unsigned int burst_size,
> > +					 dma_addr_t baddr, u64 modifier)
> > +{
> > +	if (modifier)
> > +		stride = round_up(stride + round_up(baddr % 8, 8), burst_size);
> > +	else
> > +		stride = round_up(stride, burst_size);
> > +
> > +	return stride;
> > +}
> > +
> > +void dpu_prg_configure(struct dpu_prg *prg,
> > +		       unsigned int width, unsigned int height,
> > +		       unsigned int x_offset, unsigned int y_offset,
> > +		       unsigned int stride, unsigned int bits_per_pixel,
> > +		       dma_addr_t baddr,
> > +		       const struct drm_format_info *format, u64 modifier,
> > +		       bool start)
> > +{
> > +	unsigned int mt_w, mt_h;	/* micro-tile width/height */
> > +	unsigned int burst_size;
> > +	dma_addr_t _baddr;
> > +	u32 val;
> > +	int ret;
> > +
> > +	ret = dpu_prg_mod_to_mt_w(prg, modifier, bits_per_pixel, &mt_w);
> > +	ret |= dpu_prg_mod_to_mt_h(prg, modifier, &mt_h);
> > +	if (ret)
> > +		return;
> > +
> > +	if (modifier) {
> > +		x_offset %= mt_w;
> > +		y_offset %= mt_h;
> > +
> > +		/* consider x offset to calculate stride */
> > +		_baddr = baddr + (x_offset * (bits_per_pixel / 8));
> > +	} else {
> > +		x_offset = 0;
> > +		y_offset = 0;
> > +		_baddr = baddr;
> > +	}
> > +
> > +	burst_size = dpu_prg_burst_size_fixup(_baddr);
> > +
> > +	stride = dpu_prg_stride_fixup(stride, burst_size, _baddr, modifier);
> > +
> > +	/*
> > +	 * address TKT342628(part 1):
> > +	 * when prg stride is less or equals to burst size,
> > +	 * the auxiliary prg height needs to be a half
> > +	 */
> > +	if (prg->is_auxiliary && stride <= burst_size) {
> > +		height /= 2;
> > +		if (modifier)
> > +			y_offset /= 2;
> > +	}
> > +
> > +	dpu_prg_write(prg, PRG_STRIDE, STRIDE(stride));
> > +	dpu_prg_write(prg, PRG_WIDTH, WIDTH(width));
> > +	dpu_prg_write(prg, PRG_HEIGHT, HEIGHT(height));
> > +	dpu_prg_write(prg, PRG_OFFSET, X(x_offset) | Y(y_offset));
> > +	dpu_prg_write(prg, PRG_BADDR, baddr);
> > +
> > +	val = SHADOW_LOAD_MODE | SC_DATA_TYPE_8BIT | BYPASS;
> > +	if (format->format == DRM_FORMAT_NV21 ||
> > +	    format->format == DRM_FORMAT_NV12) {
> > +		val |= HANDSHAKE_MODE_8LINES;
> > +		/*
> > +		 * address TKT342628(part 2):
> > +		 * when prg stride is less or equals to burst size,
> > +		 * we disable UV_EN bit for the auxiliary prg
> > +		 */
> > +		if (prg->is_auxiliary && stride > burst_size)
> > +			val |= UV_EN;
> > +	} else {
> > +		val |= HANDSHAKE_MODE_4LINES;
> > +	}
> > +	switch (bits_per_pixel) {
> > +	case 32:
> > +		val |= DES_DATA_TYPE_32BPP;
> > +		break;
> > +	case 24:
> > +		val |= DES_DATA_TYPE_24BPP;
> > +		break;
> > +	case 16:
> > +		val |= DES_DATA_TYPE_16BPP;
> > +		break;
> > +	case 8:
> > +		val |= DES_DATA_TYPE_8BPP;
> > +		break;
> > +	}
> > +	/* no shadow for the first frame */
> > +	if (!start)
> > +		val |= SHADOW_EN;
> > +	dpu_prg_write(prg, PRG_CTRL, val);
> > +}
> > +
> > +void dpu_prg_reg_update(struct dpu_prg *prg)
> > +{
> > +	dpu_prg_write(prg, PRG_REG_UPDATE, REG_UPDATE);
> > +}
> > +
> > +void dpu_prg_shadow_enable(struct dpu_prg *prg)
> > +{
> > +	dpu_prg_write(prg, PRG_CTRL + SET, SHADOW_EN);
> > +}
> > +
> > +bool dpu_prg_stride_supported(struct dpu_prg *prg,
> > +			      unsigned int x_offset,
> > +			      unsigned int bits_per_pixel, u64 modifier,
> > +			      unsigned int stride, dma_addr_t baddr)
> > +{
> > +	unsigned int mt_w;	/* micro-tile width */
> > +	unsigned int burst_size;
> > +	int ret;
> > +
> > +	ret = dpu_prg_mod_to_mt_w(prg, modifier, bits_per_pixel, &mt_w);
> > +	if (ret)
> > +		return false;
> > +
> > +	if (modifier) {
> > +		x_offset %= mt_w;
> > +
> > +		/* consider x offset to calculate stride */
> > +		baddr += (x_offset * (bits_per_pixel / 8));
> > +	}
> > +
> > +	burst_size = dpu_prg_burst_size_fixup(baddr);
> > +
> > +	stride = dpu_prg_stride_fixup(stride, burst_size, baddr, modifier);
> > +
> > +	if (stride > DPU_PRG_MAX_STRIDE)
> > +		return false;
> > +
> > +	return true;
> > +}
> > +
> > +void dpu_prg_set_auxiliary(struct dpu_prg *prg)
> > +{
> > +	prg->is_auxiliary = true;
> > +}
> > +
> > +void dpu_prg_set_primary(struct dpu_prg *prg)
> > +{
> > +	prg->is_auxiliary = false;
> > +}
> > +
> > +struct dpu_prg *
> > +dpu_prg_lookup_by_phandle(struct device *dev, const char *name, int index)
> > +{
> > +	struct device_node *prg_node = of_parse_phandle(dev->of_node,
> > +							name, index);
> > +	struct dpu_prg *prg;
> > +
> > +	mutex_lock(&dpu_prg_list_mutex);
> > +	list_for_each_entry(prg, &dpu_prg_list, list) {
> > +		if (prg_node == prg->dev->of_node) {
> > +			mutex_unlock(&dpu_prg_list_mutex);
> > +			device_link_add(dev, prg->dev,
> > +					DL_FLAG_PM_RUNTIME |
> > +					DL_FLAG_AUTOREMOVE_CONSUMER);
> > +			return prg;
> > +		}
> > +	}
> > +	mutex_unlock(&dpu_prg_list_mutex);
> > +
> > +	return NULL;
> > +}
> > +
> > +static const struct of_device_id dpu_prg_dt_ids[] = {
> > +	{ .compatible = "fsl,imx8qm-prg", },
> > +	{ .compatible = "fsl,imx8qxp-prg", },
> > +	{ /* sentinel */ },
> > +};
> > +
> > +static int dpu_prg_probe(struct platform_device *pdev)
> > +{
> > +	struct device *dev = &pdev->dev;
> > +	struct resource *res;
> > +	struct dpu_prg *prg;
> > +	int ret;
> > +
> > +	prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
> > +	if (!prg)
> > +		return -ENOMEM;
> > +
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	prg->base = devm_ioremap_resource(&pdev->dev, res);
> > +	if (IS_ERR(prg->base))
> > +		return PTR_ERR(prg->base);
> > +
> > +	prg->clk_apb = devm_clk_get(dev, "apb");
> > +	if (IS_ERR(prg->clk_apb)) {
> > +		ret = PTR_ERR(prg->clk_apb);
> > +		dev_err_probe(dev, ret, "failed to get apb clock\n");
> > +		return ret;
> > +	}
> > +
> > +	prg->clk_rtram = devm_clk_get(dev, "rtram");
> > +	if (IS_ERR(prg->clk_rtram)) {
> > +		ret = PTR_ERR(prg->clk_rtram);
> > +		dev_err_probe(dev, ret, "failed to get rtram clock\n");
> > +		return ret;
> > +	}
> > +
> > +	prg->dev = dev;
> > +	platform_set_drvdata(pdev, prg);
> > +
> > +	pm_runtime_enable(dev);
> > +
> > +	mutex_lock(&dpu_prg_list_mutex);
> > +	list_add(&prg->list, &dpu_prg_list);
> > +	mutex_unlock(&dpu_prg_list_mutex);
> > +
> > +	return 0;
> > +}
> > +
> > +static int dpu_prg_remove(struct platform_device *pdev)
> > +{
> > +	struct dpu_prg *prg = platform_get_drvdata(pdev);
> > +
> > +	mutex_lock(&dpu_prg_list_mutex);
> > +	list_del(&prg->list);
> > +	mutex_unlock(&dpu_prg_list_mutex);
> > +
> > +	pm_runtime_disable(&pdev->dev);
> > +
> > +	return 0;
> > +}
> > +
> > +static int __maybe_unused dpu_prg_runtime_suspend(struct device *dev)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct dpu_prg *prg = platform_get_drvdata(pdev);
> > +
> > +	clk_disable_unprepare(prg->clk_rtram);
> > +	clk_disable_unprepare(prg->clk_apb);
> > +
> > +	return 0;
> > +}
> > +
> > +static int __maybe_unused dpu_prg_runtime_resume(struct device *dev)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct dpu_prg *prg = platform_get_drvdata(pdev);
> > +	int ret;
> > +
> > +	ret = clk_prepare_enable(prg->clk_apb);
> > +	if (ret) {
> > +		dev_err(dev, "failed to enable apb clock: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	ret = clk_prepare_enable(prg->clk_rtram);
> > +	if (ret) {
> > +		dev_err(dev, "failed to enable rtramclock: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	dpu_prg_reset(prg);
> > +
> > +	return ret;
> > +}
> > +
> > +static const struct dev_pm_ops dpu_prg_pm_ops = {
> > +	SET_RUNTIME_PM_OPS(dpu_prg_runtime_suspend,
> > +			   dpu_prg_runtime_resume, NULL)
> > +};
> > +
> > +struct platform_driver dpu_prg_driver = {
> > +	.probe = dpu_prg_probe,
> > +	.remove = dpu_prg_remove,
> > +	.driver = {
> > +		.pm = &dpu_prg_pm_ops,
> > +		.name = "dpu-prg",
> > +		.of_match_table = dpu_prg_dt_ids,
> > +	},
> > +};
> > diff --git a/drivers/gpu/drm/imx/dpu/dpu-prg.h b/drivers/gpu/drm/imx/dpu/dpu-prg.h
> > new file mode 100644
> > index 00000000..550e350
> > --- /dev/null
> > +++ b/drivers/gpu/drm/imx/dpu/dpu-prg.h
> > @@ -0,0 +1,45 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +
> > +/*
> > + * Copyright 2017-2020 NXP
> > + */
> > +
> > +#ifndef _DPU_PRG_H_
> > +#define _DPU_PRG_H_
> > +
> > +#include <linux/device.h>
> > +#include <linux/types.h>
> > +
> > +#include <drm/drm_fourcc.h>
> > +
> > +struct dpu_prg;
> > +
> > +void dpu_prg_enable(struct dpu_prg *prg);
> > +
> > +void dpu_prg_disable(struct dpu_prg *prg);
> > +
> > +void dpu_prg_configure(struct dpu_prg *prg,
> > +		       unsigned int width, unsigned int height,
> > +		       unsigned int x_offset, unsigned int y_offset,
> > +		       unsigned int stride, unsigned int bits_per_pixel,
> > +		       dma_addr_t baddr,
> > +		       const struct drm_format_info *format, u64 modifier,
> > +		       bool start);
> > +
> > +void dpu_prg_reg_update(struct dpu_prg *prg);
> > +
> > +void dpu_prg_shadow_enable(struct dpu_prg *prg);
> > +
> > +bool dpu_prg_stride_supported(struct dpu_prg *prg,
> > +			      unsigned int x_offset,
> > +			      unsigned int bits_per_pixel, u64 modifier,
> > +			      unsigned int stride, dma_addr_t baddr);
> > +
> > +void dpu_prg_set_auxiliary(struct dpu_prg *prg);
> > +
> > +void dpu_prg_set_primary(struct dpu_prg *prg);
> > +
> > +struct dpu_prg *
> > +dpu_prg_lookup_by_phandle(struct device *dev, const char *name, int index);
> > +
> > +#endif
> > diff --git a/drivers/gpu/drm/imx/dpu/dpu-prv.h b/drivers/gpu/drm/imx/dpu/dpu-prv.h
> > new file mode 100644
> > index 00000000..8931af7
> > --- /dev/null
> > +++ b/drivers/gpu/drm/imx/dpu/dpu-prv.h
> > @@ -0,0 +1,233 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +
> > +/*
> > + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> > + * Copyright 2017-2020 NXP
> > + */
> > +
> > +#ifndef __DPU_PRV_H__
> > +#define __DPU_PRV_H__
> > +
> > +#include <linux/clk.h>
> > +#include <linux/device.h>
> > +#include <linux/irqdomain.h>
> > +
> > +#include "dpu.h"
> > +
> > +/* DPU common control registers */
> > +#define DPU_COMCTRL_REG(offset)		(offset)
> > +
> > +#define IPIDENTIFIER			DPU_COMCTRL_REG(0x0)
> > +#define LOCKUNLOCK			DPU_COMCTRL_REG(0x40)
> > +#define LOCKSTATUS			DPU_COMCTRL_REG(0x44)
> > +#define USERINTERRUPTMASK(n)		DPU_COMCTRL_REG(0x48 + 4 * (n))
> > +#define INTERRUPTENABLE(n)		DPU_COMCTRL_REG(0x50 + 4 * (n))
> > +#define INTERRUPTPRESET(n)		DPU_COMCTRL_REG(0x58 + 4 * (n))
> > +#define INTERRUPTCLEAR(n)		DPU_COMCTRL_REG(0x60 + 4 * (n))
> > +#define INTERRUPTSTATUS(n)		DPU_COMCTRL_REG(0x68 + 4 * (n))
> > +#define USERINTERRUPTENABLE(n)		DPU_COMCTRL_REG(0x80 + 4 * (n))
> > +#define USERINTERRUPTPRESET(n)		DPU_COMCTRL_REG(0x88 + 4 * (n))
> > +#define USERINTERRUPTCLEAR(n)		DPU_COMCTRL_REG(0x90 + 4 * (n))
> > +#define USERINTERRUPTSTATUS(n)		DPU_COMCTRL_REG(0x98 + 4 * (n))
> > +#define GENERALPURPOSE			DPU_COMCTRL_REG(0x100)
> > +
> > +#define DPU_SAFETY_STREAM_OFFSET	4
> > +
> > +/* shadow enable bit for several DPU units */
> > +#define SHDEN				BIT(0)
> > +
> > +/* Pixel Engine Configuration register fields */
> > +#define CLKEN_MASK_SHIFT		24
> > +#define CLKEN_MASK			(0x3 << CLKEN_MASK_SHIFT)
> > +#define CLKEN(n)			((n) << CLKEN_MASK_SHIFT)
> > +
> > +/* H/Vscaler register fields */
> > +#define SCALE_FACTOR_MASK		0xfffff
> > +#define SCALE_FACTOR(n)			((n) & 0xfffff)
> > +#define PHASE_OFFSET_MASK		0x1fffff
> > +#define PHASE_OFFSET(n)			((n) & 0x1fffff)
> > +#define OUTPUT_SIZE_MASK		0x3fff0000
> > +#define OUTPUT_SIZE(n)			((((n) - 1) << 16) & OUTPUT_SIZE_MASK)
> > +#define FILTER_MODE_MASK		0x100
> > +#define FILTER_MODE(n)			((n) << 8)
> > +#define SCALE_MODE_MASK			0x10
> > +#define SCALE_MODE(n)			((n) << 4)
> > +
> > +enum dpu_irq {
> > +	DPU_IRQ_STORE9_SHDLOAD		 = 0,
> > +	DPU_IRQ_STORE9_FRAMECOMPLETE	 = 1,
> > +	DPU_IRQ_STORE9_SEQCOMPLETE	 = 2,
> > +	DPU_IRQ_EXTDST0_SHDLOAD		 = 3,
> > +	DPU_IRQ_EXTDST0_FRAMECOMPLETE	 = 4,
> > +	DPU_IRQ_EXTDST0_SEQCOMPLETE	 = 5,
> > +	DPU_IRQ_EXTDST4_SHDLOAD		 = 6,
> > +	DPU_IRQ_EXTDST4_FRAMECOMPLETE	 = 7,
> > +	DPU_IRQ_EXTDST4_SEQCOMPLETE	 = 8,
> > +	DPU_IRQ_EXTDST1_SHDLOAD		 = 9,
> > +	DPU_IRQ_EXTDST1_FRAMECOMPLETE	 = 10,
> > +	DPU_IRQ_EXTDST1_SEQCOMPLETE	 = 11,
> > +	DPU_IRQ_EXTDST5_SHDLOAD		 = 12,
> > +	DPU_IRQ_EXTDST5_FRAMECOMPLETE	 = 13,
> > +	DPU_IRQ_EXTDST5_SEQCOMPLETE	 = 14,
> > +	DPU_IRQ_DISENGCFG_SHDLOAD0	 = 15,
> > +	DPU_IRQ_DISENGCFG_FRAMECOMPLETE0 = 16,
> > +	DPU_IRQ_DISENGCFG_SEQCOMPLETE0	 = 17,
> > +	DPU_IRQ_FRAMEGEN0_INT0		 = 18,
> > +	DPU_IRQ_FRAMEGEN0_INT1		 = 19,
> > +	DPU_IRQ_FRAMEGEN0_INT2		 = 20,
> > +	DPU_IRQ_FRAMEGEN0_INT3		 = 21,
> > +	DPU_IRQ_SIG0_SHDLOAD		 = 22,
> > +	DPU_IRQ_SIG0_VALID		 = 23,
> > +	DPU_IRQ_SIG0_ERROR		 = 24,
> > +	DPU_IRQ_DISENGCFG_SHDLOAD1	 = 25,
> > +	DPU_IRQ_DISENGCFG_FRAMECOMPLETE1 = 26,
> > +	DPU_IRQ_DISENGCFG_SEQCOMPLETE1	 = 27,
> > +	DPU_IRQ_FRAMEGEN1_INT0		 = 28,
> > +	DPU_IRQ_FRAMEGEN1_INT1		 = 29,
> > +	DPU_IRQ_FRAMEGEN1_INT2		 = 30,
> > +	DPU_IRQ_FRAMEGEN1_INT3		 = 31,
> > +	DPU_IRQ_SIG1_SHDLOAD		 = 32,
> > +	DPU_IRQ_SIG1_VALID		 = 33,
> > +	DPU_IRQ_SIG1_ERROR		 = 34,
> > +	DPU_IRQ_RESERVED		 = 35,
> > +	DPU_IRQ_CMDSEQ_ERROR		 = 36,
> > +	DPU_IRQ_COMCTRL_SW0		 = 37,
> > +	DPU_IRQ_COMCTRL_SW1		 = 38,
> > +	DPU_IRQ_COMCTRL_SW2		 = 39,
> > +	DPU_IRQ_COMCTRL_SW3		 = 40,
> > +	DPU_IRQ_FRAMEGEN0_PRIMSYNC_ON	 = 41,
> > +	DPU_IRQ_FRAMEGEN0_PRIMSYNC_OFF	 = 42,
> > +	DPU_IRQ_FRAMEGEN0_SECSYNC_ON	 = 43,
> > +	DPU_IRQ_FRAMEGEN0_SECSYNC_OFF	 = 44,
> > +	DPU_IRQ_FRAMEGEN1_PRIMSYNC_ON	 = 45,
> > +	DPU_IRQ_FRAMEGEN1_PRIMSYNC_OFF	 = 46,
> > +	DPU_IRQ_FRAMEGEN1_SECSYNC_ON	 = 47,
> > +	DPU_IRQ_FRAMEGEN1_SECSYNC_OFF	 = 48,
> > +	DPU_IRQ_COUNT			 = 49,
> > +};
> > +
> > +enum dpu_unit_type {
> > +	DPU_DISP,
> > +	DPU_BLIT,
> > +};
> > +
> > +struct dpu_soc {
> > +	struct device		*dev;
> > +
> > +	struct device		*pd_dc_dev;
> > +	struct device		*pd_pll0_dev;
> > +	struct device		*pd_pll1_dev;
> > +	struct device_link	*pd_dc_link;
> > +	struct device_link	*pd_pll0_link;
> > +	struct device_link	*pd_pll1_link;
> > +
> > +	void __iomem		*comctrl_reg;
> > +
> > +	struct clk		*clk_cfg;
> > +	struct clk		*clk_axi;
> > +
> > +	int			id;
> > +
> > +	int			irq[DPU_IRQ_COUNT];
> > +
> > +	struct irq_domain	*domain;
> > +
> > +	struct dpu_constframe	*cf_priv[4];
> > +	struct dpu_disengcfg	*dec_priv[2];
> > +	struct dpu_extdst	*ed_priv[4];
> > +	struct dpu_fetchunit	*fd_priv[3];
> > +	struct dpu_fetchunit	*fe_priv[4];
> > +	struct dpu_framegen	*fg_priv[2];
> > +	struct dpu_fetchunit	*fl_priv[1];
> > +	struct dpu_fetchunit	*fw_priv[2];
> > +	struct dpu_gammacor	*gc_priv[2];
> > +	struct dpu_hscaler	*hs_priv[3];
> > +	struct dpu_layerblend	*lb_priv[4];
> > +	struct dpu_tcon		*tcon_priv[2];
> > +	struct dpu_vscaler	*vs_priv[3];
> > +};
> > +
> > +struct dpu_units {
> > +	const unsigned int *ids;
> > +	const enum dpu_unit_type *types;
> > +	const unsigned long *ofss;
> > +	const unsigned long *pec_ofss;	/* Pixel Engine Configuration */
> > +	const unsigned int cnt;
> > +	const char *name;
> > +
> > +	/* software initialization */
> > +	int (*init)(struct dpu_soc *dpu, unsigned int index,
> > +		    unsigned int id, enum dpu_unit_type type,
> > +		    unsigned long pec_base, unsigned long base);
> > +
> > +	/* hardware initialization */
> > +	void (*hw_init)(struct dpu_soc *dpu, unsigned int index);
> > +};
> > +
> > +void dpu_cf_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_dec_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_ed_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_fd_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_fe_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_fg_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_fl_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_fw_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_gc_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_hs_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_lb_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_tcon_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +void dpu_vs_hw_init(struct dpu_soc *dpu, unsigned int index);
> > +
> > +int dpu_cf_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long pec_base, unsigned long base);
> > +
> > +int dpu_dec_init(struct dpu_soc *dpu, unsigned int index,
> > +		 unsigned int id, enum dpu_unit_type type,
> > +		 unsigned long unused, unsigned long base);
> > +
> > +int dpu_ed_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long pec_base, unsigned long base);
> > +
> > +int dpu_fd_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long pec_base, unsigned long base);
> > +
> > +int dpu_fe_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long pec_base, unsigned long base);
> > +
> > +int dpu_fg_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long unused, unsigned long base);
> > +
> > +int dpu_fl_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long pec_base, unsigned long base);
> > +
> > +int dpu_fw_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long pec_base, unsigned long base);
> > +
> > +int dpu_gc_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long unused, unsigned long base);
> > +
> > +int dpu_hs_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long pec_base, unsigned long base);
> > +
> > +int dpu_lb_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long pec_base, unsigned long base);
> > +
> > +int dpu_tcon_init(struct dpu_soc *dpu, unsigned int index,
> > +		  unsigned int id, enum dpu_unit_type type,
> > +		  unsigned long unused, unsigned long base);
> > +
> > +int dpu_vs_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long pec_base, unsigned long base);
> > +
> > +#endif /* __DPU_PRV_H__ */
> > diff --git a/drivers/gpu/drm/imx/dpu/dpu-tcon.c b/drivers/gpu/drm/imx/dpu/dpu-tcon.c
> > new file mode 100644
> > index 00000000..143f51f
> > --- /dev/null
> > +++ b/drivers/gpu/drm/imx/dpu/dpu-tcon.c
> > @@ -0,0 +1,250 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +
> > +/*
> > + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> > + * Copyright 2017-2020 NXP
> > + */
> > +
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mutex.h>
> > +#include <linux/sizes.h>
> > +
> > +#include "dpu.h"
> > +#include "dpu-prv.h"
> > +
> > +#define SSQCNTS			0x0
> > +#define SSQCYCLE		0x408
> > +#define SWRESET			0x40c
> > +
> > +#define TCON_CTRL		0x410
> > +#define  CTRL_RST_VAL		0x01401408
> > +#define  BYPASS			BIT(3)
> > +
> > +#define RSDSINVCTRL		0x414
> > +
> > +/* red: MAPBIT 29-20, green: MAPBIT 19-10, blue: MAPBIT 9-0 */
> > +#define MAPBIT3_0		0x418
> > +#define MAPBIT7_4		0x41c
> > +#define MAPBIT11_8		0x420
> > +#define MAPBIT15_12		0x424
> > +#define MAPBIT19_16		0x428
> > +#define MAPBIT23_20		0x42c
> > +#define MAPBIT27_24		0x430
> > +#define MAPBIT31_28		0x434
> > +#define MAPBIT34_32		0x438
> > +#define MAPBIT3_0_DUAL		0x43c
> > +#define MAPBIT7_4_DUAL		0x440
> > +#define MAPBIT11_8_DUAL		0x444
> > +#define MAPBIT15_12_DUAL	0x448
> > +#define MAPBIT19_16_DUAL	0x44c
> > +#define MAPBIT23_20_DUAL	0x450
> > +#define MAPBIT27_24_DUAL	0x454
> > +#define MAPBIT31_28_DUAL	0x458
> > +#define MAPBIT34_32_DUAL	0x45c
> > +
> > +#define SPGPOSON(n)		(0x460 + (n) * 16)
> > +#define SPGMASKON(n)		(0x464 + (n) * 16)
> > +#define SPGPOSOFF(n)		(0x468 + (n) * 16)
> > +#define SPGMASKOFF(n)		(0x46c + (n) * 16)
> > +#define  X(n)			(((n) & 0x7fff) << 16)
> > +#define  Y(n)			((n) & 0x7fff)
> > +
> > +#define SMXSIGS(n)		(0x520 + (n) * 8)
> > +#define SMXFCTTABLE(n)		(0x524 + (n) * 8)
> > +#define RESET_OVER_UNFERFLOW	0x580
> > +#define DUAL_DEBUG		0x584
> > +
> > +struct dpu_tcon {
> > +	void __iomem *base;
> > +	struct mutex mutex;
> > +	unsigned int id;
> > +	unsigned int index;
> > +	bool inuse;
> > +	struct dpu_soc *dpu;
> > +};
> > +
> > +static inline u32 dpu_tcon_read(struct dpu_tcon *tcon, unsigned int offset)
> > +{
> > +	return readl(tcon->base + offset);
> > +}
> > +
> > +static inline void dpu_tcon_write(struct dpu_tcon *tcon,
> > +				  unsigned int offset, u32 value)
> > +{
> > +	writel(value, tcon->base + offset);
> > +}
> > +
> > +static inline void dpu_tcon_write_mask(struct dpu_tcon *tcon,
> > +				       unsigned int offset, u32 mask, u32 value)
> > +{
> > +	u32 tmp;
> > +
> > +	tmp = dpu_tcon_read(tcon, offset);
> > +	tmp &= ~mask;
> > +	dpu_tcon_write(tcon, offset, tmp | value);
> > +}
> > +
> > +void dpu_tcon_set_fmt(struct dpu_tcon *tcon)
> > +{
> > +	/*
> > +	 * The pixels reach TCON are always in 30-bit BGR format.
> > +	 * The first bridge always receives pixels in 30-bit RGB format.
> > +	 * So, map the format to MEDIA_BUS_FMT_RGB101010_1X30.
> > +	 */
> > +	dpu_tcon_write(tcon, MAPBIT3_0,   0x17161514);
> > +	dpu_tcon_write(tcon, MAPBIT7_4,   0x1b1a1918);
> > +	dpu_tcon_write(tcon, MAPBIT11_8,  0x0b0a1d1c);
> > +	dpu_tcon_write(tcon, MAPBIT15_12, 0x0f0e0d0c);
> > +	dpu_tcon_write(tcon, MAPBIT19_16, 0x13121110);
> > +	dpu_tcon_write(tcon, MAPBIT23_20, 0x03020100);
> > +	dpu_tcon_write(tcon, MAPBIT27_24, 0x07060504);
> > +	dpu_tcon_write(tcon, MAPBIT31_28, 0x00000908);
> > +}
> > +
> > +void dpu_tcon_set_operation_mode(struct dpu_tcon *tcon)
> > +{
> > +	dpu_tcon_write_mask(tcon, TCON_CTRL, BYPASS, 0);
> > +}
> > +
> > +void dpu_tcon_cfg_videomode(struct dpu_tcon *tcon, struct drm_display_mode *m)
> > +{
> > +	int hdisplay, hsync_start, hsync_end;
> > +	int vdisplay, vsync_start, vsync_end;
> > +	int y;
> > +
> > +	hdisplay = m->hdisplay;
> > +	vdisplay = m->vdisplay;
> > +	hsync_start = m->hsync_start;
> > +	vsync_start = m->vsync_start;
> > +	hsync_end = m->hsync_end;
> > +	vsync_end = m->vsync_end;
> > +
> > +	/*
> > +	 * TKT320590:
> > +	 * Turn TCON into operation mode later after the first dumb frame is
> > +	 * generated by DPU.  This makes DPR/PRG be able to evade the frame.
> > +	 */
> > +	dpu_tcon_write_mask(tcon, TCON_CTRL, BYPASS, BYPASS);
> > +
> > +	/* dsp_control[0]: hsync */
> > +	dpu_tcon_write(tcon, SPGPOSON(0), X(hsync_start));
> > +	dpu_tcon_write(tcon, SPGMASKON(0), 0xffff);
> > +
> > +	dpu_tcon_write(tcon, SPGPOSOFF(0), X(hsync_end));
> > +	dpu_tcon_write(tcon, SPGMASKOFF(0), 0xffff);
> > +
> > +	dpu_tcon_write(tcon, SMXSIGS(0), 0x2);
> > +	dpu_tcon_write(tcon, SMXFCTTABLE(0), 0x1);
> > +
> > +	/* dsp_control[1]: vsync */
> > +	dpu_tcon_write(tcon, SPGPOSON(1), X(hsync_start) | Y(vsync_start - 1));
> > +	dpu_tcon_write(tcon, SPGMASKON(1), 0x0);
> > +
> > +	dpu_tcon_write(tcon, SPGPOSOFF(1), X(hsync_start) | Y(vsync_end - 1));
> > +	dpu_tcon_write(tcon, SPGMASKOFF(1), 0x0);
> > +
> > +	dpu_tcon_write(tcon, SMXSIGS(1), 0x3);
> > +	dpu_tcon_write(tcon, SMXFCTTABLE(1), 0x1);
> > +
> > +	/* dsp_control[2]: data enable */
> > +	/* horizontal */
> > +	dpu_tcon_write(tcon, SPGPOSON(2), 0x0);
> > +	dpu_tcon_write(tcon, SPGMASKON(2), 0xffff);
> > +
> > +	dpu_tcon_write(tcon, SPGPOSOFF(2), X(hdisplay));
> > +	dpu_tcon_write(tcon, SPGMASKOFF(2), 0xffff);
> > +
> > +	/* vertical */
> > +	dpu_tcon_write(tcon, SPGPOSON(3), 0x0);
> > +	dpu_tcon_write(tcon, SPGMASKON(3), 0x7fff0000);
> > +
> > +	dpu_tcon_write(tcon, SPGPOSOFF(3), Y(vdisplay));
> > +	dpu_tcon_write(tcon, SPGMASKOFF(3), 0x7fff0000);
> > +
> > +	dpu_tcon_write(tcon, SMXSIGS(2), 0x2c);
> > +	dpu_tcon_write(tcon, SMXFCTTABLE(2), 0x8);
> > +
> > +	/* dsp_control[3]: kachuck */
> > +	y = vdisplay + 1;
> > +
> > +	dpu_tcon_write(tcon, SPGPOSON(4), X(0x0) | Y(y));
> > +	dpu_tcon_write(tcon, SPGMASKON(4), 0x0);
> > +
> > +	dpu_tcon_write(tcon, SPGPOSOFF(4), X(0x20) | Y(y));
> > +	dpu_tcon_write(tcon, SPGMASKOFF(4), 0x0);
> > +
> > +	dpu_tcon_write(tcon, SMXSIGS(3), 0x6);
> > +	dpu_tcon_write(tcon, SMXFCTTABLE(3), 0x2);
> > +}
> > +
> > +struct dpu_tcon *dpu_tcon_get(struct dpu_soc *dpu, unsigned int id)
> > +{
> > +	struct dpu_tcon *tcon;
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(dpu->tcon_priv); i++) {
> > +		tcon = dpu->tcon_priv[i];
> > +		if (tcon->id == id)
> > +			break;
> > +	}
> > +
> > +	if (i == ARRAY_SIZE(dpu->tcon_priv))
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	mutex_lock(&tcon->mutex);
> > +
> > +	if (tcon->inuse) {
> > +		mutex_unlock(&tcon->mutex);
> > +		return ERR_PTR(-EBUSY);
> > +	}
> > +
> > +	tcon->inuse = true;
> > +
> > +	mutex_unlock(&tcon->mutex);
> > +
> > +	return tcon;
> > +}
> > +
> > +void dpu_tcon_put(struct dpu_tcon *tcon)
> > +{
> > +	if (IS_ERR_OR_NULL(tcon))
> > +		return;
> > +
> > +	mutex_lock(&tcon->mutex);
> > +
> > +	tcon->inuse = false;
> > +
> > +	mutex_unlock(&tcon->mutex);
> > +}
> > +
> > +void dpu_tcon_hw_init(struct dpu_soc *dpu, unsigned int index)
> > +{
> > +	/* reset TCON_CTRL to POR default so that TCON works in bypass mode */
> > +	dpu_tcon_write(dpu->tcon_priv[index], TCON_CTRL, CTRL_RST_VAL);
> > +}
> > +
> > +int dpu_tcon_init(struct dpu_soc *dpu, unsigned int index,
> > +		  unsigned int id, enum dpu_unit_type type,
> > +		  unsigned long unused, unsigned long base)
> > +{
> > +	struct dpu_tcon *tcon;
> > +
> > +	tcon = devm_kzalloc(dpu->dev, sizeof(*tcon), GFP_KERNEL);
> > +	if (!tcon)
> > +		return -ENOMEM;
> > +
> > +	dpu->tcon_priv[index] = tcon;
> > +
> > +	tcon->base = devm_ioremap(dpu->dev, base, SZ_2K);
> > +	if (!tcon->base)
> > +		return -ENOMEM;
> > +
> > +	tcon->dpu = dpu;
> > +	tcon->id = id;
> > +	tcon->index = index;
> > +
> > +	mutex_init(&tcon->mutex);
> > +
> > +	return 0;
> > +}
> > diff --git a/drivers/gpu/drm/imx/dpu/dpu-vscaler.c b/drivers/gpu/drm/imx/dpu/dpu-vscaler.c
> > new file mode 100644
> > index 00000000..bdef0cd
> > --- /dev/null
> > +++ b/drivers/gpu/drm/imx/dpu/dpu-vscaler.c
> > @@ -0,0 +1,308 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +
> > +/*
> > + * Copyright 2017-2020 NXP
> > + */
> > +
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mutex.h>
> > +#include <linux/sizes.h>
> > +
> > +#include "dpu.h"
> > +#include "dpu-prv.h"
> > +
> > +#define PIXENGCFG_DYNAMIC		0x8
> > +#define  PIXENGCFG_DYNAMIC_SRC_SEL_MASK	0x3f
> > +
> > +#define STATICCONTROL			0x8
> > +
> > +#define SETUP(n)			(0xc + ((n) - 1) * 0x4)
> > +
> > +#define CONTROL				0x20
> > +#define  FIELD_MODE_MASK		0x3000
> > +#define  FIELD_MODE(n)			((n) << 12)
> > +#define  CTRL_MODE_MASK			BIT(0)
> > +
> > +struct dpu_vscaler {
> > +	void __iomem *pec_base;
> > +	void __iomem *base;
> > +	struct mutex mutex;
> > +	unsigned int id;
> > +	unsigned int index;
> > +	enum dpu_link_id link_id;
> > +	bool inuse;
> > +	struct dpu_soc *dpu;
> > +};
> > +
> > +static const enum dpu_link_id dpu_vs_link_id[] = {
> > +	LINK_ID_VSCALER4, LINK_ID_VSCALER5, LINK_ID_VSCALER9
> > +};
> > +
> > +static const enum dpu_link_id src_sels[3][4] = {
> > +	{
> > +		LINK_ID_NONE,
> > +		LINK_ID_FETCHDECODE0,
> > +		LINK_ID_MATRIX4,
> > +		LINK_ID_HSCALER4,
> > +	}, {
> > +		LINK_ID_NONE,
> > +		LINK_ID_FETCHDECODE1,
> > +		LINK_ID_MATRIX5,
> > +		LINK_ID_HSCALER5,
> > +	}, {
> > +		LINK_ID_NONE,
> > +		LINK_ID_MATRIX9,
> > +		LINK_ID_HSCALER9,
> > +	},
> > +};
> > +
> > +static inline u32 dpu_pec_vs_read(struct dpu_vscaler *vs,
> > +				  unsigned int offset)
> > +{
> > +	return readl(vs->pec_base + offset);
> > +}
> > +
> > +static inline void dpu_pec_vs_write(struct dpu_vscaler *vs,
> > +				    unsigned int offset, u32 value)
> > +{
> > +	writel(value, vs->pec_base + offset);
> > +}
> > +
> > +static inline void dpu_pec_vs_write_mask(struct dpu_vscaler *vs,
> > +					 unsigned int offset,
> > +					 u32 mask, u32 value)
> > +{
> > +	u32 tmp;
> > +
> > +	tmp = dpu_pec_vs_read(vs, offset);
> > +	tmp &= ~mask;
> > +	dpu_pec_vs_write(vs, offset, tmp | value);
> > +}
> > +
> > +static inline u32 dpu_vs_read(struct dpu_vscaler *vs, unsigned int offset)
> > +{
> > +	return readl(vs->base + offset);
> > +}
> > +
> > +static inline void dpu_vs_write(struct dpu_vscaler *vs,
> > +				unsigned int offset, u32 value)
> > +{
> > +	writel(value, vs->base + offset);
> > +}
> > +
> > +static inline void dpu_vs_write_mask(struct dpu_vscaler *vs,
> > +				     unsigned int offset, u32 mask, u32 value)
> > +{
> > +	u32 tmp;
> > +
> > +	tmp = dpu_vs_read(vs, offset);
> > +	tmp &= ~mask;
> > +	dpu_vs_write(vs, offset, tmp | value);
> > +}
> > +
> > +enum dpu_link_id dpu_vs_get_link_id(struct dpu_vscaler *vs)
> > +{
> > +	return vs->link_id;
> > +}
> > +
> > +void dpu_vs_pec_dynamic_src_sel(struct dpu_vscaler *vs, enum dpu_link_id src)
> > +{
> > +	struct dpu_soc *dpu = vs->dpu;
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(src_sels[vs->index]); i++) {
> > +		if (src_sels[vs->index][i] == src) {
> > +			dpu_pec_vs_write_mask(vs, PIXENGCFG_DYNAMIC,
> > +					      PIXENGCFG_DYNAMIC_SRC_SEL_MASK,
> > +					      src);
> > +			return;
> > +		}
> > +	}
> > +
> > +	dev_err(dpu->dev, "VScaler%u - invalid source 0x%02x\n", vs->id, src);
> > +}
> > +
> > +void dpu_vs_pec_clken(struct dpu_vscaler *vs, enum dpu_pec_clken clken)
> > +{
> > +	dpu_pec_vs_write_mask(vs, PIXENGCFG_DYNAMIC, CLKEN_MASK, CLKEN(clken));
> > +}
> > +
> > +static void dpu_vs_enable_shden(struct dpu_vscaler *vs)
> > +{
> > +	dpu_vs_write_mask(vs, STATICCONTROL, SHDEN, SHDEN);
> > +}
> > +
> > +void dpu_vs_setup1(struct dpu_vscaler *vs,
> > +		   unsigned int src_w, unsigned int dst_w, bool deinterlace)
> > +{
> > +	struct dpu_soc *dpu = vs->dpu;
> > +	u32 scale_factor;
> > +	u64 tmp64;
> > +
> > +	if (deinterlace)
> > +		dst_w *= 2;
> > +
> > +	if (src_w == dst_w) {
> > +		scale_factor = 0x80000;
> > +	} else {
> > +		if (src_w > dst_w) {
> > +			tmp64 = (u64)((u64)dst_w * 0x80000);
> > +			do_div(tmp64, src_w);
> > +
> > +		} else {
> > +			tmp64 = (u64)((u64)src_w * 0x80000);
> > +			do_div(tmp64, dst_w);
> > +		}
> > +		scale_factor = (u32)tmp64;
> > +	}
> > +
> > +	if (scale_factor > 0x80000) {
> > +		dev_err(dpu->dev, "VScaler%u - invalid scale factor 0x%08x\n",
> > +							vs->id, scale_factor);
> > +		return;
> > +	}
> > +
> > +	dpu_vs_write(vs, SETUP(1), SCALE_FACTOR(scale_factor));
> > +
> > +	dev_dbg(dpu->dev, "VScaler%u - scale factor 0x%08x\n",
> > +							vs->id, scale_factor);
> > +}
> > +
> > +void dpu_vs_setup2(struct dpu_vscaler *vs, bool deinterlace)
> > +{
> > +	/* 0x20000: +0.25 phase offset for deinterlace */
> > +	u32 phase_offset = deinterlace ? 0x20000 : 0;
> > +
> > +	dpu_vs_write(vs, SETUP(2), PHASE_OFFSET(phase_offset));
> > +}
> > +
> > +void dpu_vs_setup3(struct dpu_vscaler *vs, bool deinterlace)
> > +{
> > +	/* 0x1e0000: -0.25 phase offset for deinterlace */
> > +	u32 phase_offset = deinterlace ? 0x1e0000 : 0;
> > +
> > +	dpu_vs_write(vs, SETUP(3), PHASE_OFFSET(phase_offset));
> > +}
> > +
> > +void dpu_vs_setup4(struct dpu_vscaler *vs, u32 phase_offset)
> > +{
> > +	dpu_vs_write(vs, SETUP(4), PHASE_OFFSET(phase_offset));
> > +}
> > +
> > +void dpu_vs_setup5(struct dpu_vscaler *vs, u32 phase_offset)
> > +{
> > +	dpu_vs_write(vs, SETUP(5), PHASE_OFFSET(phase_offset));
> > +}
> > +
> > +void dpu_vs_output_size(struct dpu_vscaler *vs, u32 line_num)
> > +{
> > +	dpu_vs_write_mask(vs, CONTROL, OUTPUT_SIZE_MASK, OUTPUT_SIZE(line_num));
> > +}
> > +
> > +void dpu_vs_field_mode(struct dpu_vscaler *vs, enum dpu_scaler_field_mode m)
> > +{
> > +	dpu_vs_write_mask(vs, CONTROL, FIELD_MODE_MASK, FIELD_MODE(m));
> > +}
> > +
> > +void dpu_vs_filter_mode(struct dpu_vscaler *vs, enum dpu_scaler_filter_mode m)
> > +{
> > +	dpu_vs_write_mask(vs, CONTROL, FILTER_MODE_MASK, FILTER_MODE(m));
> > +}
> > +
> > +void dpu_vs_scale_mode(struct dpu_vscaler *vs, enum dpu_scaler_scale_mode m)
> > +{
> > +	dpu_vs_write_mask(vs, CONTROL, SCALE_MODE_MASK, SCALE_MODE(m));
> > +}
> > +
> > +void dpu_vs_mode(struct dpu_vscaler *vs, enum dpu_scaler_mode m)
> > +{
> > +	dpu_vs_write_mask(vs, CONTROL, CTRL_MODE_MASK, m);
> > +}
> > +
> > +unsigned int dpu_vs_get_id(struct dpu_vscaler *vs)
> > +{
> > +	return vs->id;
> > +}
> > +
> > +struct dpu_vscaler *dpu_vs_get(struct dpu_soc *dpu, unsigned int id)
> > +{
> > +	struct dpu_vscaler *vs;
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(dpu->vs_priv); i++) {
> > +		vs = dpu->vs_priv[i];
> > +		if (vs->id == id)
> > +			break;
> > +	}
> > +
> > +	if (i == ARRAY_SIZE(dpu->vs_priv))
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	mutex_lock(&vs->mutex);
> > +
> > +	if (vs->inuse) {
> > +		mutex_unlock(&vs->mutex);
> > +		return ERR_PTR(-EBUSY);
> > +	}
> > +
> > +	vs->inuse = true;
> > +
> > +	mutex_unlock(&vs->mutex);
> > +
> > +	return vs;
> > +}
> > +
> > +void dpu_vs_put(struct dpu_vscaler *vs)
> > +{
> > +	if (IS_ERR_OR_NULL(vs))
> > +		return;
> > +
> > +	mutex_lock(&vs->mutex);
> > +
> > +	vs->inuse = false;
> > +
> > +	mutex_unlock(&vs->mutex);
> > +}
> > +
> > +void dpu_vs_hw_init(struct dpu_soc *dpu, unsigned int index)
> > +{
> > +	struct dpu_vscaler *vs = dpu->vs_priv[index];
> > +
> > +	dpu_vs_enable_shden(vs);
> > +	dpu_vs_setup2(vs, false);
> > +	dpu_vs_setup3(vs, false);
> > +	dpu_vs_setup4(vs, 0);
> > +	dpu_vs_setup5(vs, 0);
> > +	dpu_vs_pec_dynamic_src_sel(vs, LINK_ID_NONE);
> > +}
> > +
> > +int dpu_vs_init(struct dpu_soc *dpu, unsigned int index,
> > +		unsigned int id, enum dpu_unit_type type,
> > +		unsigned long pec_base, unsigned long base)
> > +{
> > +	struct dpu_vscaler *vs;
> > +
> > +	vs = devm_kzalloc(dpu->dev, sizeof(*vs), GFP_KERNEL);
> > +	if (!vs)
> > +		return -ENOMEM;
> > +
> > +	dpu->vs_priv[index] = vs;
> > +
> > +	vs->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
> > +	if (!vs->pec_base)
> > +		return -ENOMEM;
> > +
> > +	vs->base = devm_ioremap(dpu->dev, base, SZ_32);
> > +	if (!vs->base)
> > +		return -ENOMEM;
> > +
> > +	vs->dpu = dpu;
> > +	vs->id = id;
> > +	vs->index = index;
> > +	vs->link_id = dpu_vs_link_id[index];
> > +
> > +	mutex_init(&vs->mutex);
> > +
> > +	return 0;
> > +}
> > diff --git a/drivers/gpu/drm/imx/dpu/dpu.h b/drivers/gpu/drm/imx/dpu/dpu.h
> > new file mode 100644
> > index 00000000..ef012e2
> > --- /dev/null
> > +++ b/drivers/gpu/drm/imx/dpu/dpu.h
> > @@ -0,0 +1,385 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +
> > +/*
> > + * Copyright (C) 2016 Freescale Semiconductor, Inc.
> > + * Copyright 2017-2020 NXP
> > + */
> > +
> > +#ifndef __DPU_H__
> > +#define __DPU_H__
> > +
> > +#include <linux/of.h>
> > +#include <linux/types.h>
> > +
> > +#include <drm/drm_color_mgmt.h>
> > +#include <drm/drm_fourcc.h>
> > +#include <drm/drm_modes.h>
> > +
> > +#define DPU_FRAMEGEN_MAX_FRAME_INDEX	0x3ffff
> > +#define DPU_FRAMEGEN_MAX_CLOCK		300000	/* in KHz */
> > +
> > +#define DPU_FETCHUNIT_CAP_USE_FETCHECO	BIT(0)
> > +#define DPU_FETCHUNIT_CAP_USE_SCALER	BIT(1)
> > +#define DPU_FETCHUNIT_CAP_PACKED_YUV422	BIT(2)
> > +
> > +struct dpu_dprc;
> > +struct dpu_fetchunit;
> > +struct dpu_soc;
> > +
> > +enum dpu_link_id {
> > +	LINK_ID_NONE		= 0x00,
> > +	LINK_ID_FETCHDECODE9	= 0x01,
> > +	LINK_ID_FETCHWARP9	= 0x02,
> > +	LINK_ID_FETCHECO9	= 0x03,
> > +	LINK_ID_ROP9		= 0x04,
> > +	LINK_ID_CLUT9		= 0x05,
> > +	LINK_ID_MATRIX9		= 0x06,
> > +	LINK_ID_HSCALER9	= 0x07,
> > +	LINK_ID_VSCALER9	= 0x08,
> > +	LINK_ID_FILTER9		= 0x09,
> > +	LINK_ID_BLITBLEND9	= 0x0a,
> > +	LINK_ID_CONSTFRAME0	= 0x0c,
> > +	LINK_ID_CONSTFRAME4	= 0x0e,
> > +	LINK_ID_CONSTFRAME1	= 0x10,
> > +	LINK_ID_CONSTFRAME5	= 0x12,
> > +	LINK_ID_FETCHWARP2	= 0x14,
> > +	LINK_ID_FETCHECO2	= 0x15,
> > +	LINK_ID_FETCHDECODE0	= 0x16,
> > +	LINK_ID_FETCHECO0	= 0x17,
> > +	LINK_ID_FETCHDECODE1	= 0x18,
> > +	LINK_ID_FETCHECO1	= 0x19,
> > +	LINK_ID_FETCHLAYER0	= 0x1a,
> > +	LINK_ID_MATRIX4		= 0x1b,
> > +	LINK_ID_HSCALER4	= 0x1c,
> > +	LINK_ID_VSCALER4	= 0x1d,
> > +	LINK_ID_MATRIX5		= 0x1e,
> > +	LINK_ID_HSCALER5	= 0x1f,
> > +	LINK_ID_VSCALER5	= 0x20,
> > +	LINK_ID_LAYERBLEND0	= 0x21,
> > +	LINK_ID_LAYERBLEND1	= 0x22,
> > +	LINK_ID_LAYERBLEND2	= 0x23,
> > +	LINK_ID_LAYERBLEND3	= 0x24,
> > +};
> > +
> > +enum dpu_fg_syncmode {
> > +	FG_SYNCMODE_OFF,	/* No side-by-side synchronization. */
> > +	FG_SYNCMODE_MASTER,	/* Framegen is master. */
> > +	FG_SYNCMODE_SLAVE_CYC,	/* Runs in cyclic synchronization mode. */
> > +	FG_SYNCMODE_SLAVE_ONCE,	/* Runs in one time synchronization mode. */
> > +};
> > +
> > +enum dpu_fg_dm {
> > +	FG_DM_BLACK,
> > +	FG_DM_CONSTCOL,	/* Constant Color Background is shown. */
> > +	FG_DM_PRIM,
> > +	FG_DM_SEC,
> > +	FG_DM_PRIM_ON_TOP,
> > +	FG_DM_SEC_ON_TOP,
> > +	FG_DM_TEST,	/* White color background with test pattern is shown. */
> > +};
> > +
> > +enum dpu_gc_mode {
> > +	GC_NEUTRAL,	/* Input data is bypassed to the output. */
> > +	GC_GAMMACOR,
> > +};
> > +
> > +enum dpu_lb_mode {
> > +	LB_NEUTRAL,	/* Output is same as primary input. */
> > +	LB_BLEND,
> > +};
> > +
> > +enum dpu_scaler_field_mode {
> > +	/* Constant 0 indicates frame or top field. */
> > +	SCALER_ALWAYS0,
> > +	/* Constant 1 indicates bottom field. */
> > +	SCALER_ALWAYS1,
> > +	/* Output field polarity is taken from input field polarity. */
> > +	SCALER_INPUT,
> > +	/* Output field polarity toggles, starting with 0 after reset. */
> > +	SCALER_TOGGLE,
> > +};
> > +
> > +enum dpu_scaler_filter_mode {
> > +	SCALER_NEAREST,	/* pointer-sampling */
> > +	SCALER_LINEAR,	/* box filter */
> > +};
> > +
> > +enum dpu_scaler_scale_mode {
> > +	SCALER_DOWNSCALE,
> > +	SCALER_UPSCALE,
> > +};
> > +
> > +enum dpu_scaler_mode {
> > +	/* Pixel by-pass the scaler, all other settings are ignored. */
> > +	SCALER_NEUTRAL,
> > +	/* Scaler is active. */
> > +	SCALER_ACTIVE,
> > +};
> > +
> > +enum dpu_pec_clken {
> > +	CLKEN_DISABLE = 0x0,
> > +	CLKEN_AUTOMATIC = 0x1,
> > +	CLKEN_FULL = 0x3,
> > +};
> > +
> > +int dpu_map_irq(struct dpu_soc *dpu, int irq);
> > +
> > +/* Constant Frame Unit */
> > +struct dpu_constframe;
> > +enum dpu_link_id dpu_cf_get_link_id(struct dpu_constframe *cf);
> > +void dpu_cf_framedimensions(struct dpu_constframe *cf, unsigned int w,
> > +			    unsigned int h);
> > +void dpu_cf_constantcolor_black(struct dpu_constframe *cf);
> > +void dpu_cf_constantcolor_blue(struct dpu_constframe *cf);
> > +struct dpu_constframe *dpu_cf_safe_get(struct dpu_soc *dpu,
> > +				       unsigned int stream_id);
> > +void dpu_cf_safe_put(struct dpu_constframe *cf);
> > +struct dpu_constframe *dpu_cf_cont_get(struct dpu_soc *dpu,
> > +				       unsigned int stream_id);
> > +void dpu_cf_cont_put(struct dpu_constframe *cf);
> > +
> > +/* Display Engine Configuration Unit */
> > +struct dpu_disengcfg;
> > +struct dpu_disengcfg *dpu_dec_get(struct dpu_soc *dpu, unsigned int id);
> > +void dpu_dec_put(struct dpu_disengcfg *dec);
> > +
> > +/* External Destination Unit */
> > +struct dpu_extdst;
> > +void dpu_ed_pec_poweron(struct dpu_extdst *ed);
> > +void dpu_ed_pec_src_sel(struct dpu_extdst *ed, enum dpu_link_id src);
> > +void dpu_ed_pec_sync_trigger(struct dpu_extdst *ed);
> > +struct dpu_extdst *dpu_ed_safe_get(struct dpu_soc *dpu,
> > +				   unsigned int stream_id);
> > +void dpu_ed_safe_put(struct dpu_extdst *ed);
> > +struct dpu_extdst *dpu_ed_cont_get(struct dpu_soc *dpu,
> > +				   unsigned int stream_id);
> > +void dpu_ed_cont_put(struct dpu_extdst *ed);
> > +
> > +/* Fetch Decode Unit */
> > +struct dpu_fetchunit *dpu_fd_get(struct dpu_soc *dpu, unsigned int id);
> > +void dpu_fd_put(struct dpu_fetchunit *fu);
> > +
> > +/* Fetch ECO Unit */
> > +struct dpu_fetchunit *dpu_fe_get(struct dpu_soc *dpu, unsigned int id);
> > +void dpu_fe_put(struct dpu_fetchunit *fu);
> > +
> > +/* Fetch Layer Unit */
> > +struct dpu_fetchunit *dpu_fl_get(struct dpu_soc *dpu, unsigned int id);
> > +void dpu_fl_put(struct dpu_fetchunit *fu);
> > +
> > +/* Fetch Warp Unit */
> > +struct dpu_fetchunit *dpu_fw_get(struct dpu_soc *dpu, unsigned int id);
> > +void dpu_fw_put(struct dpu_fetchunit *fu);
> > +
> > +/* Frame Generator Unit */
> > +struct dpu_framegen;
> > +void dpu_fg_syncmode(struct dpu_framegen *fg, enum dpu_fg_syncmode mode);
> > +void dpu_fg_cfg_videomode(struct dpu_framegen *fg, struct drm_display_mode *m);
> > +void dpu_fg_displaymode(struct dpu_framegen *fg, enum dpu_fg_dm mode);
> > +void dpu_fg_panic_displaymode(struct dpu_framegen *fg, enum dpu_fg_dm mode);
> > +void dpu_fg_enable(struct dpu_framegen *fg);
> > +void dpu_fg_disable(struct dpu_framegen *fg);
> > +void dpu_fg_shdtokgen(struct dpu_framegen *fg);
> > +u32 dpu_fg_get_frame_index(struct dpu_framegen *fg);
> > +int dpu_fg_get_line_index(struct dpu_framegen *fg);
> > +int dpu_fg_wait_for_frame_counter_moving(struct dpu_framegen *fg);
> > +bool dpu_fg_secondary_requests_to_read_empty_fifo(struct dpu_framegen *fg);
> > +void dpu_fg_secondary_clear_channel_status(struct dpu_framegen *fg);
> > +int dpu_fg_wait_for_secondary_syncup(struct dpu_framegen *fg);
> > +void dpu_fg_enable_clock(struct dpu_framegen *fg);
> > +void dpu_fg_disable_clock(struct dpu_framegen *fg);
> > +struct dpu_framegen *dpu_fg_get(struct dpu_soc *dpu, unsigned int id);
> > +void dpu_fg_put(struct dpu_framegen *fg);
> > +
> > +/* Gamma Correction Unit */
> > +struct dpu_gammacor;
> > +void dpu_gc_enable_rgb_write(struct dpu_gammacor *gc);
> > +void dpu_gc_disable_rgb_write(struct dpu_gammacor *gc);
> > +void dpu_gc_start_rgb(struct dpu_gammacor *gc, const struct drm_color_lut *lut);
> > +void dpu_gc_delta_rgb(struct dpu_gammacor *gc, const struct drm_color_lut *lut);
> > +void dpu_gc_mode(struct dpu_gammacor *gc, enum dpu_gc_mode mode);
> > +struct dpu_gammacor *dpu_gc_get(struct dpu_soc *dpu, unsigned int id);
> > +void dpu_gc_put(struct dpu_gammacor *gc);
> > +
> > +/* Horizontal Scaler Unit */
> > +struct dpu_hscaler;
> > +enum dpu_link_id dpu_hs_get_link_id(struct dpu_hscaler *hs);
> > +void dpu_hs_pec_dynamic_src_sel(struct dpu_hscaler *hs, enum dpu_link_id src);
> > +void dpu_hs_pec_clken(struct dpu_hscaler *hs, enum dpu_pec_clken clken);
> > +void dpu_hs_setup1(struct dpu_hscaler *hs,
> > +		   unsigned int src_w, unsigned int dst_w);
> > +void dpu_hs_setup2(struct dpu_hscaler *hs, u32 phase_offset);
> > +void dpu_hs_output_size(struct dpu_hscaler *hs, u32 line_num);
> > +void dpu_hs_filter_mode(struct dpu_hscaler *hs, enum dpu_scaler_filter_mode m);
> > +void dpu_hs_scale_mode(struct dpu_hscaler *hs, enum dpu_scaler_scale_mode m);
> > +void dpu_hs_mode(struct dpu_hscaler *hs, enum dpu_scaler_mode m);
> > +unsigned int dpu_hs_get_id(struct dpu_hscaler *hs);
> > +struct dpu_hscaler *dpu_hs_get(struct dpu_soc *dpu, unsigned int id);
> > +void dpu_hs_put(struct dpu_hscaler *hs);
> > +
> > +/* Layer Blend Unit */
> > +struct dpu_layerblend;
> > +enum dpu_link_id dpu_lb_get_link_id(struct dpu_layerblend *lb);
> > +void dpu_lb_pec_dynamic_prim_sel(struct dpu_layerblend *lb,
> > +				 enum dpu_link_id prim);
> > +void dpu_lb_pec_dynamic_sec_sel(struct dpu_layerblend *lb,
> > +				enum dpu_link_id sec);
> > +void dpu_lb_pec_clken(struct dpu_layerblend *lb, enum dpu_pec_clken clken);
> > +void dpu_lb_mode(struct dpu_layerblend *lb, enum dpu_lb_mode mode);
> > +void dpu_lb_blendcontrol(struct dpu_layerblend *lb, unsigned int zpos,
> > +			 unsigned int pixel_blend_mode, u16 alpha);
> > +void dpu_lb_position(struct dpu_layerblend *lb, int x, int y);
> > +unsigned int dpu_lb_get_id(struct dpu_layerblend *lb);
> > +struct dpu_layerblend *dpu_lb_get(struct dpu_soc *dpu, unsigned int id);
> > +void dpu_lb_put(struct dpu_layerblend *lb);
> > +
> > +/* Timing Controller Unit */
> > +struct dpu_tcon;
> > +void dpu_tcon_set_fmt(struct dpu_tcon *tcon);
> > +void dpu_tcon_set_operation_mode(struct dpu_tcon *tcon);
> > +void dpu_tcon_cfg_videomode(struct dpu_tcon *tcon, struct drm_display_mode *m);
> > +struct dpu_tcon *dpu_tcon_get(struct dpu_soc *dpu, unsigned int id);
> > +void dpu_tcon_put(struct dpu_tcon *tcon);
> > +
> > +/* Vertical Scaler Unit */
> > +struct dpu_vscaler;
> > +enum dpu_link_id dpu_vs_get_link_id(struct dpu_vscaler *vs);
> > +void dpu_vs_pec_dynamic_src_sel(struct dpu_vscaler *vs, enum dpu_link_id src);
> > +void dpu_vs_pec_clken(struct dpu_vscaler *vs, enum dpu_pec_clken clken);
> > +void dpu_vs_setup1(struct dpu_vscaler *vs,
> > +		   unsigned int src_w, unsigned int dst_w, bool deinterlace);
> > +void dpu_vs_setup2(struct dpu_vscaler *vs, bool deinterlace);
> > +void dpu_vs_setup3(struct dpu_vscaler *vs, bool deinterlace);
> > +void dpu_vs_setup4(struct dpu_vscaler *vs, u32 phase_offset);
> > +void dpu_vs_setup5(struct dpu_vscaler *vs, u32 phase_offset);
> > +void dpu_vs_output_size(struct dpu_vscaler *vs, u32 line_num);
> > +void dpu_vs_field_mode(struct dpu_vscaler *vs, enum dpu_scaler_field_mode m);
> > +void dpu_vs_filter_mode(struct dpu_vscaler *vs, enum dpu_scaler_filter_mode m);
> > +void dpu_vs_scale_mode(struct dpu_vscaler *vs, enum dpu_scaler_scale_mode m);
> > +void dpu_vs_mode(struct dpu_vscaler *vs, enum dpu_scaler_mode m);
> > +unsigned int dpu_vs_get_id(struct dpu_vscaler *vs);
> > +struct dpu_vscaler *dpu_vs_get(struct dpu_soc *dpu, unsigned int id);
> > +void dpu_vs_put(struct dpu_vscaler *vs);
> > +
> > +/* Fetch Units */
> > +struct dpu_fetchunit_ops {
> > +	void (*set_pec_dynamic_src_sel)(struct dpu_fetchunit *fu,
> > +					enum dpu_link_id src);
> > +
> > +	bool (*is_enabled)(struct dpu_fetchunit *fu);
> > +
> > +	void (*set_stream_id)(struct dpu_fetchunit *fu, unsigned int stream_id);
> > +
> > +	unsigned int (*get_stream_id)(struct dpu_fetchunit *fu);
> > +
> > +	void (*set_no_stream_id)(struct dpu_fetchunit *fu);
> > +
> > +	bool (*has_stream_id)(struct dpu_fetchunit *fu);
> > +
> > +	void (*set_numbuffers)(struct dpu_fetchunit *fu, unsigned int num);
> > +
> > +	void (*set_burstlength)(struct dpu_fetchunit *fu,
> > +				unsigned int x_offset, unsigned int mt_w,
> > +				int bpp, dma_addr_t baddr);
> > +
> > +	void (*set_baseaddress)(struct dpu_fetchunit *fu, unsigned int width,
> > +				unsigned int x_offset, unsigned int y_offset,
> > +				unsigned int mt_w, unsigned int mt_h,
> > +				int bpp, dma_addr_t baddr);
> > +
> > +	void (*set_src_stride)(struct dpu_fetchunit *fu,
> > +			       unsigned int width, unsigned int x_offset,
> > +			       unsigned int mt_w, int bpp, unsigned int stride,
> > +			       dma_addr_t baddr);
> > +
> > +	void (*set_src_buf_dimensions)(struct dpu_fetchunit *fu,
> > +				       unsigned int w, unsigned int h,
> > +				       const struct drm_format_info *format,
> > +				       bool deinterlace);
> > +
> > +	void (*set_fmt)(struct dpu_fetchunit *fu,
> > +			const struct drm_format_info *format,
> > +			enum drm_color_encoding color_encoding,
> > +			enum drm_color_range color_range,
> > +			bool deinterlace);
> > +
> > +	void (*set_pixel_blend_mode)(struct dpu_fetchunit *fu,
> > +				     unsigned int pixel_blend_mode, u16 alpha,
> > +				     bool fb_format_has_alpha);
> > +
> > +	void (*enable_src_buf)(struct dpu_fetchunit *fu);
> > +	void (*disable_src_buf)(struct dpu_fetchunit *fu);
> > +
> > +	void (*set_framedimensions)(struct dpu_fetchunit *fu,
> > +				    unsigned int w, unsigned int h,
> > +				    bool deinterlace);
> > +
> > +	struct dpu_dprc *(*get_dprc)(struct dpu_fetchunit *fu);
> > +	struct dpu_fetchunit *(*get_fetcheco)(struct dpu_fetchunit *fu);
> > +	struct dpu_hscaler *(*get_hscaler)(struct dpu_fetchunit *fu);
> > +	struct dpu_vscaler *(*get_vscaler)(struct dpu_fetchunit *fu);
> > +
> > +	void (*set_layerblend)(struct dpu_fetchunit *fu,
> > +			       struct dpu_layerblend *lb);
> > +
> > +	bool (*is_available)(struct dpu_fetchunit *fu);
> > +	void (*set_available)(struct dpu_fetchunit *fu);
> > +	void (*set_inavailable)(struct dpu_fetchunit *fu);
> > +
> > +	enum dpu_link_id (*get_link_id)(struct dpu_fetchunit *fu);
> > +
> > +	u32 (*get_cap_mask)(struct dpu_fetchunit *fu);
> > +
> > +	const char *(*get_name)(struct dpu_fetchunit *fu);
> > +};
> > +
> > +const struct dpu_fetchunit_ops *dpu_fu_get_ops(struct dpu_fetchunit *fu);
> > +struct dpu_fetchunit *dpu_fu_get_from_list(struct list_head *l);
> > +void dpu_fu_add_to_list(struct dpu_fetchunit *fu, struct list_head *l);
> > +
> > +/* HW resources for a plane group */
> > +struct dpu_plane_res {
> > +	struct dpu_fetchunit	**fd;
> > +	struct dpu_fetchunit	**fe;
> > +	struct dpu_fetchunit	**fl;
> > +	struct dpu_fetchunit	**fw;
> > +	struct dpu_layerblend	**lb;
> > +	unsigned int		fd_cnt;
> > +	unsigned int		fe_cnt;
> > +	unsigned int		fl_cnt;
> > +	unsigned int		fw_cnt;
> > +	unsigned int		lb_cnt;
> > +};
> > +
> > +/*
> > + * fetchunit/scaler/layerblend resources of a plane group are
> > + * shared by the two CRTCs in a CRTC group
> > + */
> > +struct dpu_plane_grp {
> > +	struct dpu_plane_res	res;
> > +	struct list_head	node;
> > +	struct list_head	fu_list;
> > +	unsigned int		hw_plane_cnt;
> > +	struct dpu_constframe	*cf[2];
> > +	struct dpu_extdst	*ed[2];
> > +};
> > +
> > +/* the two CRTCs of one DPU are in a CRTC group */
> > +struct dpu_crtc_grp {
> > +	u32			crtc_mask;
> > +	struct dpu_plane_grp	*plane_grp;
> > +};
> > +
> > +struct dpu_client_platformdata {
> > +	const unsigned int	stream_id;
> > +	const unsigned int	dec_frame_complete_irq;
> > +	const unsigned int	dec_seq_complete_irq;
> > +	const unsigned int	dec_shdld_irq;
> > +	const unsigned int	ed_cont_shdld_irq;
> > +	const unsigned int	ed_safe_shdld_irq;
> > +	struct dpu_crtc_grp	*crtc_grp;
> > +
> > +	struct device_node	*of_node;
> > +};
> > +
> > +#endif /* __DPU_H__ */
> > -- 
> > 2.7.4
> > 


_______________________________________________
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] 8+ messages in thread

end of thread, other threads:[~2021-03-03 21:43 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-02  6:33 [PATCH v8 0/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM Liu Ying
2021-03-02  6:33 ` [PATCH v8 1/6] dt-bindings: display: imx: Add i.MX8qxp/qm DPU binding Liu Ying
2021-03-02  6:33 ` [PATCH v8 2/6] dt-bindings: display: imx: Add i.MX8qxp/qm PRG binding Liu Ying
2021-03-02  6:33 ` [PATCH v8 3/6] dt-bindings: display: imx: Add i.MX8qxp/qm DPR channel binding Liu Ying
2021-03-02  6:33 ` [PATCH v8 4/6] drm/atomic: Avoid unused-but-set-variable warning on for_each_old_plane_in_state Liu Ying
2021-03-02  6:33 ` [PATCH v8 6/6] MAINTAINERS: add maintainer for i.MX8qxp DPU DRM driver Liu Ying
     [not found] ` <1614666796-19374-6-git-send-email-victor.liu@nxp.com>
2021-03-02 14:36   ` [PATCH v8 5/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM Laurentiu Palcu
2021-03-03  6:21     ` Liu Ying

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