Add Unisoc's drm kms module
Subsystems (4)
v6 cover Add Unisoc's drm kms module
From: Kevin Tang <[email protected]>
ChangeList:
v1:
1. only upstream modeset and atomic at first commit.
2. remove some unused code;
3. use alpha and blend_mode properties;
3. add yaml support;
4. remove auto-adaptive panel driver;
5. bugfix
v2:
1. add sprd crtc and plane module for KMS, preparing for multi crtc&encoder
2. remove gem drivers, use generic CMA handlers
3. remove redundant "module_init", all the sub modules loading by KMS
v3:
1. multi crtc&encoder design have problem, so rollback to v1
v4:
1. update to gcc-linaro-7.5.0
2. update to Linux 5.6-rc3
3. remove pm_runtime support
4. add COMPILE_TEST, remove unused kconfig
5. "drm_dev_put" on drm_unbind
6. fix some naming convention issue
7. remove semaphore lock for crtc flip
8. remove static variables
v5:
1. optimize encoder and connector code implementation
2. use "platform_get_irq" and "platform_get_resource"
3. drop useless function return type, drop unless debug log
4. custom properties should be separate, so drop it
5. use DRM_XXX replase pr_xxx
6. drop dsi&dphy hal callback ops
7. drop unless callback ops checking
8. add comments for sprd dpu structure
v6:
1. Access registers via readl/writel
2. Checking for unsupported KMS properties (format, rotation, blend_mode, etc) on plane_check ops
3. Remove always true checks for dpu core ops
Kevin Tang (6):
dt-bindings: display: add Unisoc's drm master bindings drm/sprd: add Unisoc's drm kms master
dt-bindings: display: add Unisoc's dpu bindings drm/sprd: add Unisoc's drm display controller driver
dt-bindings: display: add Unisoc's mipi dsi&dphy bindings drm/sprd: add Unisoc's drm mipi dsi&dphy driver
.../devicetree/bindings/display/sprd/dphy.yaml | 75 + .../devicetree/bindings/display/sprd/dpu.yaml | 82 ++ .../devicetree/bindings/display/sprd/drm.yaml | 36 + .../devicetree/bindings/display/sprd/dsi.yaml | 98 ++ drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/sprd/Kconfig | 12 + drivers/gpu/drm/sprd/Makefile | 13 + drivers/gpu/drm/sprd/disp_lib.c | 57 + drivers/gpu/drm/sprd/disp_lib.h | 16 + drivers/gpu/drm/sprd/dphy/Makefile | 7 + drivers/gpu/drm/sprd/dphy/pll/Makefile | 3 + drivers/gpu/drm/sprd/dphy/pll/megacores_sharkle.c | 473 +++++++ drivers/gpu/drm/sprd/dphy/sprd_dphy_api.c | 201 +++ drivers/gpu/drm/sprd/dphy/sprd_dphy_api.h | 22 + drivers/gpu/drm/sprd/dpu/Makefile | 3 + drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 503 +++++++ drivers/gpu/drm/sprd/dsi/Makefile | 8 + drivers/gpu/drm/sprd/dsi/core/Makefile | 4 + drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.c | 964 +++++++++++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.h | 1477 ++++++++++++++++++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.c | 328 +++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.h | 32 + drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c | 590 ++++++++ drivers/gpu/drm/sprd/dsi/sprd_dsi_api.h | 26 + drivers/gpu/drm/sprd/sprd_dphy.c | 209 +++ drivers/gpu/drm/sprd/sprd_dphy.h | 50 + drivers/gpu/drm/sprd/sprd_dpu.c | 668 +++++++++ drivers/gpu/drm/sprd/sprd_dpu.h | 190 +++ drivers/gpu/drm/sprd/sprd_drm.c | 227 +++ drivers/gpu/drm/sprd/sprd_drm.h | 18 + drivers/gpu/drm/sprd/sprd_dsi.c | 571 ++++++++ drivers/gpu/drm/sprd/sprd_dsi.h | 108 ++ 33 files changed, 7074 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/dphy.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/dpu.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/drm.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/dsi.yaml create mode 100644 drivers/gpu/drm/sprd/Kconfig create mode 100644 drivers/gpu/drm/sprd/Makefile create mode 100644 drivers/gpu/drm/sprd/disp_lib.c create mode 100644 drivers/gpu/drm/sprd/disp_lib.h create mode 100644 drivers/gpu/drm/sprd/dphy/Makefile create mode 100644 drivers/gpu/drm/sprd/dphy/pll/Makefile create mode 100644 drivers/gpu/drm/sprd/dphy/pll/megacores_sharkle.c create mode 100644 drivers/gpu/drm/sprd/dphy/sprd_dphy_api.c create mode 100644 drivers/gpu/drm/sprd/dphy/sprd_dphy_api.h create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c create mode 100644 drivers/gpu/drm/sprd/dsi/Makefile create mode 100644 drivers/gpu/drm/sprd/dsi/core/Makefile create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.c create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.h create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.c create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.h create mode 100644 drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c create mode 100644 drivers/gpu/drm/sprd/dsi/sprd_dsi_api.h create mode 100644 drivers/gpu/drm/sprd/sprd_dphy.c create mode 100644 drivers/gpu/drm/sprd/sprd_dphy.h create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.h create mode 100644 drivers/gpu/drm/sprd/sprd_drm.c create mode 100644 drivers/gpu/drm/sprd/sprd_drm.h create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.c create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.h
Signature · 1 line
2.7.4
RFC PATCH v6 1/6 dt-bindings: display: add Unisoc's drm master bindings
From: Kevin Tang <[email protected]>
The Unisoc DRM master device is a virtual device needed to list all DPU devices or other display interface nodes that comprise the graphics subsystem
--- .../devicetree/bindings/display/sprd/drm.yaml | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/drm.yaml
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +36 -0
@@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/sprd/drm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc DRM master device + +maintainers: + - Mark Rutland <[email protected]> + +description: | + The Unisoc DRM master device is a virtual device needed to list all + DPU devices or other display interface nodes that comprise the + graphics subsystem. + +properties: + compatible: + const: sprd,display-subsystem + + ports: + description: + Should contain a list of phandles pointing to display interface port + of DPU devices. + +required: + - compatible + - ports + +examples: + - | + display-subsystem { + compatible = "sprd,display-subsystem"; + ports = <&dpu_out>; + }; +
Signature · 1 line
2.7.4
Re: [PATCH RFC v6 1/6] dt-bindings: display: add Unisoc's drm master bindings
Hi Kevin
Documentation/devicetree/bindings/display/sprd/drm.yaml
Quoted 19 lines · Kevin Tang
From: Kevin Tang <[email protected]>
The Unisoc DRM master device is a virtual device needed to list all DPU devices or other display interface nodes that comprise the graphics subsystem
Cc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>--- .../devicetree/bindings/display/sprd/drm.yaml | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/drm.yamlDocumentation/devicetree/bindings/display/sprd/drm.yaml new file +0
-0
drm seems like a sub-optimal name.
How about usign the compatible name "display-subsystem" as it is a bit more specific (but not good).
Documentation/devicetree/bindings/display/sprd/drm.yaml line 1
Quoted 2 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +1
-0@@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0
Any chance this can be (GPL-2.0-only OR BSD-2-Clause).
I noticed that for example clock/sprd,sc9863a-clk.yaml uses this license so I hope this is OK.
Quoted 13 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +13
-0+%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/sprd/drm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc DRM master device + +maintainers: + - Mark Rutland <[email protected]> + +description: | + The Unisoc DRM master device is a virtual device needed to list all + DPU devices or other display interface nodes that comprise the
Documentation/devicetree/bindings/display/sprd/drm.yaml line 24
Quoted 10 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +10
-0+ graphics subsystem. + +properties: + compatible: + const: sprd,display-subsystem + + ports: + description: + Should contain a list of phandles pointing to display interface port + of DPU devices.
Add type - like this:
$ref: /schemas/types.yaml#/definitions/phandle-array
See for example display/rockchip/rockchip-drm.yaml
Any specific reason why this is not a ports node like used by many other display bindings?
In other words - I think this is too simple.
Documentation/devicetree/bindings/display/sprd/drm.yaml line 29
Quoted 5 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +5
-0+ +required: + - compatible + - ports +
Add:
additionalProperties: false
so we catch if other properties sneak in.
Quoted 14 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +7
-0+examples: + - | + display-subsystem { + compatible = "sprd,display-subsystem"; + ports = <&dpu_out>; + }; +Signature · 6 lines
2.7.4 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH RFC v6 1/6] dt-bindings: display: add Unisoc's drm master bindings
Quoted 18 lines · Sam Ravnborg <[email protected]> 于2020年7月29日周三 上午4:27写道:
Hi Kevin
Quoted 14 lines · Kevin Tang
From: Kevin Tang <[email protected]>
The Unisoc DRM master device is a virtual device needed to list all DPU devices or other display interface nodes that comprise the graphics subsystem
Cc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>--- .../devicetree/bindings/display/sprd/drm.yaml | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/drm.yaml
Quoted 8 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml
Quoted 5 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +0
-0drm seems like a sub-optimal name.
How about usign the compatible name "display-subsystem" as it is a bit more specific (but not good).
You're right, maybe "sprd,drm.yaml" or "sprd-drm.yaml" will be better
Quoted 7 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml line 1
Quoted 3 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +1
-0@@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0Any chance this can be (GPL-2.0-only OR BSD-2-Clause).
I noticed that for exampleclock/sprd,sc9863a-clk.yamluses this license so I hope this is OK.
I will add GPL-2.0-only to it.
Quoted 27 lines
Quoted 14 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +13
-0+%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/sprd/drm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc DRM master device + +maintainers: + - Mark Rutland <[email protected]> + +description: | + The Unisoc DRM master device is a virtual device needed to list all + DPU devices or other display interface nodes that comprise theDocumentation/devicetree/bindings/display/sprd/drm.yaml line 24
Quoted 10 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +10
-0+ graphics subsystem. + +properties: + compatible: + const: sprd,display-subsystem + + ports: + description: + Should contain a list of phandles pointing to display interface port + of DPU devices.Add type - like this:
$ref: /schemas/types.yaml#/definitions/phandle-array
Quoted 5 lines
See for example
display/rockchip/rockchip-drm.yamlAny specific reason why this is not a ports node like used by many other display bindings?
In other words - I think this is too simple.
We only support one display pipeline now, other interface, like DP(DisplayPort), HDMI...will be add later...
ports:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: |
Should contain a list of phandles pointing to display interface port of dpu devices.. dpu definitions as defined in Documentation/devicetree/bindings/display/sprd/sprd,dpu.yaml
Quoted 26 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml line 29
Quoted 6 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +5
-0+ +required: + - compatible + - ports +Add:
additionalProperties: falseso we catch if other properties sneak in.
Quoted 14 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +7
-1+examples: + - | + display-subsystem { + compatible = "sprd,display-subsystem"; + ports = <&dpu_out>; + }; + --2.7.4
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH RFC v6 1/6] dt-bindings: display: add Unisoc's drm master bindings
Hi Kevin.
Quoted 7 lines
Quoted 4 lines
Any specific reason why this is not a ports node like used by many other display bindings?
In other words - I think this is too simple.We only support one display pipeline now, other interface, like DP(DisplayPort), HDMI...will be add later...
Quoted 6 lines
ports:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: |
Should contain a list of phandles pointing to display interface port of dpu devices.. dpu definitions as defined inDocumentation/devicetree/bindings/display/sprd/sprd,dpu.yaml
There is nothing wrong having a ports node that is limited to a single port node. But please remember the binding describes the HW - so if the HW supports more than one port the binding should describe this. What the driver supports is not relevant for the binding.
Sam
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH RFC v6 1/6] dt-bindings: display: add Unisoc's drm master bindings
In reply to Kevin TangQuoted 7 lines · Kevin Tang
From: Kevin Tang <[email protected]>
The Unisoc DRM master device is a virtual device needed to list all DPU devices or other display interface nodes that comprise the graphics subsystem
Quoted 7 lines
Cc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>--- .../devicetree/bindings/display/sprd/drm.yaml | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/drm.yaml
If you want bindings reviewed, then you need to Cc [email protected]. Otherwise you may be waiting until the 6th version or later or never.
Documentation/devicetree/bindings/display/sprd/drm.yaml line 1
Quoted 8 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +1
-0@@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0
New bindings should be dual licensed:
(GPL-2.0-only OR BSD-2-Clause)
Documentation/devicetree/bindings/display/sprd/drm.yaml line 7
Quoted 6 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +6
-0+%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/sprd/drm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc DRM master device
DRM is a Linux thing and shouldn't be part of a binding.
Documentation/devicetree/bindings/display/sprd/drm.yaml line 10
Quoted 3 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +3
-0+ +maintainers: + - Mark Rutland <[email protected]>
No, this should be you or someone that knows the h/w.
Quoted 14 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +14
-0+ +description: | + The Unisoc DRM master device is a virtual device needed to list all + DPU devices or other display interface nodes that comprise the + graphics subsystem. + +properties: + compatible: + const: sprd,display-subsystem + + ports: + description: + Should contain a list of phandles pointing to display interface port + of DPU devices.
Documentation/devicetree/bindings/display/sprd/drm.yaml line 34
Quoted 10 lines
Documentation/devicetree/bindings/display/sprd/drm.yaml new file +10
-0+ +required: + - compatible + - ports + +examples: + - | + display-subsystem { + compatible = "sprd,display-subsystem"; + ports = <&dpu_out>;
We generally try to avoid this virtual node as it doesn't represent any h/w. Can't you bind the driver to the DPU directly?
Rob
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
RFC PATCH v6 2/6 drm/sprd: add Unisoc's drm kms master
In reply to Kevin TangFrom: Kevin Tang <[email protected]>
Adds drm support for the Unisoc's display subsystem.
This is drm kms driver, this driver provides support for the application framework in Android, Yocto and more.
Application framework can access Unisoc's display internel peripherals through libdrm or libkms, it's test ok by modetest (DRM/KMS test tool) and Android HWComposer.
--- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/sprd/Kconfig | 12 +++ drivers/gpu/drm/sprd/Makefile | 5 + drivers/gpu/drm/sprd/sprd_drm.c | 226 ++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_drm.h | 16 +++ 6 files changed, 262 insertions(+) create mode 100644 drivers/gpu/drm/sprd/Kconfig create mode 100644 drivers/gpu/drm/sprd/Makefile create mode 100644 drivers/gpu/drm/sprd/sprd_drm.c create mode 100644 drivers/gpu/drm/sprd/sprd_drm.h
drivers/gpu/drm/Kconfig +2 -0
@@ -386,6 +386,8 @@ source "drivers/gpu/drm/mcde/Kconfig" source "drivers/gpu/drm/tidss/Kconfig" +source "drivers/gpu/drm/sprd/Kconfig" + # Keep legacy drivers last menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
@@ -123,3 +123,4 @@ obj-$(CONFIG_DRM_PANFROST) += panfrost/ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ obj-$(CONFIG_DRM_MCDE) += mcde/ obj-$(CONFIG_DRM_TIDSS) += tidss/ +obj-$(CONFIG_DRM_SPRD) += sprd/
drivers/gpu/drm/sprd/Kconfig new file +12 -0
@@ -0,0 +1,12 @@ +config DRM_SPRD + tristate "DRM Support for Unisoc SoCs Platform" + depends on ARCH_SPRD || COMPILE_TEST + depends on DRM && OF + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select DRM_MIPI_DSI + help + Choose this option if you have a Unisoc chipsets. + If M is selected the module will be called sprd-drm. +
drivers/gpu/drm/sprd/Makefile new file +5 -0
@@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +subdir-ccflags-y += -I$(srctree)/$(src) + +obj-y := sprd_drm.o
drivers/gpu/drm/sprd/sprd_drm.c new file +226 -0
226 lines not on this page · raw message
drivers/gpu/drm/sprd/sprd_drm.h new file +16 -0
@@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#ifndef _SPRD_DRM_H_ +#define _SPRD_DRM_H_ + +#include <drm/drm_atomic.h> +#include <drm/drm_print.h> + +struct sprd_drm { +struct drm_device *drm; +}; + +#endif /* _SPRD_DRM_H_ */
Signature · 1 line
2.7.4
Re: [PATCH RFC v6 2/6] drm/sprd: add Unisoc's drm kms master
Quoted 6 lines · Kevin Tang
drivers/gpu/drm/sprd/Kconfig new file +0
-0
drivers/gpu/drm/sprd/Kconfig line 10
Quoted 10 lines
drivers/gpu/drm/sprd/Kconfig new file +10
-0@@ -0,0 +1,12 @@ +config DRM_SPRD + tristate "DRM Support for Unisoc SoCs Platform" + depends on ARCH_SPRD || COMPILE_TEST + depends on DRM && OF + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select DRM_MIPI_DSI + help + Choose this option if you have a Unisoc chipsets.
chipset.
drivers/gpu/drm/sprd/Kconfig line 11
Quoted 1 line
drivers/gpu/drm/sprd/Kconfig new file +1
-0+ If M is selected the module will be called sprd-drm.
sprd_drm.
Quoted 12 lines
drivers/gpu/drm/sprd/Kconfig new file +1
-0+drivers/gpu/drm/sprd/Makefile new file +5
-0@@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +subdir-ccflags-y += -I$(srctree)/$(src) + +obj-y := sprd_drm.o
Signature · 1 line
~Randy
Re: [PATCH RFC v6 2/6] drm/sprd: add Unisoc's drm kms master
In reply to Kevin TangHi Kevin.
Nice split of the driver.
Some feedback in the following.
Most to bring the driver up-to-date with what have happened since we saw it last time.
Keeping up with the changes in drm is not always easy.
Sam
Quoted 73 lines · Kevin Tang
From: Kevin Tang <[email protected]>
Adds drm support for the Unisoc's display subsystem.
This is drm kms driver, this driver provides support for the application framework in Android, Yocto and more.
Application framework can access Unisoc's display internel peripherals through libdrm or libkms, it's test ok by modetest (DRM/KMS test tool) and Android HWComposer.
Cc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>--- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/sprd/Kconfig | 12 +++ drivers/gpu/drm/sprd/Makefile | 5 + drivers/gpu/drm/sprd/sprd_drm.c | 226 ++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_drm.h | 16 +++ 6 files changed, 262 insertions(+) create mode 100644 drivers/gpu/drm/sprd/Kconfig create mode 100644 drivers/gpu/drm/sprd/Makefile create mode 100644 drivers/gpu/drm/sprd/sprd_drm.c create mode 100644 drivers/gpu/drm/sprd/sprd_drm.hdrivers/gpu/drm/Kconfig +2
-0@@ -386,6 +386,8 @@ source "drivers/gpu/drm/mcde/Kconfig" source "drivers/gpu/drm/tidss/Kconfig" +source "drivers/gpu/drm/sprd/Kconfig" + # Keep legacy drivers last menuconfig DRM_LEGACYdrivers/gpu/drm/Makefile +1
-0@@ -123,3 +123,4 @@ obj-$(CONFIG_DRM_PANFROST) += panfrost/ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ obj-$(CONFIG_DRM_MCDE) += mcde/ obj-$(CONFIG_DRM_TIDSS) += tidss/ +obj-$(CONFIG_DRM_SPRD) += sprd/drivers/gpu/drm/sprd/Kconfig new file +12
-0@@ -0,0 +1,12 @@ +config DRM_SPRD + tristate "DRM Support for Unisoc SoCs Platform" + depends on ARCH_SPRD || COMPILE_TEST + depends on DRM && OF + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select DRM_MIPI_DSI + help + Choose this option if you have a Unisoc chipsets. + If M is selected the module will be called sprd-drm. +drivers/gpu/drm/sprd/Makefile new file +0
-0
drivers/gpu/drm/sprd/Makefile line 3
Quoted 3 lines
drivers/gpu/drm/sprd/Makefile new file +3
-0@@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +subdir-ccflags-y += -I$(srctree)/$(src)
subdir-ccflags-y is not needed - drop it.
Quoted 40 lines
drivers/gpu/drm/sprd/Makefile new file +2
-0+ +obj-y := sprd_drm.odrivers/gpu/drm/sprd/sprd_drm.c new file +32
-0@@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/component.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of_graph.h> +#include <linux/of_platform.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_drv.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_of.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> + +#include "sprd_drm.h" + +#define DRIVER_NAME "sprd" +#define DRIVER_DESC "Spreadtrum SoCs' DRM Driver" +#define DRIVER_DATE "20200201" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 + +static const struct drm_mode_config_helper_funcs sprd_drm_mode_config_helper = { + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, +};
drivers/gpu/drm/sprd/sprd_drm.c line 42
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +10
-0+ +static const struct drm_mode_config_funcs sprd_drm_mode_config_funcs = { + .fb_create = drm_gem_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static void sprd_drm_mode_config_init (struct drm_device *drm) +{ +drm_mode_config_init (drm);
The documentation of this functions says:
FIXME: This function is deprecated and drivers should be converted over to drmm_mode_config_init().
Quoted 32 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +32
-0+ + drm->mode_config.min_width =0 ; + drm->mode_config.min_height =0 ; + drm->mode_config.max_width =8192 ; + drm->mode_config.max_height =8192 ; + drm->mode_config.allow_fb_modifiers = true; + + drm->mode_config.funcs = &sprd_drm_mode_config_funcs; + drm->mode_config.helper_private = &sprd_drm_mode_config_helper; +} + +DEFINE_DRM_GEM_CMA_FOPS (sprd_drm_fops); + +static struct drm_driver sprd_drm_drv = { + .driver_features =DRIVER_GEM |DRIVER_MODESET |DRIVER_ATOMIC , + .fops = &sprd_drm_fops, + +/* GEM Operations */ +DRM_GEM_CMA_VMAP_DRIVER_OPS , + + .name =DRIVER_NAME , + .desc =DRIVER_DESC , + .date =DRIVER_DATE , + .major =DRIVER_MAJOR , + .minor =DRIVER_MINOR , +}; + +static int sprd_drm_bind (struct device *dev) +{ +struct drm_device *drm; +struct sprd_drm *sprd; +int err;
drivers/gpu/drm/sprd/sprd_drm.c line 84
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +10
-0+ + drm =drm_dev_alloc (&sprd_drm_drv, dev); +if (IS_ERR (drm)) +return PTR_ERR (drm); + +dev_set_drvdata (dev, drm); + + sprd =devm_kzalloc (drm->dev,sizeof (*sprd),GFP_KERNEL ); +if (!sprd) + err = -ENOMEM ;
Embed drm_device in sprd_drm and use devm_drm_dev_alloc See other drivers and drm_drv.c how to do it.drm_drv.c has a nice example explained in one of the comment blocks.
drivers/gpu/drm/sprd/sprd_drm.c line 86
Quoted 2 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +2
-0+ + drm->dev_private = sprd;
dev_private is deprecated. Alwyas use upclassing.
Quoted 8 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +8
-0+ +sprd_drm_mode_config_init (drm); + +/* bind and init sub drivers */ + err =component_bind_all (drm->dev, drm); +if (err) { +DRM_ERROR ("failed to bind all component.\n" ); + goto err_dc_cleanup;
drivers/gpu/drm/sprd/sprd_drm.c line 104
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +10
-0+ } + +/* vblank init */ + err =drm_vblank_init (drm, drm->mode_config.num_crtc); +if (err) { +DRM_ERROR ("failed to initialize vblank.\n" ); + goto err_unbind_all; + } +/* with irq_enabled = true, we can use the vblank feature. */ + drm->irq_enabled = true;
Can drm_irq_install() be used?
Then this flag shall not be set by the driver.
Quoted 151 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +122
-0+ +/* reset all the states of crtc/plane/encoder/connector */ +drm_mode_config_reset (drm); + +/* init kms poll for handling hpd */ +drm_kms_helper_poll_init (drm); + + err =drm_dev_register (drm,0 ); +if (err <0 ) + goto err_kms_helper_poll_fini; + +return 0 ; + +err_kms_helper_poll_fini: +drm_kms_helper_poll_fini (drm); +err_unbind_all: +component_unbind_all (drm->dev, drm); +err_dc_cleanup: +drm_mode_config_cleanup (drm); +return err; +} + +static void sprd_drm_unbind (struct device *dev) +{ +struct drm_device *drm =dev_get_drvdata (dev); + +drm_dev_unregister (drm); + +drm_kms_helper_poll_fini (drm); + +drm_mode_config_cleanup (drm); + +component_unbind_all (drm->dev, drm); + drm->dev_private =NULL ; +dev_set_drvdata (dev,NULL ); + +drm_dev_put (drm); +} + +static const struct component_master_ops drm_component_ops = { + .bind = sprd_drm_bind, + .unbind = sprd_drm_unbind, +}; + +static int compare_of (struct device *dev,void *data) +{ +return dev->of_node == data; +} + +static int sprd_drm_probe (struct platform_device *pdev) +{ +int ret; + + ret =dma_set_mask_and_coherent (&pdev->dev, ~0 ); +if (ret) { +DRM_ERROR ("dma_set_mask_and_coherent failed (%d)\n" , ret); +return ret; + } + +return drm_of_component_probe (&pdev->dev, compare_of, &drm_component_ops); +} + +static int sprd_drm_remove (struct platform_device *pdev) +{ +component_master_del (&pdev->dev, &drm_component_ops); +return 0 ; +} + +static void sprd_drm_shutdown (struct platform_device *pdev) +{ +struct drm_device *drm =platform_get_drvdata (pdev); + +if (!drm) { +DRM_WARN ("drm device is not available, no shutdown\n" ); +return ; + } + +drm_atomic_helper_shutdown (drm); +} + +static const struct of_device_id drm_match_table[] = { + { .compatible ="sprd,display-subsystem" , }, + {/* sentinel */ }, +}; +MODULE_DEVICE_TABLE (of, drm_match_table); + +static struct platform_driver sprd_drm_driver = { + .probe = sprd_drm_probe, + .remove = sprd_drm_remove, + .shutdown = sprd_drm_shutdown, + .driver = { + .name ="sprd-drm-drv" , + .of_match_table = drm_match_table, + }, +}; + +static struct platform_driver *sprd_drm_drivers[] = { + &sprd_drm_driver, +}; + +static int __init sprd_drm_init (void ) +{ +int ret; + + ret =platform_register_drivers (sprd_drm_drivers, +ARRAY_SIZE (sprd_drm_drivers)); +return ret; +} + +static void __exit sprd_drm_exit(void) +{ +platform_unregister_drivers (sprd_drm_drivers, +ARRAY_SIZE (sprd_drm_drivers)); +} + +module_init (sprd_drm_init); +module_exit (sprd_drm_exit); + +MODULE_AUTHOR ("Leon He <[email protected]>" ); +MODULE_AUTHOR ("Kevin Tang <[email protected]>" ); +MODULE_DESCRIPTION ("Unisoc DRM KMS Master Driver" ); +MODULE_LICENSE ("GPL v2" );drivers/gpu/drm/sprd/sprd_drm.h new file +16
-0@@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#ifndef _SPRD_DRM_H_ +#define _SPRD_DRM_H_ + +#include <drm/drm_atomic.h> +#include <drm/drm_print.h> + +struct sprd_drm { +struct drm_device *drm; +}; + +#endif /* _SPRD_DRM_H_ */ Signature · 6 lines
2.7.4 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH RFC v6 2/6] drm/sprd: add Unisoc's drm kms master
Quoted 11 lines · Sam Ravnborg <[email protected]> 于2020年7月29日周三 上午4:45写道:
Hi Kevin.
Nice split of the driver.
Some feedback in the following.
Most to bring the driver up-to-date with what have happened since we saw it last time.
Keeping up with the changes in drm is not always easy.Sam
Hi Sam,
Thanks for your feedback,
I am really busy sometimes, but will try my best to keep up with others.
Quoted 183 lines · Kevin Tang
Quoted 73 lines
From: Kevin Tang <[email protected]>
Adds drm support for the Unisoc's display subsystem.
This is drm kms driver, this driver provides support for the application framework in Android, Yocto and more.
Application framework can access Unisoc's display internel peripherals through libdrm or libkms, it's test ok by modetest (DRM/KMS test tool) and Android HWComposer.
Cc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>--- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/sprd/Kconfig | 12 +++ drivers/gpu/drm/sprd/Makefile | 5 + drivers/gpu/drm/sprd/sprd_drm.c | 226 ++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_drm.h | 16 +++ 6 files changed, 262 insertions(+) create mode 100644 drivers/gpu/drm/sprd/Kconfig create mode 100644 drivers/gpu/drm/sprd/Makefile create mode 100644 drivers/gpu/drm/sprd/sprd_drm.c create mode 100644 drivers/gpu/drm/sprd/sprd_drm.hdrivers/gpu/drm/Kconfig +2
-0@@ -386,6 +386,8 @@ source "drivers/gpu/drm/mcde/Kconfig" source "drivers/gpu/drm/tidss/Kconfig" +source "drivers/gpu/drm/sprd/Kconfig" + # Keep legacy drivers last menuconfig DRM_LEGACYdrivers/gpu/drm/Makefile +1
-0@@ -123,3 +123,4 @@ obj-$(CONFIG_DRM_PANFROST) += panfrost/ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ obj-$(CONFIG_DRM_MCDE) += mcde/ obj-$(CONFIG_DRM_TIDSS) += tidss/ +obj-$(CONFIG_DRM_SPRD) += sprd/drivers/gpu/drm/sprd/Kconfig new file +12
-0@@ -0,0 +1,12 @@ +config DRM_SPRD + tristate "DRM Support for Unisoc SoCs Platform" + depends on ARCH_SPRD || COMPILE_TEST + depends on DRM && OF + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select DRM_MIPI_DSI + help + Choose this option if you have a Unisoc chipsets. + If M is selected the module will be called sprd-drm. +drivers/gpu/drm/sprd/Makefile new file +0
-0drivers/gpu/drm/sprd/Makefile line 3
Quoted 3 lines
drivers/gpu/drm/sprd/Makefile new file +3
-0@@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +subdir-ccflags-y += -I$(srctree)/$(src)subdir-ccflags-y is not needed - drop it.
Quoted 40 lines
drivers/gpu/drm/sprd/Makefile new file +2
-0+ +obj-y := sprd_drm.odrivers/gpu/drm/sprd/sprd_drm.c new file +32
-0@@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/component.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of_graph.h> +#include <linux/of_platform.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_drv.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_of.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> + +#include "sprd_drm.h" + +#define DRIVER_NAME "sprd" +#define DRIVER_DESC "Spreadtrum SoCs' DRM Driver" +#define DRIVER_DATE "20200201" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 + +static const struct drm_mode_config_helper_funcs sprd_drm_mode_config_helper = { + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, +};drivers/gpu/drm/sprd/sprd_drm.c line 42
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +10
-0+ +static const struct drm_mode_config_funcs sprd_drm_mode_config_funcs = { + .fb_create = drm_gem_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static void sprd_drm_mode_config_init (struct drm_device *drm) +{ +drm_mode_config_init (drm);The documentation of this functions says:
FIXME: This function is deprecated and drivers should be converted over to
drmm_mode_config_init().Quoted 32 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +32
-0+ + drm->mode_config.min_width =0 ; + drm->mode_config.min_height =0 ; + drm->mode_config.max_width =8192 ; + drm->mode_config.max_height =8192 ; + drm->mode_config.allow_fb_modifiers = true; + + drm->mode_config.funcs = &sprd_drm_mode_config_funcs; + drm->mode_config.helper_private = &sprd_drm_mode_config_helper; +} + +DEFINE_DRM_GEM_CMA_FOPS (sprd_drm_fops); + +static struct drm_driver sprd_drm_drv = { + .driver_features =DRIVER_GEM |DRIVER_MODESET |DRIVER_ATOMIC , + .fops = &sprd_drm_fops, + +/* GEM Operations */ +DRM_GEM_CMA_VMAP_DRIVER_OPS , + + .name =DRIVER_NAME , + .desc =DRIVER_DESC , + .date =DRIVER_DATE , + .major =DRIVER_MAJOR , + .minor =DRIVER_MINOR , +}; + +static int sprd_drm_bind (struct device *dev) +{ +struct drm_device *drm; +struct sprd_drm *sprd; +int err;drivers/gpu/drm/sprd/sprd_drm.c line 84
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +10
-0+ + drm =drm_dev_alloc (&sprd_drm_drv, dev); +if (IS_ERR (drm)) +return PTR_ERR (drm); + +dev_set_drvdata (dev, drm); + + sprd =devm_kzalloc (drm->dev,sizeof (*sprd),GFP_KERNEL ); +if (!sprd) + err = -ENOMEM ;Embed
drm_deviceinsprd_drmand usedevm_drm_dev_allocSee other drivers anddrm_drv.chow to do it.drm_drv.chas a nice example explained in one of the comment blocks.
Quoted 3 lines
drivers/gpu/drm/sprd/sprd_drm.c line 86
Quoted 2 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +2
-0+ + drm->dev_private = sprd;
dev_privateis deprecated. Alwyas use upclassing.
dev_private is deprecated ? I see everyone is still using it, so it will be deprecated in the future?
Quoted 13 lines
Quoted 13 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +12
-0+ +sprd_drm_mode_config_init (drm); + +/* bind and init sub drivers */ + err =component_bind_all (drm->dev, drm); +if (err) { +DRM_ERROR ("failed to bind all component.\n" ); + goto err_dc_cleanup; + } + +/* vblank init */ + err =drm_vblank_init (drm, drm->mode_config.num_crtc);
Quoted 9 lines
drivers/gpu/drm/sprd/sprd_drm.c line 104
Quoted 6 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +6
-0+if (err) { +DRM_ERROR ("failed to initialize vblank.\n" ); + goto err_unbind_all; + } +/* with irq_enabled = true, we can use the vblank feature. */ + drm->irq_enabled = true;Can
drm_irq_install()be used?
Then this flag shall not be set by the driver, And the interrupt numbers on different Soc are not necessarily the same
We need to set "IRQ_NOAUTOEN" flag for CRTC IRQ, you can see that we manually turn the interrupt on and off by crtc atomic_enable/atomic_disable
and the interrupt number on different Soc are not necessarily the same. So intall interrupt in kms maybe is not suitable for us...
Quoted 151 lines
Quoted 151 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +122
-0+ +/* reset all the states of crtc/plane/encoder/connector */ +drm_mode_config_reset (drm); + +/* init kms poll for handling hpd */ +drm_kms_helper_poll_init (drm); + + err =drm_dev_register (drm,0 ); +if (err <0 ) + goto err_kms_helper_poll_fini; + +return 0 ; + +err_kms_helper_poll_fini: +drm_kms_helper_poll_fini (drm); +err_unbind_all: +component_unbind_all (drm->dev, drm); +err_dc_cleanup: +drm_mode_config_cleanup (drm); +return err; +} + +static void sprd_drm_unbind (struct device *dev) +{ +struct drm_device *drm =dev_get_drvdata (dev); + +drm_dev_unregister (drm); + +drm_kms_helper_poll_fini (drm); + +drm_mode_config_cleanup (drm); + +component_unbind_all (drm->dev, drm); + drm->dev_private =NULL ; +dev_set_drvdata (dev,NULL ); + +drm_dev_put (drm); +} + +static const struct component_master_ops drm_component_ops = { + .bind = sprd_drm_bind, + .unbind = sprd_drm_unbind, +}; + +static int compare_of (struct device *dev,void *data) +{ +return dev->of_node == data; +} + +static int sprd_drm_probe (struct platform_device *pdev) +{ +int ret; + + ret =dma_set_mask_and_coherent (&pdev->dev, ~0 ); +if (ret) { +DRM_ERROR ("dma_set_mask_and_coherent failed (%d)\n" , ret); +return ret; + } + +return drm_of_component_probe (&pdev->dev, compare_of, &drm_component_ops); +} + +static int sprd_drm_remove (struct platform_device *pdev) +{ +component_master_del (&pdev->dev, &drm_component_ops); +return 0 ; +} + +static void sprd_drm_shutdown (struct platform_device *pdev) +{ +struct drm_device *drm =platform_get_drvdata (pdev); + +if (!drm) { +DRM_WARN ("drm device is not available, no shutdown\n" ); +return ; + } + +drm_atomic_helper_shutdown (drm); +} + +static const struct of_device_id drm_match_table[] = { + { .compatible ="sprd,display-subsystem" , }, + {/* sentinel */ }, +}; +MODULE_DEVICE_TABLE (of, drm_match_table); + +static struct platform_driver sprd_drm_driver = { + .probe = sprd_drm_probe, + .remove = sprd_drm_remove, + .shutdown = sprd_drm_shutdown, + .driver = { + .name ="sprd-drm-drv" , + .of_match_table = drm_match_table, + }, +}; + +static struct platform_driver *sprd_drm_drivers[] = { + &sprd_drm_driver, +}; + +static int __init sprd_drm_init (void ) +{ +int ret; + + ret =platform_register_drivers (sprd_drm_drivers, +ARRAY_SIZE (sprd_drm_drivers)); +return ret; +} + +static void __exit sprd_drm_exit(void) +{ +platform_unregister_drivers (sprd_drm_drivers, +ARRAY_SIZE (sprd_drm_drivers)); +} + +module_init (sprd_drm_init); +module_exit (sprd_drm_exit); + +MODULE_AUTHOR ("Leon He <[email protected]>" ); +MODULE_AUTHOR ("Kevin Tang <[email protected]>" ); +MODULE_DESCRIPTION ("Unisoc DRM KMS Master Driver" ); +MODULE_LICENSE ("GPL v2" );drivers/gpu/drm/sprd/sprd_drm.h new file +16
-1@@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#ifndef _SPRD_DRM_H_ +#define _SPRD_DRM_H_ + +#include <drm/drm_atomic.h> +#include <drm/drm_print.h> + +struct sprd_drm { +struct drm_device *drm; +}; + +#endif /* _SPRD_DRM_H_ */ --2.7.4
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH RFC v6 2/6] drm/sprd: add Unisoc's drm kms master
Hi Kevin
Quoted 6 lines
Quoted 4 lines
Review
Quoted 3 lines
(quoted diff) +2
-0+ + drm->dev_private = sprd;
dev_privateis deprecated. Alwyas use upclassing.
dev_privateis deprecated ? I see everyone is still using it, so it will be deprecated in the future?
It is deprecated - and a lot of drivers is in need up an update to get away from using it.
From the kernel-doc:
/**
* @dev_private:
*
* DRM driver private data. This is deprecated and should be left set to
* NULL.
*
* Instead of using this pointer it is recommended that drivers use
* drm_dev_init() and embed struct &drm_device in their larger
* per-device structure.
*/
void *dev_private;
Quoted 11 lines
Quoted 6 lines
drivers/gpu/drm/sprd/sprd_drm.c line 104
Quoted 3 lines
drivers/gpu/drm/sprd/sprd_drm.c new file +3
-0+ } +/* with irq_enabled = true, we can use the vblank feature. */ + drm->irq_enabled = true;Can
drm_irq_install()be used?
Then this flag shall not be set by the driver, And the interrupt numbers on different Soc are not necessarily the sameWe need to set "
IRQ_NOAUTOEN" flag for CRTC IRQ, you can see that we manually turn the interrupt on and off by crtc atomic_enable/atomic_disable
and the interrupt number on different Soc are not necessarily the same. So intall interrupt in kms maybe is not suitable for us...
Maybe drm_irq_install() does not fit the need here. But please take an extra look as what is does is quite basic. And no need to roll your own if there is available infrstructure that can be used.
But there is nothing wrong rolloing your own if needed.
Sam
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
RFC PATCH v6 3/6 dt-bindings: display: add Unisoc's dpu bindings
In reply to Kevin TangFrom: Kevin Tang <[email protected]>
DPU (Display Processor Unit) is the Display Controller for the Unisoc SoCs which transfers the image data from a video memory buffer to an internal LCD interface.
--- .../devicetree/bindings/display/sprd/dpu.yaml | 82 ++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/dpu.yaml
Documentation/devicetree/bindings/display/sprd/dpu.yaml new file +82 -0
@@ -0,0 +1,82 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/sprd/dpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc SoC Display Processor Unit (DPU) + +maintainers: + - Mark Rutland <[email protected]> + +description: | + DPU (Display Processor Unit) is the Display Controller for the Unisoc SoCs + which transfers the image data from a video memory buffer to an internal + LCD interface. + +properties: + compatible: + const: sprd,sharkl3-dpu + + reg: + maxItems: 1 + description: + Physical base address and length of the DPU registers set + + interrupts: + maxItems: 1 + description: + The interrupt signal from DPU + + clocks: + minItems: 2 + + clock-names: + items: + - const: clk_src_128m + - const: clk_src_384m + + power-domains: + description: A phandle to DPU power domain node. + + iommus: + description: A phandle to DPU iommu node. + + port: + type: object + description: + A port node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + That port should be the output endpoint, usually output to + the associated DSI. + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - port + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/clock/sprd,sc9860-clk.h> + dpu: dpu@0x63000000 { + compatible = "sprd,sharkl3-dpu"; + reg = <0x0 0x63000000 0x0 0x1000>; + interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "clk_src_128m", + "clk_src_384m"; + + clocks = <&pll CLK_TWPLL_128M>, + <&pll CLK_TWPLL_384M>; + + dpu_port: port { + dpu_out: endpoint { + remote-endpoint = <&dsi_in>; + }; + }; + };
Signature · 1 line
2.7.4
Re: [PATCH RFC v6 3/6] dt-bindings: display: add Unisoc's dpu bindings
Hi Kevin.
Quoted 11 lines · Kevin Tang
From: Kevin Tang <[email protected]>
DPU (Display Processor Unit) is the Display Controller for the Unisoc SoCs which transfers the image data from a video memory buffer to an internal LCD interface.
Cc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>--- .../devicetree/bindings/display/sprd/dpu.yaml | 82 ++++++++++++++++++++++
Could we name it after the compatible "sharkl3-dpu.yaml"?
Documentation/devicetree/bindings/display/sprd/dpu.yaml line 1
Quoted 10 lines
1 file changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/dpu.yamlDocumentation/devicetree/bindings/display/sprd/dpu.yaml new file +1
-0@@ -0,0 +1,82 @@ +# SPDX-License-Identifier: GPL-2.0
Can this be: (GPL-2.0-only OR BSD-2-Clause)
Quoted 29 lines
Documentation/devicetree/bindings/display/sprd/dpu.yaml new file +29
-0+%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/sprd/dpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc SoC Display Processor Unit (DPU) + +maintainers: + - Mark Rutland <[email protected]> + +description: | + DPU (Display Processor Unit) is the Display Controller for the Unisoc SoCs + which transfers the image data from a video memory buffer to an internal + LCD interface. + +properties: + compatible: + const: sprd,sharkl3-dpu + + reg: + maxItems: 1 + description: + Physical base address and length of the DPU registers set + + interrupts: + maxItems: 1 + description: + The interrupt signal from DPU +
Documentation/devicetree/bindings/display/sprd/dpu.yaml line 40
Quoted 10 lines
Documentation/devicetree/bindings/display/sprd/dpu.yaml new file +10
-0+ clocks: + minItems: 2 + + clock-names: + items: + - const: clk_src_128m + - const: clk_src_384m + + power-domains: + description: A phandle to DPU power domain node.
maxItems: 1
Documentation/devicetree/bindings/display/sprd/dpu.yaml line 43
Quoted 3 lines
Documentation/devicetree/bindings/display/sprd/dpu.yaml new file +3
-0+ + iommus: + description: A phandle to DPU iommu node.
maxItems: 1
Quoted 29 lines
Documentation/devicetree/bindings/display/sprd/dpu.yaml new file +29
-0+ + port: + type: object + description: + A port node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + That port should be the output endpoint, usually output to + the associated DSI. + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - port + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/clock/sprd,sc9860-clk.h> + dpu: dpu@0x63000000 { + compatible = "sprd,sharkl3-dpu"; + reg = <0x0 0x63000000 0x0 0x1000>; + interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "clk_src_128m", + "clk_src_384m";
Documentation/devicetree/bindings/display/sprd/dpu.yaml line 82
Quoted 10 lines
Documentation/devicetree/bindings/display/sprd/dpu.yaml new file +10
-0+ + clocks = <&pll CLK_TWPLL_128M>, + <&pll CLK_TWPLL_384M>; + + dpu_port: port { + dpu_out: endpoint { + remote-endpoint = <&dsi_in>; + }; + }; + };
Be consistent in indent. Now it is a mix of 6 and 8 spaces. (My preference is 4 spaces, but 2,4,6,8 are all OK)
End the file with and end statement like this:
<empty line>
...
Quoted 7 lines
Signature · 6 lines
2.7.4 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
RFC PATCH v6 4/6 drm/sprd: add Unisoc's drm display controller driver
In reply to Kevin TangFrom: Kevin Tang <[email protected]>
Adds DPU(Display Processor Unit) support for the Unisoc's display subsystem. It's support multi planes, scaler, rotation, PQ(Picture Quality) and more.
RFC v6:
- Access registers via readl/writel
- Checking for unsupported KMS properties (format, rotation, blend_mode, etc) on plane_check ops
- Remove always true checks for dpu core ops
--- drivers/gpu/drm/sprd/Makefile | 5 +- drivers/gpu/drm/sprd/dpu/Makefile | 3 + drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 503 ++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.c | 646 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.h | 187 +++++++++++ drivers/gpu/drm/sprd/sprd_drm.c | 1 + drivers/gpu/drm/sprd/sprd_drm.h | 2 + 7 files changed, 1346 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.h
drivers/gpu/drm/sprd/Makefile +4 -1
@@ -2,4 +2,7 @@ subdir-ccflags-y += -I$(srctree)/$(src) -obj-y := sprd_drm.o +obj-y := sprd_drm.o \ + sprd_dpu.o + +obj-y += dpu/
drivers/gpu/drm/sprd/dpu/Makefile new file +3 -0
@@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += dpu_r2p0.o
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +503 -0
503 lines not on this page · raw message
drivers/gpu/drm/sprd/sprd_dpu.c new file +646 -0
646 lines not on this page · raw message
drivers/gpu/drm/sprd/sprd_dpu.h new file +187 -0
187 lines not on this page · raw message
drivers/gpu/drm/sprd/sprd_drm.c +1 -0
@@ -200,6 +200,7 @@ static struct platform_driver sprd_drm_driver = {static struct platform_driver *sprd_drm_drivers[] = { &sprd_drm_driver, + &sprd_dpu_driver, };static int __init sprd_drm_init (void )
drivers/gpu/drm/sprd/sprd_drm.h +2 -0
@@ -13,4 +13,6 @@ struct sprd_drm { struct drm_device *drm; }; +extern struct platform_driver sprd_dpu_driver; +#endif /* _SPRD_DRM_H_ */
Signature · 1 line
2.7.4
Re: [PATCH RFC v6 4/6] drm/sprd: add Unisoc's drm display controller driver
Hi Kevin.
Some feedback in the following.
I lost track of thing for the atomic modesettting stuff and I hope other will review that.
Sam
Quoted 32 lines · Kevin Tang
From: Kevin Tang <[email protected]>
Adds DPU(Display Processor Unit) support for the Unisoc's display subsystem. It's support multi planes, scaler, rotation, PQ(Picture Quality) and more.
RFC v6:
- Access registers via readl/writel
- Checking for unsupported KMS properties (format, rotation,blend_mode, etc) onplane_checkops
- Remove always true checks for dpu core opsCc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>--- drivers/gpu/drm/sprd/Makefile | 5 +- drivers/gpu/drm/sprd/dpu/Makefile | 3 + drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 503 ++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.c | 646 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.h | 187 +++++++++++ drivers/gpu/drm/sprd/sprd_drm.c | 1 + drivers/gpu/drm/sprd/sprd_drm.h | 2 + 7 files changed, 1346 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.hdrivers/gpu/drm/sprd/Makefile +0
-0
drivers/gpu/drm/sprd/Makefile line 3
Quoted 2 lines
drivers/gpu/drm/sprd/Makefile +0
-0@@ -2,4 +2,7 @@ subdir-ccflags-y += -I$(srctree)/$(src)
Not needed - drop.
drivers/gpu/drm/sprd/Makefile line 8
Quoted 6 lines
drivers/gpu/drm/sprd/Makefile +4
-1-obj-y := sprd_drm.o +obj-y := sprd_drm.o \ + sprd_dpu.o + +obj-y += dpu/
Until there are several DPU's there is no need for a separate directory. Make it simpler by keeping it all in drm/sprd/*
Quoted 25 lines
drivers/gpu/drm/sprd/dpu/Makefile new file +3
-0@@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += dpu_r2p0.odrivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0@@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/workqueue.h> +
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 20
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+#include "sprd_dpu.h" + +/* DPU registers size, 4 Bytes(32 Bits) */ +#define DPU_REG_SIZE 0x04 + +/* Layer registers offset */ +#define DPU_LAY_REG_OFFSET 0x0C + +#define DPU_LAY_REG (reg, index) \ + (reg + index * DPU_LAY_REG_OFFSET * DPU_REG_SIZE)
Use a static inline to get better typecheck.
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 30
Quoted 9 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +9
-0+#define DPU_REG_RD (reg) readl_relaxed(reg) + +#define DPU_REG_WR (reg, mask) writel_relaxed(mask, reg) + +#define DPU_REG_SET (reg, mask) \ + writel_relaxed(readl_relaxed(reg) | mask, reg) + +#define DPU_REG_CLR (reg, mask) \ + writel_relaxed(readl_relaxed(reg) & ~mask, reg)
I am no fan of macros used like this.
Maybe use static inlines and add struct dpu_context * as first argument. Then adding base can be hidden away.
I had a hard time convincing myself that _relaxed was the right variants. If I get it correct we may see writes re-ordered with the _relaxed variants wich would be no good when dealign with interrupts. But I may miss somethign here.
Quoted 75 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +75
-0+ +/* Global control registers */ +#define REG_DPU_CTRL 0x04 +#define REG_DPU_CFG0 0x08 +#define REG_DPU_CFG1 0x0C +#define REG_DPU_CFG2 0x10 +#define REG_PANEL_SIZE 0x20 +#define REG_BLEND_SIZE 0x24 +#define REG_BG_COLOR 0x2C + +/* Layer0 control registers */ +#define REG_LAY_BASE_ADDR0 0x30 +#define REG_LAY_BASE_ADDR1 0x34 +#define REG_LAY_BASE_ADDR2 0x38 +#define REG_LAY_CTRL 0x40 +#define REG_LAY_SIZE 0x44 +#define REG_LAY_PITCH 0x48 +#define REG_LAY_POS 0x4C +#define REG_LAY_ALPHA 0x50 +#define REG_LAY_PALLETE 0x58 +#define REG_LAY_CROP_START 0x5C + +/* Interrupt control registers */ +#define REG_DPU_INT_EN 0x1E0 +#define REG_DPU_INT_CLR 0x1E4 +#define REG_DPU_INT_STS 0x1E8 + +/* DPI control registers */ +#define REG_DPI_CTRL 0x1F0 +#define REG_DPI_H_TIMING 0x1F4 +#define REG_DPI_V_TIMING 0x1F8 + +/* MMU control registers */ +#define REG_MMU_EN 0x800 +#define REG_MMU_VPN_RANGE 0x80C +#define REG_MMU_VAOR_ADDR_RD 0x818 +#define REG_MMU_VAOR_ADDR_WR 0x81C +#define REG_MMU_INV_ADDR_RD 0x820 +#define REG_MMU_INV_ADDR_WR 0x824 +#define REG_MMU_PPN1 0x83C +#define REG_MMU_RANGE1 0x840 +#define REG_MMU_PPN2 0x844 +#define REG_MMU_RANGE2 0x848 + +/* Global control bits */ +#define BIT_DPU_RUN BIT(0) +#define BIT_DPU_STOP BIT(1) +#define BIT_DPU_REG_UPDATE BIT(2) +#define BIT_DPU_IF_EDPI BIT(0) +#define BIT_DPU_COEF_NARROW_RANGE BIT(4) +#define BIT_DPU_Y2R_COEF_ITU709_STANDARD BIT(5) + +/* Layer control bits */ +#define BIT_DPU_LAY_EN BIT(0) + +/* Interrupt control & status bits */ +#define BIT_DPU_INT_DONE BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_FBC_PLD_ERR BIT(8) +#define BIT_DPU_INT_FBC_HDR_ERR BIT(9) +#define BIT_DPU_INT_MMU_VAOR_RD BIT(16) +#define BIT_DPU_INT_MMU_VAOR_WR BIT(17) +#define BIT_DPU_INT_MMU_INV_RD BIT(18) +#define BIT_DPU_INT_MMU_INV_WR BIT(19) + +/* DPI control bits */ +#define BIT_DPU_EDPI_TE_EN BIT(8) +#define BIT_DPU_EDPI_FROM_EXTERNAL_PAD BIT(10) +#define BIT_DPU_DPI_HALT_EN BIT(16) + + +static u32 check_mmu_isr (struct dpu_context *ctx,u32 reg_val)
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 115
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+{ +u32 mmu_mask =BIT_DPU_INT_MMU_VAOR_RD | +BIT_DPU_INT_MMU_VAOR_WR | +BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +u32 val = reg_val & mmu_mask; +int i; + +if (val) { +DRM_ERROR ("--- iommu interrupt err: 0x%04x ---\n" , val);
General comment, applies for the whole patch.
Use drm_err(drm, ...), drm_info(drm, ...) etc.
Use upclassing to get sprd_dpu - and then you have a drm_device * (After drm_device is embedded in sprd_dpu as suggested in the other mail)
Quoted 158 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +158
-0+ +if (val &BIT_DPU_INT_MMU_INV_RD ) +DRM_ERROR ("iommu invalid read error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_INV_ADDR_RD )); +if (val &BIT_DPU_INT_MMU_INV_WR ) +DRM_ERROR ("iommu invalid write error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_INV_ADDR_WR )); +if (val &BIT_DPU_INT_MMU_VAOR_RD ) +DRM_ERROR ("iommu va out of range read error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_VAOR_ADDR_RD )); +if (val &BIT_DPU_INT_MMU_VAOR_WR ) +DRM_ERROR ("iommu va out of range write error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_VAOR_ADDR_WR )); + +for (i =0 ; i <8 ; i++) { + reg_val =DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i)); +if (reg_val &0x1 ) +DRM_INFO ("layer%d: 0x%08x 0x%08x 0x%08x ctrl: 0x%08x\n" , i, +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR0 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR1 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR2 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i))); + } + } + +return val; +} + +static void dpu_clean_all (struct dpu_context *ctx) +{ +int i; + +for (i =0 ; i <8 ; i++) +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i),0x00 ); +} + +static u32 dpu_isr (struct dpu_context *ctx) +{ +u32 reg_val, int_mask =0 ; + + reg_val =DPU_REG_RD (ctx->base +REG_DPU_INT_STS ); + +/* disable err interrupt */ +if (reg_val &BIT_DPU_INT_ERR ) + int_mask |=BIT_DPU_INT_ERR ; + +/* dpu update done isr */ +if (reg_val &BIT_DPU_INT_UPDATE_DONE ) { + ctx->evt_update = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu stop done isr */ +if (reg_val &BIT_DPU_INT_DONE ) { + ctx->evt_stop = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu ifbc payload error isr */ +if (reg_val &BIT_DPU_INT_FBC_PLD_ERR ) { + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +DRM_ERROR ("dpu ifbc payload error\n" ); + } + +/* dpu ifbc header error isr */ +if (reg_val &BIT_DPU_INT_FBC_HDR_ERR ) { + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +DRM_ERROR ("dpu ifbc header error\n" ); + } + + int_mask |=check_mmu_isr (ctx, reg_val); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR , reg_val); +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN , int_mask); + +return reg_val; +} + +static int dpu_wait_stop_done (struct dpu_context *ctx) +{ +int rc; + +if (ctx->stopped) +return 0 ; + + rc =wait_event_interruptible_timeout (ctx->wait_queue, ctx->evt_stop, +msecs_to_jiffies (500 )); + ctx->evt_stop = false; + + ctx->stopped = true; + +if (!rc) { +DRM_ERROR ("dpu wait for stop done time out!\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +static int dpu_wait_update_done (struct dpu_context *ctx) +{ +int rc; + + ctx->evt_update = false; + + rc =wait_event_interruptible_timeout (ctx->wait_queue, ctx->evt_update, +msecs_to_jiffies (500 )); + +if (!rc) { +DRM_ERROR ("dpu wait for reg update done time out!\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +static void dpu_stop (struct dpu_context *ctx) +{ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_STOP ); + +dpu_wait_stop_done (ctx); +} + +static void dpu_run (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; +} + +static void dpu_init (struct dpu_context *ctx) +{ +u32 reg_val, size; + +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + + size = (ctx->vm.vactive <<16 ) | ctx->vm.hactive; + +DPU_REG_WR (ctx->base +REG_PANEL_SIZE , size); +DPU_REG_WR (ctx->base +REG_BLEND_SIZE , size); + + reg_val =BIT_DPU_COEF_NARROW_RANGE |BIT_DPU_Y2R_COEF_ITU709_STANDARD ; +DPU_REG_WR (ctx->base +REG_DPU_CFG0 , reg_val); +DPU_REG_WR (ctx->base +REG_DPU_CFG1 ,0x004466da ); +DPU_REG_WR (ctx->base +REG_DPU_CFG2 ,0x00 ); + +if (ctx->stopped) +dpu_clean_all (ctx); + +DPU_REG_WR (ctx->base +REG_MMU_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_PPN1 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE1 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_PPN2 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE2 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_VPN_RANGE ,0x1ffff ); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xffff );
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 283
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+} + +static void dpu_fini (struct dpu_context *ctx) +{ +DPU_REG_WR (ctx->base +REG_DPU_INT_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xff ); +} + +static void dpu_layer (struct dpu_context *ctx, +struct dpu_layer *hwlayer)
No linebreak needed here.
Quoted 189 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +189
-0+{ +const struct drm_format_info *info; +u32 size, offset, ctrl, pitch; +int i; + + offset = (hwlayer->dst_x &0xffff ) | ((hwlayer->dst_y) <<16 ); + +if (hwlayer->src_w && hwlayer->src_h) + size = (hwlayer->src_w &0xffff ) | ((hwlayer->src_h) <<16 ); +else + size = (hwlayer->dst_w &0xffff ) | ((hwlayer->dst_h) <<16 ); + +for (i =0 ; i < hwlayer->planes; i++) +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR0 , + hwlayer->index), hwlayer->addr[i]); + +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_POS , + hwlayer->index), offset); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_SIZE , + hwlayer->index), size); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CROP_START , + hwlayer->index), hwlayer->src_y <<16 | hwlayer->src_x); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_ALPHA , + hwlayer->index), hwlayer->alpha); + + info =drm_format_info (hwlayer->format); +if (hwlayer->planes ==3 ) { +/* UV pitch is 1/2 of Y pitch*/ + pitch = (hwlayer->pitch[0 ] / info->cpp[0 ]) | + (hwlayer->pitch[0 ] / info->cpp[0 ] <<15 ); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + }else { + pitch = hwlayer->pitch[0 ] / info->cpp[0 ]; +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + } + + ctrl = hwlayer->format | + hwlayer->blending | + (hwlayer->rotation &0x7 ) <<20 ; + +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index), ctrl); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index),BIT_DPU_LAY_EN ); + +DRM_DEBUG ("dst_x = %d, dst_y = %d, dst_w = %d, dst_h = %d\n" , + hwlayer->dst_x, hwlayer->dst_y, + hwlayer->dst_w, hwlayer->dst_h); +DRM_DEBUG ("start_x = %d, start_y = %d, start_w = %d, start_h = %d\n" , + hwlayer->src_x, hwlayer->src_y, + hwlayer->src_w, hwlayer->src_h); +} + +static void dpu_flip (struct dpu_context *ctx, +struct dpu_layer layers[],u8 count) +{ +int i; +u32 reg_val; + +/* +* Make sure the dpu is in stop status. DPU_R2P0 has no shadow +* registers in EDPI mode. So the config registers can only be +* updated in the rising edge of DPU_RUN bit. +*/ +if (ctx->if_type ==SPRD_DPU_IF_EDPI ) +dpu_wait_stop_done (ctx); + +/* reset the bgcolor to black */ +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + +/* disable all the layers */ +dpu_clean_all (ctx); + +/* start configure dpu layers */ +for (i =0 ; i < count; i++) +dpu_layer (ctx, &layers[i]); + +/* update trigger and wait */ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +if (!ctx->stopped) { +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_REG_UPDATE ); +dpu_wait_update_done (ctx); + } + +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_ERR ); + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; + } + +/* +* If the following interrupt was disabled in isr, +* re-enable it. +*/ + reg_val =BIT_DPU_INT_FBC_PLD_ERR | +BIT_DPU_INT_FBC_HDR_ERR | +BIT_DPU_INT_MMU_VAOR_RD | +BIT_DPU_INT_MMU_VAOR_WR | +BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +DPU_REG_SET (ctx->base +REG_DPU_INT_EN , reg_val); + +} + +static void dpu_dpi_init (struct dpu_context *ctx) +{ +u32 int_mask =0 ; +u32 reg_val; + +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +/* use dpi as interface */ +DPU_REG_CLR (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* disable Halt function for SPRD DSI */ +DPU_REG_CLR (ctx->base +REG_DPI_CTRL ,BIT_DPU_DPI_HALT_EN ); + +/* select te from external pad */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_FROM_EXTERNAL_PAD ); + +/* set dpi timing */ + reg_val = ctx->vm.hsync_len <<0 | + ctx->vm.hback_porch <<8 | + ctx->vm.hfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_H_TIMING , reg_val); + + reg_val = ctx->vm.vsync_len <<0 | + ctx->vm.vback_porch <<8 | + ctx->vm.vfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_V_TIMING , reg_val); + +if (ctx->vm.vsync_len + ctx->vm.vback_porch <32 ) +DRM_WARN ("Warning: (vsync + vbp) < 32, " +"underflow risk!\n" ); + +/* enable dpu update done INT */ + int_mask |=BIT_DPU_INT_UPDATE_DONE ; +/* enable dpu DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable dpu dpi vsync */ + int_mask |=BIT_DPU_INT_VSYNC ; +/* enable dpu TE INT */ + int_mask |=BIT_DPU_INT_TE ; +/* enable underflow err INT */ + int_mask |=BIT_DPU_INT_ERR ; + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +/* use edpi as interface */ +DPU_REG_SET (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* use external te */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_FROM_EXTERNAL_PAD ); + +/* enable te */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_TE_EN ); + +/* enable stop DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable TE INT */ + int_mask |=BIT_DPU_INT_TE ; + } + +/* enable ifbc payload error INT */ + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +/* enable ifbc header error INT */ + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +/* enable iommu va out of range read error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_RD ; +/* enable iommu va out of range write error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_WR ; +/* enable iommu invalid read error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_RD ; +/* enable iommu invalid write error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_WR ; + +DPU_REG_WR (ctx->base +REG_DPU_INT_EN , int_mask); +} + +static void enable_vsync (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} + +static void disable_vsync (struct dpu_context *ctx) +{ +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} +
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 482
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+static const u32 primary_fmts[] = { +DRM_FORMAT_XRGB8888 ,DRM_FORMAT_XBGR8888 , +DRM_FORMAT_ARGB8888 ,DRM_FORMAT_ABGR8888 , +DRM_FORMAT_RGBA8888 ,DRM_FORMAT_BGRA8888 , +DRM_FORMAT_RGBX8888 ,DRM_FORMAT_RGB565 , +DRM_FORMAT_BGR565 ,DRM_FORMAT_NV12 , +DRM_FORMAT_NV21 ,DRM_FORMAT_NV16 , +DRM_FORMAT_NV61 ,DRM_FORMAT_YUV420 , +DRM_FORMAT_YVU420 , +};
One format per line improves readability a lot.
Maybe sort alphbetically too.
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 485
Quoted 3 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +3
-0+ +static void dpu_capability (struct dpu_context *ctx, +struct dpu_capability *cap)
Drop linebreak
Quoted 893 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +18
-0+{ + cap->max_layers =6 ; + cap->fmts_ptr = primary_fmts; + cap->fmts_cnt =ARRAY_SIZE (primary_fmts); +} + +const struct dpu_core_ops dpu_r2p0_core_ops = { + .init = dpu_init, + .fini = dpu_fini, + .run = dpu_run, + .stop = dpu_stop, + .isr = dpu_isr, + .ifconfig = dpu_dpi_init, + .capability = dpu_capability, + .flip = dpu_flip, + .enable_vsync = enable_vsync, + .disable_vsync = disable_vsync, +};drivers/gpu/drm/sprd/sprd_dpu.c new file +646
-0@@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/component.h> +#include <linux/dma-buf.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_plane_helper.h> + +#include "sprd_drm.h" +#include "sprd_dpu.h" + +struct sprd_plane { +struct drm_plane plane; +u32 index; +u32 addr[4 ]; +u32 pitch[4 ]; +u32 format; +u32 rotation; +u32 blend_mode; +}; + +static void sprd_dpu_init (struct sprd_dpu *dpu); +static void sprd_dpu_fini (struct sprd_dpu *dpu); + +static inline struct sprd_plane *to_sprd_plane (struct drm_plane *plane) +{ + return container_of(plane, struct sprd_plane, plane); +} + +static int sprd_plane_format_convert (u32 fourcc,u32 *format) +{ +switch (fourcc) { +case DRM_FORMAT_BGRA8888 : +/* BGRA8888 -> ARGB8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_RGBX8888 : +case DRM_FORMAT_RGBA8888 : +/* RGBA8888 -> ABGR8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* FALLTHRU */ +case DRM_FORMAT_ABGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_ARGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_XBGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_XRGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_BGR565 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_RGB565 : + *format |=BIT_DPU_LAY_FORMAT_RGB565 ; +break ; +case DRM_FORMAT_NV12 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_NV21 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV16 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV61 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YUV420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YVU420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_rotation_convert (u32 angle,u32 *rotation) +{ +switch (angle) { +case DRM_MODE_ROTATE_0 : + *rotation =DPU_LAYER_ROTATION_0 ; +break ; +case DRM_MODE_ROTATE_90 : + *rotation =DPU_LAYER_ROTATION_90 ; +break ; +case DRM_MODE_ROTATE_180 : + *rotation =DPU_LAYER_ROTATION_180 ; +break ; +case DRM_MODE_ROTATE_270 : + *rotation =DPU_LAYER_ROTATION_270 ; +break ; +case DRM_MODE_REFLECT_Y : + *rotation =DPU_LAYER_ROTATION_180_M ; +break ; +case (DRM_MODE_REFLECT_Y |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_90_M ; +break ; +case DRM_MODE_REFLECT_X : + *rotation =DPU_LAYER_ROTATION_0_M ; +break ; +case (DRM_MODE_REFLECT_X |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_270_M ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_atomic_check (struct drm_plane *plane, +struct drm_plane_state *state) +{ +struct sprd_plane *p =to_sprd_plane (plane); +struct drm_framebuffer *fb = state->fb; +struct drm_gem_cma_object *cma_obj; +int i, ret; +u32 addr; + +if (!state->fb || !state->crtc) +return 0 ; + + ret =sprd_plane_format_convert (fb->format->format, + &p->format); +if (ret <0 ) { +DRM_ERROR ("Invalid plane format\n" ); +return ret; + } + + ret =sprd_plane_rotation_convert (state->rotation, + &p->rotation); +if (ret <0 ) { +DRM_ERROR ("Invalid plane rotation\n" ); +return ret; + } + +switch (state->pixel_blend_mode) { +case DRM_MODE_BLEND_COVERAGE : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Normal mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_NORMAL ; +break ; +case DRM_MODE_BLEND_PREMULTI : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Pre-mult mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_PREMULT ; +break ; +case DRM_MODE_BLEND_PIXEL_NONE : +default : +/* don't do blending, maybe RGBX */ +/* alpha mode select - layer alpha */ + p->blend_mode |=BIT_DPU_LAY_LAYER_ALPHA ; +break ; + } + +for (i =0 ; i < fb->format->num_planes; i++) { + cma_obj =drm_fb_cma_get_gem_obj (fb, i); + addr = cma_obj->paddr + fb->offsets[i]; +if (addr %16 ) { +DRM_ERROR ("layer addr[%d] is not 16 bytes align, it's 0x%08x\n" , + i, addr); +return -EFAULT ; + } + + p->addr[i] = addr; + p->pitch[i] = fb->pitches[i]; + } + +return 0 ; +} + +static void sprd_plane_atomic_update (struct drm_plane *plane, +struct drm_plane_state *old_state) +{ +struct drm_plane_state *state = plane->state; +struct drm_framebuffer *fb = plane->state->fb; +struct sprd_plane *p =to_sprd_plane (plane); +struct sprd_dpu *dpu =crtc_to_dpu (plane->state->crtc); +struct dpu_layer *layer = &dpu->layers[p->index]; +int i; + +if (!state->crtc || !state->fb) +return ; + + layer->index = p->index; + layer->src_x = state->src_x >>16 ; + layer->src_y = state->src_y >>16 ; + layer->src_w = state->src_w >>16 ; + layer->src_h = state->src_h >>16 ; + layer->dst_x = state->crtc_x; + layer->dst_y = state->crtc_y; + layer->dst_w = state->crtc_w; + layer->dst_h = state->crtc_h; + layer->alpha = state->alpha; + layer->format = p->format; + layer->blending = p->blend_mode; + layer->rotation = p->rotation; + layer->planes = fb->format->num_planes; + +for (i =0 ; i < layer->planes; i++) { + layer->addr[i] = p->addr[i]; + layer->pitch[i] = p->pitch[i]; + } + + dpu->pending_planes++; +} + +static void sprd_plane_create_properties (struct sprd_plane *p,int index) +{ +unsigned int supported_modes =BIT (DRM_MODE_BLEND_PIXEL_NONE ) | +BIT (DRM_MODE_BLEND_PREMULTI ) | +BIT (DRM_MODE_BLEND_COVERAGE ); + +/* create rotation property */ +drm_plane_create_rotation_property (&p->plane, +DRM_MODE_ROTATE_0 , +DRM_MODE_ROTATE_MASK | +DRM_MODE_REFLECT_MASK ); + +/* create alpha property */ +drm_plane_create_alpha_property (&p->plane); + +/* create blend mode property */ +drm_plane_create_blend_mode_property (&p->plane, supported_modes); + +/* create zpos property */ +drm_plane_create_zpos_immutable_property (&p->plane, index); +} + +static const struct drm_plane_helper_funcs sprd_plane_helper_funcs = { + .atomic_check = sprd_plane_atomic_check, + .atomic_update = sprd_plane_atomic_update, +}; + +static const struct drm_plane_funcs sprd_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static struct drm_plane *sprd_plane_init (struct drm_device *drm, +struct sprd_dpu *dpu) +{ +struct drm_plane *primary =NULL ; +struct sprd_plane *p =NULL ; +struct dpu_capability cap = {}; +int ret, i; + + dpu->core->capability (&dpu->ctx, &cap); + + dpu->layers =devm_kcalloc (drm->dev, cap.max_layers, +sizeof (struct dpu_layer ),GFP_KERNEL ); +if (!dpu->layers) +return ERR_PTR (-ENOMEM ); + +for (i =0 ; i < cap.max_layers; i++) { + + p =devm_kzalloc (drm->dev,sizeof (*p),GFP_KERNEL ); +if (!p) +return ERR_PTR (-ENOMEM ); + + ret =drm_universal_plane_init (drm, &p->plane,1 , + &sprd_plane_funcs, cap.fmts_ptr, + cap.fmts_cnt,NULL , +DRM_PLANE_TYPE_PRIMARY ,NULL ); +if (ret) { +DRM_ERROR ("fail to init primary plane\n" ); +return ERR_PTR (ret); + } + +drm_plane_helper_add (&p->plane, &sprd_plane_helper_funcs); + +sprd_plane_create_properties (p, i); + + p->index = i; +if (i ==0 ) + primary = &p->plane; + } + +return primary; +} + +static enum drm_mode_status sprd_crtc_mode_valid (struct drm_crtc *crtc, +const struct drm_display_mode *mode) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +DRM_DEBUG ("%s() mode: " DRM_MODE_FMT "\n" , __func__,DRM_MODE_ARG (mode)); + +if (mode->type &DRM_MODE_TYPE_PREFERRED ) { +drm_display_mode_to_videomode (mode, &dpu->ctx.vm); + +if ((mode->hdisplay == mode->htotal) || + (mode->vdisplay == mode->vtotal)) + dpu->ctx.if_type =SPRD_DPU_IF_EDPI ; +else + dpu->ctx.if_type =SPRD_DPU_IF_DPI ; + } + +return MODE_OK ; +} + +static void sprd_crtc_atomic_enable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +sprd_dpu_init (dpu); + +enable_irq (dpu->ctx.irq); +} + +static void sprd_crtc_atomic_disable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +disable_irq (dpu->ctx.irq); + +sprd_dpu_fini (dpu); + +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_atomic_check (struct drm_crtc *crtc, +struct drm_crtc_state *state) +{ +DRM_DEBUG ("%s()\n" , __func__); + +return 0 ; +} + +static void sprd_crtc_atomic_begin (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +memset (dpu->layers,0 ,sizeof (*dpu->layers) * dpu->pending_planes); + + dpu->pending_planes =0 ; +} + +static void sprd_crtc_atomic_flush (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) + +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +if (dpu->pending_planes) + dpu->core->flip (&dpu->ctx, dpu->layers, dpu->pending_planes); + +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_enable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->enable_vsync (&dpu->ctx); + +return 0 ; +} + +static void sprd_crtc_disable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->disable_vsync (&dpu->ctx); +} + +static const struct drm_crtc_helper_funcs sprd_crtc_helper_funcs = { + .mode_valid = sprd_crtc_mode_valid, + .atomic_check = sprd_crtc_atomic_check, + .atomic_begin = sprd_crtc_atomic_begin, + .atomic_flush = sprd_crtc_atomic_flush, + .atomic_enable = sprd_crtc_atomic_enable, + .atomic_disable = sprd_crtc_atomic_disable, +}; + +static const struct drm_crtc_funcs sprd_crtc_funcs = { + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = sprd_crtc_enable_vblank, + .disable_vblank = sprd_crtc_disable_vblank, +}; + +static int sprd_crtc_init (struct drm_device *drm,struct drm_crtc *crtc, +struct drm_plane *primary) +{ +struct device_node *port; +int ret; + +/* +* set crtc port so that drm_of_find_possible_crtcs call works +*/ + port =of_parse_phandle (drm->dev->of_node,"ports" ,0 ); +if (!port) { +DRM_ERROR ("find 'ports' phandle of %s failed\n" , + drm->dev->of_node->full_name); +return -EINVAL ; + } +of_node_put (port); + crtc->port = port; + + ret =drm_crtc_init_with_planes (drm, crtc, primary,NULL , + &sprd_crtc_funcs,NULL ); +if (ret) { +DRM_ERROR ("failed to init crtc.\n" ); +return ret; + } + +drm_mode_crtc_set_gamma_size (crtc,256 ); + +drm_crtc_helper_add (crtc, &sprd_crtc_helper_funcs); + +return 0 ; +} + +static void sprd_dpu_init (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->init (ctx); + dpu->core->ifconfig (ctx); +} + +static void sprd_dpu_fini (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->fini (ctx); +} + +static irqreturn_t sprd_dpu_isr (int irq,void *data) +{ +struct sprd_dpu *dpu = data; +struct dpu_context *ctx = &dpu->ctx; +u32 int_mask =0 ; + + int_mask = dpu->core->isr (ctx); + +if (int_mask &BIT_DPU_INT_ERR ) +DRM_WARN ("Warning: dpu underflow!\n" ); + +if (int_mask &BIT_DPU_INT_VSYNC ) +drm_crtc_handle_vblank (&dpu->crtc); + +return IRQ_HANDLED ; +} + +static int sprd_dpu_bind (struct device *dev,struct device *master,void *data) +{ +struct drm_device *drm = data; +struct sprd_dpu *dpu =dev_get_drvdata (dev); +struct drm_plane *plane; +int ret; + + plane =sprd_plane_init (drm, dpu); +if (IS_ERR_OR_NULL (plane)) { + ret =PTR_ERR (plane); +return ret; + } + + ret =sprd_crtc_init (drm, &dpu->crtc, plane); +if (ret) +return ret; + +return 0 ; +} + +static void sprd_dpu_unbind (struct device *dev,struct device *master, +void *data) +{ +struct sprd_dpu *dpu =dev_get_drvdata (dev); + +drm_crtc_cleanup (&dpu->crtc); +} + +static const struct component_ops dpu_component_ops = { + .bind = sprd_dpu_bind, + .unbind = sprd_dpu_unbind, +}; + +static int sprd_dpu_context_init (struct sprd_dpu *dpu, +struct device *dev) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dpu_context *ctx = &dpu->ctx; +struct resource *res; +int ret; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + ctx->base =devm_ioremap (dev, res->start,resource_size (res)); +if (!ctx->base) { +DRM_ERROR ("failed to map dpu registers\n" ); +return -EFAULT ; + } + + ctx->irq =platform_get_irq (pdev,0 ); +if (ctx->irq <0 ) { +DRM_ERROR ("failed to get dpu irq\n" ); +return ctx->irq; + } + +irq_set_status_flags (ctx->irq,IRQ_NOAUTOEN ); + ret =devm_request_irq (dev, ctx->irq, sprd_dpu_isr, +0 ,"DPU" , dpu); +if (ret) { +DRM_ERROR ("failed to register dpu irq handler\n" ); +return ret; + } + +init_waitqueue_head (&ctx->wait_queue); + +return 0 ; +} + +static const struct sprd_dpu_ops sharkl3_dpu = { + .core = &dpu_r2p0_core_ops, +}; + +static const struct of_device_id dpu_match_table[] = { + { .compatible ="sprd,sharkl3-dpu" , + .data = &sharkl3_dpu }, + {/* sentinel */ }, +}; + +static int sprd_dpu_probe (struct platform_device *pdev) +{ +const struct sprd_dpu_ops *pdata; +struct sprd_dpu *dpu; +int ret; + + dpu =devm_kzalloc (&pdev->dev,sizeof (*dpu),GFP_KERNEL ); +if (!dpu) +return -ENOMEM ; + + pdata =of_device_get_match_data (&pdev->dev); +if (pdata) { + dpu->core = pdata->core; + }else { +DRM_ERROR ("No matching driver data found\n" ); +return -EINVAL ; + } + + ret =sprd_dpu_context_init (dpu, &pdev->dev); +if (ret) +return ret; + +platform_set_drvdata (pdev, dpu); + +return component_add (&pdev->dev, &dpu_component_ops); +} + +static int sprd_dpu_remove (struct platform_device *pdev) +{ +component_del (&pdev->dev, &dpu_component_ops); +return 0 ; +} + +struct platform_driver sprd_dpu_driver = { + .probe = sprd_dpu_probe, + .remove = sprd_dpu_remove, + .driver = { + .name ="sprd-dpu-drv" , + .of_match_table = dpu_match_table, + }, +}; + +MODULE_AUTHOR ("Leon He <[email protected]>" ); +MODULE_AUTHOR ("Kevin Tang <[email protected]>" ); +MODULE_DESCRIPTION ("Unisoc Display Controller Driver" ); +MODULE_LICENSE ("GPL v2" );drivers/gpu/drm/sprd/sprd_dpu.h new file +187
-0@@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#ifndef __SPRD_DPU_H__ +#define __SPRD_DPU_H__ + +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <video/videomode.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_print.h> +#include <drm/drm_vblank.h> +#include <uapi/drm/drm_mode.h> + +#define BIT_DPU_INT_DONE_ BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_EDPI_TE BIT(3) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_WB_DONE BIT(6) +#define BIT_DPU_INT_WB_ERR BIT(7) + +#define BIT_DPU_LAY_LAYER_ALPHA (0x01 << 2) +#define BIT_DPU_LAY_COMBO_ALPHA (0x02 << 2) +#define BIT_DPU_LAY_FORMAT_YUV422_2PLANE (0x00 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_2PLANE (0x01 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_3PLANE (0x02 << 4) +#define BIT_DPU_LAY_FORMAT_ARGB8888 (0x03 << 4) +#define BIT_DPU_LAY_FORMAT_RGB565 (0x04 << 4) +#define BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 (0x00 << 8) +#define BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 (0x01 << 8) +#define BIT_DPU_LAY_NO_SWITCH (0x00 << 10) +#define BIT_DPU_LAY_RB_OR_UV_SWITCH (0x01 << 10) +#define BIT_DPU_LAY_MODE_BLEND_NORMAL (0x00 << 16) +#define BIT_DPU_LAY_MODE_BLEND_PREMULT (0x01 << 16) + +enum { +SPRD_DPU_IF_DBI =0 , +SPRD_DPU_IF_DPI , +SPRD_DPU_IF_EDPI , +SPRD_DPU_IF_LIMIT +}; + +enum { +DPU_LAYER_ROTATION_0 , +DPU_LAYER_ROTATION_90 , +DPU_LAYER_ROTATION_180 , +DPU_LAYER_ROTATION_270 , +DPU_LAYER_ROTATION_0_M , +DPU_LAYER_ROTATION_90_M , +DPU_LAYER_ROTATION_180_M , +DPU_LAYER_ROTATION_270_M , +}; + +struct dpu_layer { +u8 index; +u8 planes; +u32 addr[4 ]; +u32 pitch[4 ]; +s16 src_x; +s16 src_y; +s16 src_w; +s16 src_h; +s16 dst_x; +s16 dst_y; +u16 dst_w; +u16 dst_h; +u32 format; +u32 alpha; +u32 blending; +u32 rotation; +}; + +/** +* Sprd DPU capability structure +* +* @max_layers: maximum number of layers available +* @fmts_ptr: A pointer to array of supported pixel formats +* @fmts_cnt: the number of format on @fmts_ptr +*/ +struct dpu_capability { +u32 max_layers; +const u32 *fmts_ptr; +u32 fmts_cnt; +}; + +/** +* Sprd DPU core callback ops +* +* This structure decribes the display controller common +* callback ops +* +* @init: initial DPU core +* @fini: cleanup DPU core +* @run: enable DPU output +* @stop: disable DPU output +* @enable_vsync: enable vblank interrupt +* @disable_vsync: disable vblank interrupt +* @isr: function pointer to the isr +* @ifconfig: initial DPI interface +* @flip: commit CRTC planes to DPU +* @capability: callback for DPU capabilities +*/ +struct dpu_context ; +struct dpu_core_ops { +void (*init)(struct dpu_context *ctx); +void (*fini)(struct dpu_context *ctx); +void (*run)(struct dpu_context *ctx); +void (*stop)(struct dpu_context *ctx); +void (*enable_vsync)(struct dpu_context *ctx); +void (*disable_vsync)(struct dpu_context *ctx); +u32 (*isr)(struct dpu_context *ctx); +void (*ifconfig)(struct dpu_context *ctx); +void (*flip)(struct dpu_context *ctx, +struct dpu_layer layers[],u8 count); +void (*capability)(struct dpu_context *ctx, +struct dpu_capability *cap); +}; + +/** +* Sprd DPU context structure +* +* @base: DPU controller base address +* @irq: IRQ number to install the handler for +* @if_type: The type of DPI interface, default is DPI mode. +* @vm: videomode structure to use for DPU and DPI initialization +* @stopped: indicates whether DPU are stopped +* @wait_queue: wait queue, used to wait for DPU shadow register update done and +* DPU stop register done interrupt signal. +* @evt_update: wait queue condition for DPU shadow register +* @evt_stop: wait queue condition for DPU stop register +*/ +struct dpu_context { +void __iomem *base; +int irq; +u8 if_type; +struct videomode vm; +bool stopped; +wait_queue_head_t wait_queue; +bool evt_update; +bool evt_stop; +}; + +/** +* Sprd DPU device structure +* +* @crtc: DRM crtc +* @ctx: A pointer to the DPU's implementation specific context +* @core: pointer to callbacks for DPU core functionality +* @layers: active DPU layers ready to commit +* @pending_planes: the number of layers on @layers +*/ +struct sprd_dpu { +struct drm_crtc crtc; +struct dpu_context ctx; +const struct dpu_core_ops *core; +struct dpu_layer *layers; +u8 pending_planes; +}; + +/** +* Sprd DPU H/W callback ops match table structure +* The structure used for matching a specific device callback ops +* +* @core: pointer to callbacks for DPU core functionality +*/ +struct sprd_dpu_ops { +const struct dpu_core_ops *core; +}; + +static inline struct sprd_dpu *crtc_to_dpu (struct drm_crtc *crtc) +{ + return crtc ? container_of(crtc, struct sprd_dpu, crtc) : NULL; +} + +extern const struct dpu_core_ops dpu_r2p0_core_ops; + +#endif drivers/gpu/drm/sprd/sprd_drm.c +1
-0@@ -200,6 +200,7 @@ static struct platform_driver sprd_drm_driver = {static struct platform_driver *sprd_drm_drivers[] = { &sprd_drm_driver, + &sprd_dpu_driver, };static int __init sprd_drm_init (void )drivers/gpu/drm/sprd/sprd_drm.h +2
-0@@ -13,4 +13,6 @@ struct sprd_drm { struct drm_device *drm; }; +extern struct platform_driver sprd_dpu_driver; +#endif /* _SPRD_DRM_H_ */ Signature · 6 lines
2.7.4 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH RFC v6 4/6] drm/sprd: add Unisoc's drm display controller driver
Quoted 47 lines · Sam Ravnborg <[email protected]> 于2020年7月29日周三 上午5:14写道:
Hi Kevin.
Some feedback in the following.
I lost track of thing for the atomic modesettting stuff and I hope other will review that.Sam
Quoted 32 lines · Kevin Tang
From: Kevin Tang <[email protected]>
Adds DPU(Display Processor Unit) support for the Unisoc's display subsystem. It's support multi planes, scaler, rotation, PQ(Picture Quality) and more.
RFC v6:
- Access registers via readl/writel
- Checking for unsupported KMS properties (format, rotation,blend_mode, etc) onplane_checkops
- Remove always true checks for dpu core opsCc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>--- drivers/gpu/drm/sprd/Makefile | 5 +- drivers/gpu/drm/sprd/dpu/Makefile | 3 + drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 503 ++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.c | 646 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.h | 187 +++++++++++ drivers/gpu/drm/sprd/sprd_drm.c | 1 + drivers/gpu/drm/sprd/sprd_drm.h | 2 + 7 files changed, 1346 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.hdrivers/gpu/drm/sprd/Makefile +0
-0drivers/gpu/drm/sprd/Makefile line 3
Quoted 2 lines
drivers/gpu/drm/sprd/Makefile +0
-0@@ -2,4 +2,7 @@ subdir-ccflags-y += -I$(srctree)/$(src)Not needed - drop.
Quoted 1 line
Quoted 8 lines
drivers/gpu/drm/sprd/Makefile line 8
Quoted 5 lines
drivers/gpu/drm/sprd/Makefile +4
-1-obj-y := sprd_drm.o +obj-y := sprd_drm.o \ + sprd_dpu.o + +obj-y += dpu/Until there are several DPU's there is no need for a separate directory. Make it simpler by keeping it all in drm/sprd/*
Ok I will move DPU IP code to drm/sprd
Quoted 49 lines
Quoted 26 lines
drivers/gpu/drm/sprd/dpu/Makefile new file +3
-0@@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += dpu_r2p0.odrivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0@@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/workqueue.h> +drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 20
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+#include "sprd_dpu.h" + +/* DPU registers size, 4 Bytes(32 Bits) */ +#define DPU_REG_SIZE 0x04 + +/* Layer registers offset */ +#define DPU_LAY_REG_OFFSET 0x0C + +#define DPU_LAY_REG (reg, index) \ + (reg + index * DPU_LAY_REG_OFFSET * DPU_REG_SIZE)Use a static inline to get better typecheck.
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 30
Quoted 9 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +9
-0+#define DPU_REG_RD (reg) readl_relaxed(reg) + +#define DPU_REG_WR (reg, mask) writel_relaxed(mask, reg) + +#define DPU_REG_SET (reg, mask) \ + writel_relaxed(readl_relaxed(reg) | mask, reg) + +#define DPU_REG_CLR (reg, mask) \ + writel_relaxed(readl_relaxed(reg) & ~mask, reg)I am no fan of macros used like this.
Quoted 2 lines
Maybe use static inlines and add struct
dpu_context* as first argument. Then adding base can be hidden away.
Maybe a good idea, i will try it, like this:
static inline void DPU_REG_CLR(dpu_context *ctx, u32 reg, u32 mask) {
writel_relaxed(readl_relaxed(ctx->base + reg) & ~mask, ctx->base + reg);
}Quoted 95 lines
I had a hard time convincing myself that
_relaxedwas the right variants. If I get it correct we may see writes re-ordered with the_relaxedvariants wich would be no good when dealign with interrupts. But I may miss somethign here.Quoted 75 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +75
-0+ +/* Global control registers */ +#define REG_DPU_CTRL 0x04 +#define REG_DPU_CFG0 0x08 +#define REG_DPU_CFG1 0x0C +#define REG_DPU_CFG2 0x10 +#define REG_PANEL_SIZE 0x20 +#define REG_BLEND_SIZE 0x24 +#define REG_BG_COLOR 0x2C + +/* Layer0 control registers */ +#define REG_LAY_BASE_ADDR0 0x30 +#define REG_LAY_BASE_ADDR1 0x34 +#define REG_LAY_BASE_ADDR2 0x38 +#define REG_LAY_CTRL 0x40 +#define REG_LAY_SIZE 0x44 +#define REG_LAY_PITCH 0x48 +#define REG_LAY_POS 0x4C +#define REG_LAY_ALPHA 0x50 +#define REG_LAY_PALLETE 0x58 +#define REG_LAY_CROP_START 0x5C + +/* Interrupt control registers */ +#define REG_DPU_INT_EN 0x1E0 +#define REG_DPU_INT_CLR 0x1E4 +#define REG_DPU_INT_STS 0x1E8 + +/* DPI control registers */ +#define REG_DPI_CTRL 0x1F0 +#define REG_DPI_H_TIMING 0x1F4 +#define REG_DPI_V_TIMING 0x1F8 + +/* MMU control registers */ +#define REG_MMU_EN 0x800 +#define REG_MMU_VPN_RANGE 0x80C +#define REG_MMU_VAOR_ADDR_RD 0x818 +#define REG_MMU_VAOR_ADDR_WR 0x81C +#define REG_MMU_INV_ADDR_RD 0x820 +#define REG_MMU_INV_ADDR_WR 0x824 +#define REG_MMU_PPN1 0x83C +#define REG_MMU_RANGE1 0x840 +#define REG_MMU_PPN2 0x844 +#define REG_MMU_RANGE2 0x848 + +/* Global control bits */ +#define BIT_DPU_RUN BIT(0) +#define BIT_DPU_STOP BIT(1) +#define BIT_DPU_REG_UPDATE BIT(2) +#define BIT_DPU_IF_EDPI BIT(0) +#define BIT_DPU_COEF_NARROW_RANGE BIT(4) +#define BIT_DPU_Y2R_COEF_ITU709_STANDARD BIT(5) + +/* Layer control bits */ +#define BIT_DPU_LAY_EN BIT(0) + +/* Interrupt control & status bits */ +#define BIT_DPU_INT_DONE BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_FBC_PLD_ERR BIT(8) +#define BIT_DPU_INT_FBC_HDR_ERR BIT(9) +#define BIT_DPU_INT_MMU_VAOR_RD BIT(16) +#define BIT_DPU_INT_MMU_VAOR_WR BIT(17) +#define BIT_DPU_INT_MMU_INV_RD BIT(18) +#define BIT_DPU_INT_MMU_INV_WR BIT(19) + +/* DPI control bits */ +#define BIT_DPU_EDPI_TE_EN BIT(8) +#define BIT_DPU_EDPI_FROM_EXTERNAL_PAD BIT(10) +#define BIT_DPU_DPI_HALT_EN BIT(16) + + +static u32 check_mmu_isr (struct dpu_context *ctx,u32 reg_val)drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 115
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+{ +u32 mmu_mask =BIT_DPU_INT_MMU_VAOR_RD | +BIT_DPU_INT_MMU_VAOR_WR | +BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +u32 val = reg_val & mmu_mask; +int i; + +if (val) { +DRM_ERROR ("--- iommu interrupt err: 0x%04x ---\n" , val);General comment, applies for the whole patch.
Quoted 5 lines
Use
drm_err(drm, ...),drm_info(drm, ...)etc.Use upclassing to get
sprd_dpu- and then you have adrm_device* (Afterdrm_deviceis embedded insprd_dpuas suggested in the other mail)
Ok, i will replace DRM_XXX with drm_xxx.
Quoted 1,271 lines
Quoted 159 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +158
-0+ +if (val &BIT_DPU_INT_MMU_INV_RD ) +DRM_ERROR ("iommu invalid read error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_INV_ADDR_RD )); +if (val &BIT_DPU_INT_MMU_INV_WR ) +DRM_ERROR ("iommu invalid write error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_INV_ADDR_WR )); +if (val &BIT_DPU_INT_MMU_VAOR_RD ) +DRM_ERROR ("iommu va out of range read error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_VAOR_ADDR_RD )); +if (val &BIT_DPU_INT_MMU_VAOR_WR ) +DRM_ERROR ("iommu va out of range write error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_VAOR_ADDR_WR )); + +for (i =0 ; i <8 ; i++) { + reg_val =DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i)); +if (reg_val &0x1 ) +DRM_INFO ("layer%d: 0x%08x 0x%08x 0x%08x ctrl: 0x%08x\n" , i, +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR0 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR1 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR2 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i))); + } + } + +return val; +} + +static void dpu_clean_all (struct dpu_context *ctx) +{ +int i; + +for (i =0 ; i <8 ; i++) +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i),0x00 ); +} + +static u32 dpu_isr (struct dpu_context *ctx) +{ +u32 reg_val, int_mask =0 ; + + reg_val =DPU_REG_RD (ctx->base +REG_DPU_INT_STS ); + +/* disable err interrupt */ +if (reg_val &BIT_DPU_INT_ERR ) + int_mask |=BIT_DPU_INT_ERR ; + +/* dpu update done isr */ +if (reg_val &BIT_DPU_INT_UPDATE_DONE ) { + ctx->evt_update = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu stop done isr */ +if (reg_val &BIT_DPU_INT_DONE ) { + ctx->evt_stop = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu ifbc payload error isr */ +if (reg_val &BIT_DPU_INT_FBC_PLD_ERR ) { + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +DRM_ERROR ("dpu ifbc payload error\n" ); + } + +/* dpu ifbc header error isr */ +if (reg_val &BIT_DPU_INT_FBC_HDR_ERR ) { + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +DRM_ERROR ("dpu ifbc header error\n" ); + } + + int_mask |=check_mmu_isr (ctx, reg_val); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR , reg_val); +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN , int_mask); + +return reg_val; +} + +static int dpu_wait_stop_done (struct dpu_context *ctx) +{ +int rc; + +if (ctx->stopped) +return 0 ; + + rc =wait_event_interruptible_timeout (ctx->wait_queue, ctx->evt_stop, +msecs_to_jiffies (500 )); + ctx->evt_stop = false; + + ctx->stopped = true; + +if (!rc) { +DRM_ERROR ("dpu wait for stop done time out!\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +static int dpu_wait_update_done (struct dpu_context *ctx) +{ +int rc; + + ctx->evt_update = false; + + rc =wait_event_interruptible_timeout (ctx->wait_queue, ctx->evt_update, +msecs_to_jiffies (500 )); + +if (!rc) { +DRM_ERROR ("dpu wait for reg update done time out!\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +static void dpu_stop (struct dpu_context *ctx) +{ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_STOP ); + +dpu_wait_stop_done (ctx); +} + +static void dpu_run (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; +} + +static void dpu_init (struct dpu_context *ctx) +{ +u32 reg_val, size; + +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + + size = (ctx->vm.vactive <<16 ) | ctx->vm.hactive; + +DPU_REG_WR (ctx->base +REG_PANEL_SIZE , size); +DPU_REG_WR (ctx->base +REG_BLEND_SIZE , size); + + reg_val =BIT_DPU_COEF_NARROW_RANGE |BIT_DPU_Y2R_COEF_ITU709_STANDARD ; +DPU_REG_WR (ctx->base +REG_DPU_CFG0 , reg_val); +DPU_REG_WR (ctx->base +REG_DPU_CFG1 ,0x004466da ); +DPU_REG_WR (ctx->base +REG_DPU_CFG2 ,0x00 ); + +if (ctx->stopped) +dpu_clean_all (ctx); + +DPU_REG_WR (ctx->base +REG_MMU_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_PPN1 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE1 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_PPN2 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE2 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_VPN_RANGE ,0x1ffff ); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xffff );drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 283
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+} + +static void dpu_fini (struct dpu_context *ctx) +{ +DPU_REG_WR (ctx->base +REG_DPU_INT_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xff ); +} + +static void dpu_layer (struct dpu_context *ctx, +struct dpu_layer *hwlayer)No linebreak needed here.
Quoted 189 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +189
-0+{ +const struct drm_format_info *info; +u32 size, offset, ctrl, pitch; +int i; + + offset = (hwlayer->dst_x &0xffff ) | ((hwlayer->dst_y) <<16 ); + +if (hwlayer->src_w && hwlayer->src_h) + size = (hwlayer->src_w &0xffff ) | ((hwlayer->src_h) <<16 ); +else + size = (hwlayer->dst_w &0xffff ) | ((hwlayer->dst_h) <<16 ); + +for (i =0 ; i < hwlayer->planes; i++) +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR0 , + hwlayer->index), hwlayer->addr[i]); + +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_POS , + hwlayer->index), offset); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_SIZE , + hwlayer->index), size); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CROP_START , + hwlayer->index), hwlayer->src_y <<16 | hwlayer->src_x); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_ALPHA , + hwlayer->index), hwlayer->alpha); + + info =drm_format_info (hwlayer->format); +if (hwlayer->planes ==3 ) { +/* UV pitch is 1/2 of Y pitch*/ + pitch = (hwlayer->pitch[0 ] / info->cpp[0 ]) | + (hwlayer->pitch[0 ] / info->cpp[0 ] <<15 ); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + }else { + pitch = hwlayer->pitch[0 ] / info->cpp[0 ]; +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + } + + ctrl = hwlayer->format | + hwlayer->blending | + (hwlayer->rotation &0x7 ) <<20 ; + +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index), ctrl); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index),BIT_DPU_LAY_EN ); + +DRM_DEBUG ("dst_x = %d, dst_y = %d, dst_w = %d, dst_h = %d\n" , + hwlayer->dst_x, hwlayer->dst_y, + hwlayer->dst_w, hwlayer->dst_h); +DRM_DEBUG ("start_x = %d, start_y = %d, start_w = %d, start_h = %d\n" , + hwlayer->src_x, hwlayer->src_y, + hwlayer->src_w, hwlayer->src_h); +} + +static void dpu_flip (struct dpu_context *ctx, +struct dpu_layer layers[],u8 count) +{ +int i; +u32 reg_val; + +/* +* Make sure the dpu is in stop status. DPU_R2P0 has no shadow +* registers in EDPI mode. So the config registers can only be +* updated in the rising edge of DPU_RUN bit. +*/ +if (ctx->if_type ==SPRD_DPU_IF_EDPI ) +dpu_wait_stop_done (ctx); + +/* reset the bgcolor to black */ +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + +/* disable all the layers */ +dpu_clean_all (ctx); + +/* start configure dpu layers */ +for (i =0 ; i < count; i++) +dpu_layer (ctx, &layers[i]); + +/* update trigger and wait */ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +if (!ctx->stopped) { +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_REG_UPDATE ); +dpu_wait_update_done (ctx); + } + +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_ERR ); + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; + } + +/* +* If the following interrupt was disabled in isr, +* re-enable it. +*/ + reg_val =BIT_DPU_INT_FBC_PLD_ERR | +BIT_DPU_INT_FBC_HDR_ERR | +BIT_DPU_INT_MMU_VAOR_RD | +BIT_DPU_INT_MMU_VAOR_WR | +BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +DPU_REG_SET (ctx->base +REG_DPU_INT_EN , reg_val); + +} + +static void dpu_dpi_init (struct dpu_context *ctx) +{ +u32 int_mask =0 ; +u32 reg_val; + +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +/* use dpi as interface */ +DPU_REG_CLR (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* disable Halt function for SPRD DSI */ +DPU_REG_CLR (ctx->base +REG_DPI_CTRL ,BIT_DPU_DPI_HALT_EN ); + +/* select te from external pad */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_FROM_EXTERNAL_PAD ); + +/* set dpi timing */ + reg_val = ctx->vm.hsync_len <<0 | + ctx->vm.hback_porch <<8 | + ctx->vm.hfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_H_TIMING , reg_val); + + reg_val = ctx->vm.vsync_len <<0 | + ctx->vm.vback_porch <<8 | + ctx->vm.vfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_V_TIMING , reg_val); + +if (ctx->vm.vsync_len + ctx->vm.vback_porch <32 ) +DRM_WARN ("Warning: (vsync + vbp) < 32, " +"underflow risk!\n" ); + +/* enable dpu update done INT */ + int_mask |=BIT_DPU_INT_UPDATE_DONE ; +/* enable dpu DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable dpu dpi vsync */ + int_mask |=BIT_DPU_INT_VSYNC ; +/* enable dpu TE INT */ + int_mask |=BIT_DPU_INT_TE ; +/* enable underflow err INT */ + int_mask |=BIT_DPU_INT_ERR ; + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +/* use edpi as interface */ +DPU_REG_SET (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* use external te */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_FROM_EXTERNAL_PAD ); + +/* enable te */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_TE_EN ); + +/* enable stop DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable TE INT */ + int_mask |=BIT_DPU_INT_TE ; + } + +/* enable ifbc payload error INT */ + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +/* enable ifbc header error INT */ + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +/* enable iommu va out of range read error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_RD ; +/* enable iommu va out of range write error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_WR ; +/* enable iommu invalid read error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_RD ; +/* enable iommu invalid write error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_WR ; + +DPU_REG_WR (ctx->base +REG_DPU_INT_EN , int_mask); +} + +static void enable_vsync (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} + +static void disable_vsync (struct dpu_context *ctx) +{ +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} +drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 482
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+static const u32 primary_fmts[] = { +DRM_FORMAT_XRGB8888 ,DRM_FORMAT_XBGR8888 , +DRM_FORMAT_ARGB8888 ,DRM_FORMAT_ABGR8888 , +DRM_FORMAT_RGBA8888 ,DRM_FORMAT_BGRA8888 , +DRM_FORMAT_RGBX8888 ,DRM_FORMAT_RGB565 , +DRM_FORMAT_BGR565 ,DRM_FORMAT_NV12 , +DRM_FORMAT_NV21 ,DRM_FORMAT_NV16 , +DRM_FORMAT_NV61 ,DRM_FORMAT_YUV420 , +DRM_FORMAT_YVU420 , +};One format per line improves readability a lot.
Maybe sort alphbetically too.drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 485
Quoted 3 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +3
-0+ +static void dpu_capability (struct dpu_context *ctx, +struct dpu_capability *cap)Drop linebreak
Quoted 893 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +18
-0+{ + cap->max_layers =6 ; + cap->fmts_ptr = primary_fmts; + cap->fmts_cnt =ARRAY_SIZE (primary_fmts); +} + +const struct dpu_core_ops dpu_r2p0_core_ops = { + .init = dpu_init, + .fini = dpu_fini, + .run = dpu_run, + .stop = dpu_stop, + .isr = dpu_isr, + .ifconfig = dpu_dpi_init, + .capability = dpu_capability, + .flip = dpu_flip, + .enable_vsync = enable_vsync, + .disable_vsync = disable_vsync, +};drivers/gpu/drm/sprd/sprd_dpu.c new file +646
-0@@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/component.h> +#include <linux/dma-buf.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_plane_helper.h> + +#include "sprd_drm.h" +#include "sprd_dpu.h" + +struct sprd_plane { +struct drm_plane plane; +u32 index; +u32 addr[4 ]; +u32 pitch[4 ]; +u32 format; +u32 rotation; +u32 blend_mode; +}; + +static void sprd_dpu_init (struct sprd_dpu *dpu); +static void sprd_dpu_fini (struct sprd_dpu *dpu); + +static inline struct sprd_plane *to_sprd_plane (struct drm_plane *plane) +{ + return container_of(plane, struct sprd_plane, plane); +} + +static int sprd_plane_format_convert (u32 fourcc,u32 *format) +{ +switch (fourcc) { +case DRM_FORMAT_BGRA8888 : +/* BGRA8888 -> ARGB8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_RGBX8888 : +case DRM_FORMAT_RGBA8888 : +/* RGBA8888 -> ABGR8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* FALLTHRU */ +case DRM_FORMAT_ABGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_ARGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_XBGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_XRGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_BGR565 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_RGB565 : + *format |=BIT_DPU_LAY_FORMAT_RGB565 ; +break ; +case DRM_FORMAT_NV12 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_NV21 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV16 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV61 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YUV420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YVU420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_rotation_convert (u32 angle,u32 *rotation) +{ +switch (angle) { +case DRM_MODE_ROTATE_0 : + *rotation =DPU_LAYER_ROTATION_0 ; +break ; +case DRM_MODE_ROTATE_90 : + *rotation =DPU_LAYER_ROTATION_90 ; +break ; +case DRM_MODE_ROTATE_180 : + *rotation =DPU_LAYER_ROTATION_180 ; +break ; +case DRM_MODE_ROTATE_270 : + *rotation =DPU_LAYER_ROTATION_270 ; +break ; +case DRM_MODE_REFLECT_Y : + *rotation =DPU_LAYER_ROTATION_180_M ; +break ; +case (DRM_MODE_REFLECT_Y |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_90_M ; +break ; +case DRM_MODE_REFLECT_X : + *rotation =DPU_LAYER_ROTATION_0_M ; +break ; +case (DRM_MODE_REFLECT_X |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_270_M ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_atomic_check (struct drm_plane *plane, +struct drm_plane_state *state) +{ +struct sprd_plane *p =to_sprd_plane (plane); +struct drm_framebuffer *fb = state->fb; +struct drm_gem_cma_object *cma_obj; +int i, ret; +u32 addr; + +if (!state->fb || !state->crtc) +return 0 ; + + ret =sprd_plane_format_convert (fb->format->format, + &p->format); +if (ret <0 ) { +DRM_ERROR ("Invalid plane format\n" ); +return ret; + } + + ret =sprd_plane_rotation_convert (state->rotation, + &p->rotation); +if (ret <0 ) { +DRM_ERROR ("Invalid plane rotation\n" ); +return ret; + } + +switch (state->pixel_blend_mode) { +case DRM_MODE_BLEND_COVERAGE : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Normal mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_NORMAL ; +break ; +case DRM_MODE_BLEND_PREMULTI : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Pre-mult mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_PREMULT ; +break ; +case DRM_MODE_BLEND_PIXEL_NONE : +default : +/* don't do blending, maybe RGBX */ +/* alpha mode select - layer alpha */ + p->blend_mode |=BIT_DPU_LAY_LAYER_ALPHA ; +break ; + } + +for (i =0 ; i < fb->format->num_planes; i++) { + cma_obj =drm_fb_cma_get_gem_obj (fb, i); + addr = cma_obj->paddr + fb->offsets[i]; +if (addr %16 ) { +DRM_ERROR ("layer addr[%d] is not 16 bytes align, it's 0x%08x\n" , + i, addr); +return -EFAULT ; + } + + p->addr[i] = addr; + p->pitch[i] = fb->pitches[i]; + } + +return 0 ; +} + +static void sprd_plane_atomic_update (struct drm_plane *plane, +struct drm_plane_state *old_state) +{ +struct drm_plane_state *state = plane->state; +struct drm_framebuffer *fb = plane->state->fb; +struct sprd_plane *p =to_sprd_plane (plane); +struct sprd_dpu *dpu =crtc_to_dpu (plane->state->crtc); +struct dpu_layer *layer = &dpu->layers[p->index]; +int i; + +if (!state->crtc || !state->fb) +return ; + + layer->index = p->index; + layer->src_x = state->src_x >>16 ; + layer->src_y = state->src_y >>16 ; + layer->src_w = state->src_w >>16 ; + layer->src_h = state->src_h >>16 ; + layer->dst_x = state->crtc_x; + layer->dst_y = state->crtc_y; + layer->dst_w = state->crtc_w; + layer->dst_h = state->crtc_h; + layer->alpha = state->alpha; + layer->format = p->format; + layer->blending = p->blend_mode; + layer->rotation = p->rotation; + layer->planes = fb->format->num_planes; + +for (i =0 ; i < layer->planes; i++) { + layer->addr[i] = p->addr[i]; + layer->pitch[i] = p->pitch[i]; + } + + dpu->pending_planes++; +} + +static void sprd_plane_create_properties (struct sprd_plane *p,int index) +{ +unsigned int supported_modes =BIT (DRM_MODE_BLEND_PIXEL_NONE ) | +BIT (DRM_MODE_BLEND_PREMULTI ) | +BIT (DRM_MODE_BLEND_COVERAGE ); + +/* create rotation property */ +drm_plane_create_rotation_property (&p->plane, +DRM_MODE_ROTATE_0 , +DRM_MODE_ROTATE_MASK | +DRM_MODE_REFLECT_MASK ); + +/* create alpha property */ +drm_plane_create_alpha_property (&p->plane); + +/* create blend mode property */ +drm_plane_create_blend_mode_property (&p->plane, supported_modes); + +/* create zpos property */ +drm_plane_create_zpos_immutable_property (&p->plane, index); +} + +static const struct drm_plane_helper_funcs sprd_plane_helper_funcs = { + .atomic_check = sprd_plane_atomic_check, + .atomic_update = sprd_plane_atomic_update, +}; + +static const struct drm_plane_funcs sprd_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static struct drm_plane *sprd_plane_init (struct drm_device *drm, +struct sprd_dpu *dpu) +{ +struct drm_plane *primary =NULL ; +struct sprd_plane *p =NULL ; +struct dpu_capability cap = {}; +int ret, i; + + dpu->core->capability (&dpu->ctx, &cap); + + dpu->layers =devm_kcalloc (drm->dev, cap.max_layers, +sizeof (struct dpu_layer ),GFP_KERNEL ); +if (!dpu->layers) +return ERR_PTR (-ENOMEM ); + +for (i =0 ; i < cap.max_layers; i++) { + + p =devm_kzalloc (drm->dev,sizeof (*p),GFP_KERNEL ); +if (!p) +return ERR_PTR (-ENOMEM ); + + ret =drm_universal_plane_init (drm, &p->plane,1 , + &sprd_plane_funcs, cap.fmts_ptr, + cap.fmts_cnt,NULL , +DRM_PLANE_TYPE_PRIMARY ,NULL ); +if (ret) { +DRM_ERROR ("fail to init primary plane\n" ); +return ERR_PTR (ret); + } + +drm_plane_helper_add (&p->plane, &sprd_plane_helper_funcs); + +sprd_plane_create_properties (p, i); + + p->index = i; +if (i ==0 ) + primary = &p->plane; + } + +return primary; +} + +static enum drm_mode_status sprd_crtc_mode_valid (struct drm_crtc *crtc, +const struct drm_display_mode *mode) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +DRM_DEBUG ("%s() mode: " DRM_MODE_FMT "\n" , __func__,DRM_MODE_ARG (mode)); + +if (mode->type &DRM_MODE_TYPE_PREFERRED ) { +drm_display_mode_to_videomode (mode, &dpu->ctx.vm); + +if ((mode->hdisplay == mode->htotal) || + (mode->vdisplay == mode->vtotal)) + dpu->ctx.if_type =SPRD_DPU_IF_EDPI ; +else + dpu->ctx.if_type =SPRD_DPU_IF_DPI ; + } + +return MODE_OK ; +} + +static void sprd_crtc_atomic_enable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +sprd_dpu_init (dpu); + +enable_irq (dpu->ctx.irq); +} + +static void sprd_crtc_atomic_disable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +disable_irq (dpu->ctx.irq); + +sprd_dpu_fini (dpu); + +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_atomic_check (struct drm_crtc *crtc, +struct drm_crtc_state *state) +{ +DRM_DEBUG ("%s()\n" , __func__); + +return 0 ; +} + +static void sprd_crtc_atomic_begin (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +memset (dpu->layers,0 ,sizeof (*dpu->layers) * dpu->pending_planes); + + dpu->pending_planes =0 ; +} + +static void sprd_crtc_atomic_flush (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) + +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +if (dpu->pending_planes) + dpu->core->flip (&dpu->ctx, dpu->layers, dpu->pending_planes); + +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_enable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->enable_vsync (&dpu->ctx); + +return 0 ; +} + +static void sprd_crtc_disable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->disable_vsync (&dpu->ctx); +} + +static const struct drm_crtc_helper_funcs sprd_crtc_helper_funcs = { + .mode_valid = sprd_crtc_mode_valid, + .atomic_check = sprd_crtc_atomic_check, + .atomic_begin = sprd_crtc_atomic_begin, + .atomic_flush = sprd_crtc_atomic_flush, + .atomic_enable = sprd_crtc_atomic_enable, + .atomic_disable = sprd_crtc_atomic_disable, +}; + +static const struct drm_crtc_funcs sprd_crtc_funcs = { + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = sprd_crtc_enable_vblank, + .disable_vblank = sprd_crtc_disable_vblank, +}; + +static int sprd_crtc_init (struct drm_device *drm,struct drm_crtc *crtc, +struct drm_plane *primary) +{ +struct device_node *port; +int ret; + +/* +* set crtc port so that drm_of_find_possible_crtcs call works +*/ + port =of_parse_phandle (drm->dev->of_node,"ports" ,0 ); +if (!port) { +DRM_ERROR ("find 'ports' phandle of %s failed\n" , + drm->dev->of_node->full_name); +return -EINVAL ; + } +of_node_put (port); + crtc->port = port; + + ret =drm_crtc_init_with_planes (drm, crtc, primary,NULL , + &sprd_crtc_funcs,NULL ); +if (ret) { +DRM_ERROR ("failed to init crtc.\n" ); +return ret; + } + +drm_mode_crtc_set_gamma_size (crtc,256 ); + +drm_crtc_helper_add (crtc, &sprd_crtc_helper_funcs); + +return 0 ; +} + +static void sprd_dpu_init (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->init (ctx); + dpu->core->ifconfig (ctx); +} + +static void sprd_dpu_fini (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->fini (ctx); +} + +static irqreturn_t sprd_dpu_isr (int irq,void *data) +{ +struct sprd_dpu *dpu = data; +struct dpu_context *ctx = &dpu->ctx; +u32 int_mask =0 ; + + int_mask = dpu->core->isr (ctx); + +if (int_mask &BIT_DPU_INT_ERR ) +DRM_WARN ("Warning: dpu underflow!\n" ); + +if (int_mask &BIT_DPU_INT_VSYNC ) +drm_crtc_handle_vblank (&dpu->crtc); + +return IRQ_HANDLED ; +} + +static int sprd_dpu_bind (struct device *dev,struct device *master,void *data) +{ +struct drm_device *drm = data; +struct sprd_dpu *dpu =dev_get_drvdata (dev); +struct drm_plane *plane; +int ret; + + plane =sprd_plane_init (drm, dpu); +if (IS_ERR_OR_NULL (plane)) { + ret =PTR_ERR (plane); +return ret; + } + + ret =sprd_crtc_init (drm, &dpu->crtc, plane); +if (ret) +return ret; + +return 0 ; +} + +static void sprd_dpu_unbind (struct device *dev,struct device *master, +void *data) +{ +struct sprd_dpu *dpu =dev_get_drvdata (dev); + +drm_crtc_cleanup (&dpu->crtc); +} + +static const struct component_ops dpu_component_ops = { + .bind = sprd_dpu_bind, + .unbind = sprd_dpu_unbind, +}; + +static int sprd_dpu_context_init (struct sprd_dpu *dpu, +struct device *dev) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dpu_context *ctx = &dpu->ctx; +struct resource *res; +int ret; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + ctx->base =devm_ioremap (dev, res->start,resource_size (res)); +if (!ctx->base) { +DRM_ERROR ("failed to map dpu registers\n" ); +return -EFAULT ; + } + + ctx->irq =platform_get_irq (pdev,0 ); +if (ctx->irq <0 ) { +DRM_ERROR ("failed to get dpu irq\n" ); +return ctx->irq; + } + +irq_set_status_flags (ctx->irq,IRQ_NOAUTOEN ); + ret =devm_request_irq (dev, ctx->irq, sprd_dpu_isr, +0 ,"DPU" , dpu); +if (ret) { +DRM_ERROR ("failed to register dpu irq handler\n" ); +return ret; + } + +init_waitqueue_head (&ctx->wait_queue); + +return 0 ; +} + +static const struct sprd_dpu_ops sharkl3_dpu = { + .core = &dpu_r2p0_core_ops, +}; + +static const struct of_device_id dpu_match_table[] = { + { .compatible ="sprd,sharkl3-dpu" , + .data = &sharkl3_dpu }, + {/* sentinel */ }, +}; + +static int sprd_dpu_probe (struct platform_device *pdev) +{ +const struct sprd_dpu_ops *pdata; +struct sprd_dpu *dpu; +int ret; + + dpu =devm_kzalloc (&pdev->dev,sizeof (*dpu),GFP_KERNEL ); +if (!dpu) +return -ENOMEM ; + + pdata =of_device_get_match_data (&pdev->dev); +if (pdata) { + dpu->core = pdata->core; + }else { +DRM_ERROR ("No matching driver data found\n" ); +return -EINVAL ; + } + + ret =sprd_dpu_context_init (dpu, &pdev->dev); +if (ret) +return ret; + +platform_set_drvdata (pdev, dpu); + +return component_add (&pdev->dev, &dpu_component_ops); +} + +static int sprd_dpu_remove (struct platform_device *pdev) +{ +component_del (&pdev->dev, &dpu_component_ops); +return 0 ; +} + +struct platform_driver sprd_dpu_driver = { + .probe = sprd_dpu_probe, + .remove = sprd_dpu_remove, + .driver = { + .name ="sprd-dpu-drv" , + .of_match_table = dpu_match_table, + }, +}; + +MODULE_AUTHOR ("Leon He <[email protected]>" ); +MODULE_AUTHOR ("Kevin Tang <[email protected]>" ); +MODULE_DESCRIPTION ("Unisoc Display Controller Driver" ); +MODULE_LICENSE ("GPL v2" );drivers/gpu/drm/sprd/sprd_dpu.h new file +187
-0@@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#ifndef __SPRD_DPU_H__ +#define __SPRD_DPU_H__ + +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <video/videomode.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_print.h> +#include <drm/drm_vblank.h> +#include <uapi/drm/drm_mode.h> + +#define BIT_DPU_INT_DONE_ BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_EDPI_TE BIT(3) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_WB_DONE BIT(6) +#define BIT_DPU_INT_WB_ERR BIT(7) + +#define BIT_DPU_LAY_LAYER_ALPHA (0x01 << 2) +#define BIT_DPU_LAY_COMBO_ALPHA (0x02 << 2) +#define BIT_DPU_LAY_FORMAT_YUV422_2PLANE (0x00 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_2PLANE (0x01 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_3PLANE (0x02 << 4) +#define BIT_DPU_LAY_FORMAT_ARGB8888 (0x03 << 4) +#define BIT_DPU_LAY_FORMAT_RGB565 (0x04 << 4) +#define BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 (0x00 << 8) +#define BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 (0x01 << 8) +#define BIT_DPU_LAY_NO_SWITCH (0x00 << 10) +#define BIT_DPU_LAY_RB_OR_UV_SWITCH (0x01 << 10) +#define BIT_DPU_LAY_MODE_BLEND_NORMAL (0x00 << 16) +#define BIT_DPU_LAY_MODE_BLEND_PREMULT (0x01 << 16) + +enum { +SPRD_DPU_IF_DBI =0 , +SPRD_DPU_IF_DPI , +SPRD_DPU_IF_EDPI , +SPRD_DPU_IF_LIMIT +}; + +enum { +DPU_LAYER_ROTATION_0 , +DPU_LAYER_ROTATION_90 , +DPU_LAYER_ROTATION_180 , +DPU_LAYER_ROTATION_270 , +DPU_LAYER_ROTATION_0_M , +DPU_LAYER_ROTATION_90_M , +DPU_LAYER_ROTATION_180_M , +DPU_LAYER_ROTATION_270_M , +}; + +struct dpu_layer { +u8 index; +u8 planes; +u32 addr[4 ]; +u32 pitch[4 ]; +s16 src_x; +s16 src_y; +s16 src_w; +s16 src_h; +s16 dst_x; +s16 dst_y; +u16 dst_w; +u16 dst_h; +u32 format; +u32 alpha; +u32 blending; +u32 rotation; +}; + +/** +* Sprd DPU capability structure +* +* @max_layers: maximum number of layers available +* @fmts_ptr: A pointer to array of supported pixel formats +* @fmts_cnt: the number of format on @fmts_ptr +*/ +struct dpu_capability { +u32 max_layers; +const u32 *fmts_ptr; +u32 fmts_cnt; +}; + +/** +* Sprd DPU core callback ops +* +* This structure decribes the display controller common +* callback ops +* +* @init: initial DPU core +* @fini: cleanup DPU core +* @run: enable DPU output +* @stop: disable DPU output +* @enable_vsync: enable vblank interrupt +* @disable_vsync: disable vblank interrupt +* @isr: function pointer to the isr +* @ifconfig: initial DPI interface +* @flip: commit CRTC planes to DPU +* @capability: callback for DPU capabilities +*/ +struct dpu_context ; +struct dpu_core_ops { +void (*init)(struct dpu_context *ctx); +void (*fini)(struct dpu_context *ctx); +void (*run)(struct dpu_context *ctx); +void (*stop)(struct dpu_context *ctx); +void (*enable_vsync)(struct dpu_context *ctx); +void (*disable_vsync)(struct dpu_context *ctx); +u32 (*isr)(struct dpu_context *ctx); +void (*ifconfig)(struct dpu_context *ctx); +void (*flip)(struct dpu_context *ctx, +struct dpu_layer layers[],u8 count); +void (*capability)(struct dpu_context *ctx, +struct dpu_capability *cap); +}; + +/** +* Sprd DPU context structure +* +* @base: DPU controller base address +* @irq: IRQ number to install the handler for +* @if_type: The type of DPI interface, default is DPI mode. +* @vm: videomode structure to use for DPU and DPI initialization +* @stopped: indicates whether DPU are stopped +* @wait_queue: wait queue, used to wait for DPU shadow register update done and +* DPU stop register done interrupt signal. +* @evt_update: wait queue condition for DPU shadow register +* @evt_stop: wait queue condition for DPU stop register +*/ +struct dpu_context { +void __iomem *base; +int irq; +u8 if_type; +struct videomode vm; +bool stopped; +wait_queue_head_t wait_queue; +bool evt_update; +bool evt_stop; +}; + +/** +* Sprd DPU device structure +* +* @crtc: DRM crtc +* @ctx: A pointer to the DPU's implementation specific context +* @core: pointer to callbacks for DPU core functionality +* @layers: active DPU layers ready to commit +* @pending_planes: the number of layers on @layers +*/ +struct sprd_dpu { +struct drm_crtc crtc; +struct dpu_context ctx; +const struct dpu_core_ops *core; +struct dpu_layer *layers; +u8 pending_planes; +}; + +/** +* Sprd DPU H/W callback ops match table structure +* The structure used for matching a specific device callback ops +* +* @core: pointer to callbacks for DPU core functionality +*/ +struct sprd_dpu_ops { +const struct dpu_core_ops *core; +}; + +static inline struct sprd_dpu *crtc_to_dpu (struct drm_crtc *crtc) +{ + return crtc ? container_of(crtc, struct sprd_dpu, crtc) : NULL; +} + +extern const struct dpu_core_ops dpu_r2p0_core_ops; + +#endif drivers/gpu/drm/sprd/sprd_drm.c +1
-0@@ -200,6 +200,7 @@ static struct platform_driver sprd_drm_driver = {static struct platform_driver *sprd_drm_drivers[] = { &sprd_drm_driver, + &sprd_dpu_driver, };static int __init sprd_drm_init (void )drivers/gpu/drm/sprd/sprd_drm.h +2
-1@@ -13,4 +13,6 @@ struct sprd_drm { struct drm_device *drm; }; +extern struct platform_driver sprd_dpu_driver; +#endif /* _SPRD_DRM_H_ */ --2.7.4
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH RFC v6 4/6] drm/sprd: add Unisoc's drm display controller driver
In reply to Sam RavnborgHi Sam,
Here is feedback of RFC V7
Quoted 37 lines · Sam Ravnborg <[email protected]> 于2020年7月29日周三 上午5:14写道:
Hi Kevin.
Some feedback in the following.
I lost track of thing for the atomic modesettting stuff and I hope other will review that.Sam
Quoted 27 lines · Kevin Tang
From: Kevin Tang <[email protected]>
Adds DPU(Display Processor Unit) support for the Unisoc's display subsystem. It's support multi planes, scaler, rotation, PQ(Picture Quality) and more.
RFC v6:
- Access registers via readl/writel
- Checking for unsupported KMS properties (format, rotation,blend_mode, etc) onplane_checkops
- Remove always true checks for dpu core opsCc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>--- drivers/gpu/drm/sprd/Makefile | 5 +- drivers/gpu/drm/sprd/dpu/Makefile | 3 + drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 503 ++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.c | 646 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.h | 187 +++++++++++ drivers/gpu/drm/sprd/sprd_drm.c | 1 + drivers/gpu/drm/sprd/sprd_drm.h | 2 + 7 files changed, 1346 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.h
Quoted 8 lines
drivers/gpu/drm/sprd/Makefile line 3
Quoted 7 lines
drivers/gpu/drm/sprd/Makefile +0
-0@@ -2,4 +2,7 @@ subdir-ccflags-y += -I$(srctree)/$(src)Not needed - drop.
It has been fixed on RFC V7.
Quoted 10 lines
drivers/gpu/drm/sprd/Makefile line 8
Quoted 7 lines
drivers/gpu/drm/sprd/Makefile +4
-1-obj-y := sprd_drm.o +obj-y := sprd_drm.o \ + sprd_dpu.o + +obj-y += dpu/Until there are several DPU's there is no need for a separate directory. Make it simpler by keeping it all in drm/sprd/*
It has been fixed on RFC V7.
Quoted 29 lines
Quoted 29 lines
drivers/gpu/drm/sprd/dpu/Makefile new file +3
-0@@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += dpu_r2p0.odrivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +13
-0@@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/workqueue.h> + +#include "sprd_dpu.h" + +/* DPU registers size, 4 Bytes(32 Bits) */
Quoted 8 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 20
Quoted 7 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +7
-0+#define DPU_REG_SIZE 0x04 + +/* Layer registers offset */ +#define DPU_LAY_REG_OFFSET 0x0C + +#define DPU_LAY_REG (reg, index) \ + (reg + index * DPU_LAY_REG_OFFSET * DPU_REG_SIZE)Use a static inline to get better typecheck.
It has been fixed on RFC V7.
Quoted 12 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 30
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +9
-0+#define DPU_REG_RD (reg) readl_relaxed(reg) + +#define DPU_REG_WR (reg, mask) writel_relaxed(mask, reg) + +#define DPU_REG_SET (reg, mask) \ + writel_relaxed(readl_relaxed(reg) | mask, reg) + +#define DPU_REG_CLR (reg, mask) \ + writel_relaxed(readl_relaxed(reg) & ~mask, reg)I am no fan of macros used like this.
Quoted 2 lines
Maybe use static inlines and add struct
dpu_context* as first argument. Then adding base can be hidden away.
It has been fixed on RFC V7.
Quoted 6 lines
I had a hard time convincing myself that
_relaxedwas the right variants. If I get it correct we may see writes re-ordered with the_relaxedvariants wich would be no good when dealign with interrupts. But I may miss somethign here.
I need to think about it
Quoted 89 lines
Quoted 76 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +75
-0+ +/* Global control registers */ +#define REG_DPU_CTRL 0x04 +#define REG_DPU_CFG0 0x08 +#define REG_DPU_CFG1 0x0C +#define REG_DPU_CFG2 0x10 +#define REG_PANEL_SIZE 0x20 +#define REG_BLEND_SIZE 0x24 +#define REG_BG_COLOR 0x2C + +/* Layer0 control registers */ +#define REG_LAY_BASE_ADDR0 0x30 +#define REG_LAY_BASE_ADDR1 0x34 +#define REG_LAY_BASE_ADDR2 0x38 +#define REG_LAY_CTRL 0x40 +#define REG_LAY_SIZE 0x44 +#define REG_LAY_PITCH 0x48 +#define REG_LAY_POS 0x4C +#define REG_LAY_ALPHA 0x50 +#define REG_LAY_PALLETE 0x58 +#define REG_LAY_CROP_START 0x5C + +/* Interrupt control registers */ +#define REG_DPU_INT_EN 0x1E0 +#define REG_DPU_INT_CLR 0x1E4 +#define REG_DPU_INT_STS 0x1E8 + +/* DPI control registers */ +#define REG_DPI_CTRL 0x1F0 +#define REG_DPI_H_TIMING 0x1F4 +#define REG_DPI_V_TIMING 0x1F8 + +/* MMU control registers */ +#define REG_MMU_EN 0x800 +#define REG_MMU_VPN_RANGE 0x80C +#define REG_MMU_VAOR_ADDR_RD 0x818 +#define REG_MMU_VAOR_ADDR_WR 0x81C +#define REG_MMU_INV_ADDR_RD 0x820 +#define REG_MMU_INV_ADDR_WR 0x824 +#define REG_MMU_PPN1 0x83C +#define REG_MMU_RANGE1 0x840 +#define REG_MMU_PPN2 0x844 +#define REG_MMU_RANGE2 0x848 + +/* Global control bits */ +#define BIT_DPU_RUN BIT(0) +#define BIT_DPU_STOP BIT(1) +#define BIT_DPU_REG_UPDATE BIT(2) +#define BIT_DPU_IF_EDPI BIT(0) +#define BIT_DPU_COEF_NARROW_RANGE BIT(4) +#define BIT_DPU_Y2R_COEF_ITU709_STANDARD BIT(5) + +/* Layer control bits */ +#define BIT_DPU_LAY_EN BIT(0) + +/* Interrupt control & status bits */ +#define BIT_DPU_INT_DONE BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_FBC_PLD_ERR BIT(8) +#define BIT_DPU_INT_FBC_HDR_ERR BIT(9) +#define BIT_DPU_INT_MMU_VAOR_RD BIT(16) +#define BIT_DPU_INT_MMU_VAOR_WR BIT(17) +#define BIT_DPU_INT_MMU_INV_RD BIT(18) +#define BIT_DPU_INT_MMU_INV_WR BIT(19) + +/* DPI control bits */ +#define BIT_DPU_EDPI_TE_EN BIT(8) +#define BIT_DPU_EDPI_FROM_EXTERNAL_PAD BIT(10) +#define BIT_DPU_DPI_HALT_EN BIT(16) + + +static u32 check_mmu_isr (struct dpu_context *ctx,u32 reg_val)drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 115
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+{ +u32 mmu_mask =BIT_DPU_INT_MMU_VAOR_RD | +BIT_DPU_INT_MMU_VAOR_WR | +BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +u32 val = reg_val & mmu_mask; +int i; + +if (val) { +DRM_ERROR ("--- iommu interrupt err: 0x%04x ---\n" , val);General comment, applies for the whole patch.
Quoted 5 lines
Use
drm_err(drm, ...),drm_info(drm, ...)etc.Use upclassing to get
sprd_dpu- and then you have adrm_device* (Afterdrm_deviceis embedded insprd_dpuas suggested in the other mail)
We did not use drm_device in crtc driver, only in kms driver(sprd_drm.c) So is this still necessary?
Quoted 162 lines
Quoted 162 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +161
-0+ +if (val &BIT_DPU_INT_MMU_INV_RD ) +DRM_ERROR ("iommu invalid read error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_INV_ADDR_RD )); +if (val &BIT_DPU_INT_MMU_INV_WR ) +DRM_ERROR ("iommu invalid write error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_INV_ADDR_WR )); +if (val &BIT_DPU_INT_MMU_VAOR_RD ) +DRM_ERROR ("iommu va out of range read error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_VAOR_ADDR_RD )); +if (val &BIT_DPU_INT_MMU_VAOR_WR ) +DRM_ERROR ("iommu va out of range write error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_VAOR_ADDR_WR )); + +for (i =0 ; i <8 ; i++) { + reg_val =DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i)); +if (reg_val &0x1 ) +DRM_INFO ("layer%d: 0x%08x 0x%08x 0x%08x ctrl: 0x%08x\n" , i, +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR0 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR1 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR2 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i))); + } + } + +return val; +} + +static void dpu_clean_all (struct dpu_context *ctx) +{ +int i; + +for (i =0 ; i <8 ; i++) +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i),0x00 ); +} + +static u32 dpu_isr (struct dpu_context *ctx) +{ +u32 reg_val, int_mask =0 ; + + reg_val =DPU_REG_RD (ctx->base +REG_DPU_INT_STS ); + +/* disable err interrupt */ +if (reg_val &BIT_DPU_INT_ERR ) + int_mask |=BIT_DPU_INT_ERR ; + +/* dpu update done isr */ +if (reg_val &BIT_DPU_INT_UPDATE_DONE ) { + ctx->evt_update = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu stop done isr */ +if (reg_val &BIT_DPU_INT_DONE ) { + ctx->evt_stop = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu ifbc payload error isr */ +if (reg_val &BIT_DPU_INT_FBC_PLD_ERR ) { + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +DRM_ERROR ("dpu ifbc payload error\n" ); + } + +/* dpu ifbc header error isr */ +if (reg_val &BIT_DPU_INT_FBC_HDR_ERR ) { + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +DRM_ERROR ("dpu ifbc header error\n" ); + } + + int_mask |=check_mmu_isr (ctx, reg_val); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR , reg_val); +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN , int_mask); + +return reg_val; +} + +static int dpu_wait_stop_done (struct dpu_context *ctx) +{ +int rc; + +if (ctx->stopped) +return 0 ; + + rc =wait_event_interruptible_timeout (ctx->wait_queue, ctx->evt_stop, +msecs_to_jiffies (500 )); + ctx->evt_stop = false; + + ctx->stopped = true; + +if (!rc) { +DRM_ERROR ("dpu wait for stop done time out!\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +static int dpu_wait_update_done (struct dpu_context *ctx) +{ +int rc; + + ctx->evt_update = false; + + rc =wait_event_interruptible_timeout (ctx->wait_queue, ctx->evt_update, +msecs_to_jiffies (500 )); + +if (!rc) { +DRM_ERROR ("dpu wait for reg update done time out!\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +static void dpu_stop (struct dpu_context *ctx) +{ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_STOP ); + +dpu_wait_stop_done (ctx); +} + +static void dpu_run (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; +} + +static void dpu_init (struct dpu_context *ctx) +{ +u32 reg_val, size; + +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + + size = (ctx->vm.vactive <<16 ) | ctx->vm.hactive; + +DPU_REG_WR (ctx->base +REG_PANEL_SIZE , size); +DPU_REG_WR (ctx->base +REG_BLEND_SIZE , size); + + reg_val =BIT_DPU_COEF_NARROW_RANGE |BIT_DPU_Y2R_COEF_ITU709_STANDARD ; +DPU_REG_WR (ctx->base +REG_DPU_CFG0 , reg_val); +DPU_REG_WR (ctx->base +REG_DPU_CFG1 ,0x004466da ); +DPU_REG_WR (ctx->base +REG_DPU_CFG2 ,0x00 ); + +if (ctx->stopped) +dpu_clean_all (ctx); + +DPU_REG_WR (ctx->base +REG_MMU_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_PPN1 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE1 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_PPN2 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE2 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_VPN_RANGE ,0x1ffff ); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xffff ); +} + +static void dpu_fini (struct dpu_context *ctx)
Quoted 8 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 283
Quoted 7 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +7
-0+{ +DPU_REG_WR (ctx->base +REG_DPU_INT_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xff ); +} + +static void dpu_layer (struct dpu_context *ctx, +struct dpu_layer *hwlayer)No linebreak needed here.
It has been fixed on RFC V7.
Quoted 194 lines
Quoted 194 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +193
-0+{ +const struct drm_format_info *info; +u32 size, offset, ctrl, pitch; +int i; + + offset = (hwlayer->dst_x &0xffff ) | ((hwlayer->dst_y) <<16 ); + +if (hwlayer->src_w && hwlayer->src_h) + size = (hwlayer->src_w &0xffff ) | ((hwlayer->src_h) <<16 ); +else + size = (hwlayer->dst_w &0xffff ) | ((hwlayer->dst_h) <<16 ); + +for (i =0 ; i < hwlayer->planes; i++) +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR0 , + hwlayer->index), hwlayer->addr[i]); + +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_POS , + hwlayer->index), offset); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_SIZE , + hwlayer->index), size); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CROP_START , + hwlayer->index), hwlayer->src_y <<16 | hwlayer->src_x); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_ALPHA , + hwlayer->index), hwlayer->alpha); + + info =drm_format_info (hwlayer->format); +if (hwlayer->planes ==3 ) { +/* UV pitch is 1/2 of Y pitch*/ + pitch = (hwlayer->pitch[0 ] / info->cpp[0 ]) | + (hwlayer->pitch[0 ] / info->cpp[0 ] <<15 ); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + }else { + pitch = hwlayer->pitch[0 ] / info->cpp[0 ]; +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + } + + ctrl = hwlayer->format | + hwlayer->blending | + (hwlayer->rotation &0x7 ) <<20 ; + +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index), ctrl); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index),BIT_DPU_LAY_EN ); + +DRM_DEBUG ("dst_x = %d, dst_y = %d, dst_w = %d, dst_h = %d\n" , + hwlayer->dst_x, hwlayer->dst_y, + hwlayer->dst_w, hwlayer->dst_h); +DRM_DEBUG ("start_x = %d, start_y = %d, start_w = %d, start_h = %d\n" , + hwlayer->src_x, hwlayer->src_y, + hwlayer->src_w, hwlayer->src_h); +} + +static void dpu_flip (struct dpu_context *ctx, +struct dpu_layer layers[],u8 count) +{ +int i; +u32 reg_val; + +/* +* Make sure the dpu is in stop status. DPU_R2P0 has no shadow +* registers in EDPI mode. So the config registers can only be +* updated in the rising edge of DPU_RUN bit. +*/ +if (ctx->if_type ==SPRD_DPU_IF_EDPI ) +dpu_wait_stop_done (ctx); + +/* reset the bgcolor to black */ +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + +/* disable all the layers */ +dpu_clean_all (ctx); + +/* start configure dpu layers */ +for (i =0 ; i < count; i++) +dpu_layer (ctx, &layers[i]); + +/* update trigger and wait */ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +if (!ctx->stopped) { +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_REG_UPDATE ); +dpu_wait_update_done (ctx); + } + +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_ERR ); + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; + } + +/* +* If the following interrupt was disabled in isr, +* re-enable it. +*/ + reg_val =BIT_DPU_INT_FBC_PLD_ERR | +BIT_DPU_INT_FBC_HDR_ERR | +BIT_DPU_INT_MMU_VAOR_RD | +BIT_DPU_INT_MMU_VAOR_WR | +BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +DPU_REG_SET (ctx->base +REG_DPU_INT_EN , reg_val); + +} + +static void dpu_dpi_init (struct dpu_context *ctx) +{ +u32 int_mask =0 ; +u32 reg_val; + +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +/* use dpi as interface */ +DPU_REG_CLR (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* disable Halt function for SPRD DSI */ +DPU_REG_CLR (ctx->base +REG_DPI_CTRL ,BIT_DPU_DPI_HALT_EN ); + +/* select te from external pad */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_FROM_EXTERNAL_PAD ); + +/* set dpi timing */ + reg_val = ctx->vm.hsync_len <<0 | + ctx->vm.hback_porch <<8 | + ctx->vm.hfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_H_TIMING , reg_val); + + reg_val = ctx->vm.vsync_len <<0 | + ctx->vm.vback_porch <<8 | + ctx->vm.vfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_V_TIMING , reg_val); + +if (ctx->vm.vsync_len + ctx->vm.vback_porch <32 ) +DRM_WARN ("Warning: (vsync + vbp) < 32, " +"underflow risk!\n" ); + +/* enable dpu update done INT */ + int_mask |=BIT_DPU_INT_UPDATE_DONE ; +/* enable dpu DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable dpu dpi vsync */ + int_mask |=BIT_DPU_INT_VSYNC ; +/* enable dpu TE INT */ + int_mask |=BIT_DPU_INT_TE ; +/* enable underflow err INT */ + int_mask |=BIT_DPU_INT_ERR ; + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +/* use edpi as interface */ +DPU_REG_SET (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* use external te */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_FROM_EXTERNAL_PAD ); + +/* enable te */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_TE_EN ); + +/* enable stop DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable TE INT */ + int_mask |=BIT_DPU_INT_TE ; + } + +/* enable ifbc payload error INT */ + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +/* enable ifbc header error INT */ + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +/* enable iommu va out of range read error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_RD ; +/* enable iommu va out of range write error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_WR ; +/* enable iommu invalid read error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_RD ; +/* enable iommu invalid write error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_WR ; + +DPU_REG_WR (ctx->base +REG_DPU_INT_EN , int_mask); +} + +static void enable_vsync (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} + +static void disable_vsync (struct dpu_context *ctx) +{ +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} + +static const u32 primary_fmts[] = { +DRM_FORMAT_XRGB8888 ,DRM_FORMAT_XBGR8888 , +DRM_FORMAT_ARGB8888 ,DRM_FORMAT_ABGR8888 , +DRM_FORMAT_RGBA8888 ,DRM_FORMAT_BGRA8888 ,
Quoted 8 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 482
Quoted 6 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +6
-0+DRM_FORMAT_RGBX8888 ,DRM_FORMAT_RGB565 , +DRM_FORMAT_BGR565 ,DRM_FORMAT_NV12 , +DRM_FORMAT_NV21 ,DRM_FORMAT_NV16 , +DRM_FORMAT_NV61 ,DRM_FORMAT_YUV420 , + DRM_FORMAT_YVU420, +};One format per line improves readability a lot.
Maybe sort alphbetically too.
It has been fixed on RFC V7.
Quoted 5 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 485
Quoted 4 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +3
-0+ +static void dpu_capability (struct dpu_context *ctx, +struct dpu_capability *cap)Drop linebreak
It has been fixed on RFC V7.
Quoted 894 lines
Quoted 894 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +18
-0+{ + cap->max_layers =6 ; + cap->fmts_ptr = primary_fmts; + cap->fmts_cnt =ARRAY_SIZE (primary_fmts); +} + +const struct dpu_core_ops dpu_r2p0_core_ops = { + .init = dpu_init, + .fini = dpu_fini, + .run = dpu_run, + .stop = dpu_stop, + .isr = dpu_isr, + .ifconfig = dpu_dpi_init, + .capability = dpu_capability, + .flip = dpu_flip, + .enable_vsync = enable_vsync, + .disable_vsync = disable_vsync, +};drivers/gpu/drm/sprd/sprd_dpu.c new file +646
-0@@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/component.h> +#include <linux/dma-buf.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_plane_helper.h> + +#include "sprd_drm.h" +#include "sprd_dpu.h" + +struct sprd_plane { +struct drm_plane plane; +u32 index; +u32 addr[4 ]; +u32 pitch[4 ]; +u32 format; +u32 rotation; +u32 blend_mode; +}; + +static void sprd_dpu_init (struct sprd_dpu *dpu); +static void sprd_dpu_fini (struct sprd_dpu *dpu); + +static inline struct sprd_plane *to_sprd_plane (struct drm_plane *plane) +{ + return container_of(plane, struct sprd_plane, plane); +} + +static int sprd_plane_format_convert (u32 fourcc,u32 *format) +{ +switch (fourcc) { +case DRM_FORMAT_BGRA8888 : +/* BGRA8888 -> ARGB8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_RGBX8888 : +case DRM_FORMAT_RGBA8888 : +/* RGBA8888 -> ABGR8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* FALLTHRU */ +case DRM_FORMAT_ABGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_ARGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_XBGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_XRGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_BGR565 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_RGB565 : + *format |=BIT_DPU_LAY_FORMAT_RGB565 ; +break ; +case DRM_FORMAT_NV12 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_NV21 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV16 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV61 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YUV420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YVU420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_rotation_convert (u32 angle,u32 *rotation) +{ +switch (angle) { +case DRM_MODE_ROTATE_0 : + *rotation =DPU_LAYER_ROTATION_0 ; +break ; +case DRM_MODE_ROTATE_90 : + *rotation =DPU_LAYER_ROTATION_90 ; +break ; +case DRM_MODE_ROTATE_180 : + *rotation =DPU_LAYER_ROTATION_180 ; +break ; +case DRM_MODE_ROTATE_270 : + *rotation =DPU_LAYER_ROTATION_270 ; +break ; +case DRM_MODE_REFLECT_Y : + *rotation =DPU_LAYER_ROTATION_180_M ; +break ; +case (DRM_MODE_REFLECT_Y |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_90_M ; +break ; +case DRM_MODE_REFLECT_X : + *rotation =DPU_LAYER_ROTATION_0_M ; +break ; +case (DRM_MODE_REFLECT_X |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_270_M ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_atomic_check (struct drm_plane *plane, +struct drm_plane_state *state) +{ +struct sprd_plane *p =to_sprd_plane (plane); +struct drm_framebuffer *fb = state->fb; +struct drm_gem_cma_object *cma_obj; +int i, ret; +u32 addr; + +if (!state->fb || !state->crtc) +return 0 ; + + ret =sprd_plane_format_convert (fb->format->format, + &p->format); +if (ret <0 ) { +DRM_ERROR ("Invalid plane format\n" ); +return ret; + } + + ret =sprd_plane_rotation_convert (state->rotation, + &p->rotation); +if (ret <0 ) { +DRM_ERROR ("Invalid plane rotation\n" ); +return ret; + } + +switch (state->pixel_blend_mode) { +case DRM_MODE_BLEND_COVERAGE : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Normal mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_NORMAL ; +break ; +case DRM_MODE_BLEND_PREMULTI : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Pre-mult mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_PREMULT ; +break ; +case DRM_MODE_BLEND_PIXEL_NONE : +default : +/* don't do blending, maybe RGBX */ +/* alpha mode select - layer alpha */ + p->blend_mode |=BIT_DPU_LAY_LAYER_ALPHA ; +break ; + } + +for (i =0 ; i < fb->format->num_planes; i++) { + cma_obj =drm_fb_cma_get_gem_obj (fb, i); + addr = cma_obj->paddr + fb->offsets[i]; +if (addr %16 ) { +DRM_ERROR ("layer addr[%d] is not 16 bytes align, it's 0x%08x\n" , + i, addr); +return -EFAULT ; + } + + p->addr[i] = addr; + p->pitch[i] = fb->pitches[i]; + } + +return 0 ; +} + +static void sprd_plane_atomic_update (struct drm_plane *plane, +struct drm_plane_state *old_state) +{ +struct drm_plane_state *state = plane->state; +struct drm_framebuffer *fb = plane->state->fb; +struct sprd_plane *p =to_sprd_plane (plane); +struct sprd_dpu *dpu =crtc_to_dpu (plane->state->crtc); +struct dpu_layer *layer = &dpu->layers[p->index]; +int i; + +if (!state->crtc || !state->fb) +return ; + + layer->index = p->index; + layer->src_x = state->src_x >>16 ; + layer->src_y = state->src_y >>16 ; + layer->src_w = state->src_w >>16 ; + layer->src_h = state->src_h >>16 ; + layer->dst_x = state->crtc_x; + layer->dst_y = state->crtc_y; + layer->dst_w = state->crtc_w; + layer->dst_h = state->crtc_h; + layer->alpha = state->alpha; + layer->format = p->format; + layer->blending = p->blend_mode; + layer->rotation = p->rotation; + layer->planes = fb->format->num_planes; + +for (i =0 ; i < layer->planes; i++) { + layer->addr[i] = p->addr[i]; + layer->pitch[i] = p->pitch[i]; + } + + dpu->pending_planes++; +} + +static void sprd_plane_create_properties (struct sprd_plane *p,int index) +{ +unsigned int supported_modes =BIT (DRM_MODE_BLEND_PIXEL_NONE ) | +BIT (DRM_MODE_BLEND_PREMULTI ) | +BIT (DRM_MODE_BLEND_COVERAGE ); + +/* create rotation property */ +drm_plane_create_rotation_property (&p->plane, +DRM_MODE_ROTATE_0 , +DRM_MODE_ROTATE_MASK | +DRM_MODE_REFLECT_MASK ); + +/* create alpha property */ +drm_plane_create_alpha_property (&p->plane); + +/* create blend mode property */ +drm_plane_create_blend_mode_property (&p->plane, supported_modes); + +/* create zpos property */ +drm_plane_create_zpos_immutable_property (&p->plane, index); +} + +static const struct drm_plane_helper_funcs sprd_plane_helper_funcs = { + .atomic_check = sprd_plane_atomic_check, + .atomic_update = sprd_plane_atomic_update, +}; + +static const struct drm_plane_funcs sprd_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static struct drm_plane *sprd_plane_init (struct drm_device *drm, +struct sprd_dpu *dpu) +{ +struct drm_plane *primary =NULL ; +struct sprd_plane *p =NULL ; +struct dpu_capability cap = {}; +int ret, i; + + dpu->core->capability (&dpu->ctx, &cap); + + dpu->layers =devm_kcalloc (drm->dev, cap.max_layers, +sizeof (struct dpu_layer ),GFP_KERNEL ); +if (!dpu->layers) +return ERR_PTR (-ENOMEM ); + +for (i =0 ; i < cap.max_layers; i++) { + + p =devm_kzalloc (drm->dev,sizeof (*p),GFP_KERNEL ); +if (!p) +return ERR_PTR (-ENOMEM ); + + ret =drm_universal_plane_init (drm, &p->plane,1 , + &sprd_plane_funcs, cap.fmts_ptr, + cap.fmts_cnt,NULL , +DRM_PLANE_TYPE_PRIMARY ,NULL ); +if (ret) { +DRM_ERROR ("fail to init primary plane\n" ); +return ERR_PTR (ret); + } + +drm_plane_helper_add (&p->plane, &sprd_plane_helper_funcs); + +sprd_plane_create_properties (p, i); + + p->index = i; +if (i ==0 ) + primary = &p->plane; + } + +return primary; +} + +static enum drm_mode_status sprd_crtc_mode_valid (struct drm_crtc *crtc, +const struct drm_display_mode *mode) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +DRM_DEBUG ("%s() mode: " DRM_MODE_FMT "\n" , __func__,DRM_MODE_ARG (mode)); + +if (mode->type &DRM_MODE_TYPE_PREFERRED ) { +drm_display_mode_to_videomode (mode, &dpu->ctx.vm); + +if ((mode->hdisplay == mode->htotal) || + (mode->vdisplay == mode->vtotal)) + dpu->ctx.if_type =SPRD_DPU_IF_EDPI ; +else + dpu->ctx.if_type =SPRD_DPU_IF_DPI ; + } + +return MODE_OK ; +} + +static void sprd_crtc_atomic_enable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +sprd_dpu_init (dpu); + +enable_irq (dpu->ctx.irq); +} + +static void sprd_crtc_atomic_disable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +disable_irq (dpu->ctx.irq); + +sprd_dpu_fini (dpu); + +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_atomic_check (struct drm_crtc *crtc, +struct drm_crtc_state *state) +{ +DRM_DEBUG ("%s()\n" , __func__); + +return 0 ; +} + +static void sprd_crtc_atomic_begin (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +memset (dpu->layers,0 ,sizeof (*dpu->layers) * dpu->pending_planes); + + dpu->pending_planes =0 ; +} + +static void sprd_crtc_atomic_flush (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) + +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +if (dpu->pending_planes) + dpu->core->flip (&dpu->ctx, dpu->layers, dpu->pending_planes); + +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_enable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->enable_vsync (&dpu->ctx); + +return 0 ; +} + +static void sprd_crtc_disable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->disable_vsync (&dpu->ctx); +} + +static const struct drm_crtc_helper_funcs sprd_crtc_helper_funcs = { + .mode_valid = sprd_crtc_mode_valid, + .atomic_check = sprd_crtc_atomic_check, + .atomic_begin = sprd_crtc_atomic_begin, + .atomic_flush = sprd_crtc_atomic_flush, + .atomic_enable = sprd_crtc_atomic_enable, + .atomic_disable = sprd_crtc_atomic_disable, +}; + +static const struct drm_crtc_funcs sprd_crtc_funcs = { + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = sprd_crtc_enable_vblank, + .disable_vblank = sprd_crtc_disable_vblank, +}; + +static int sprd_crtc_init (struct drm_device *drm,struct drm_crtc *crtc, +struct drm_plane *primary) +{ +struct device_node *port; +int ret; + +/* +* set crtc port so that drm_of_find_possible_crtcs call works +*/ + port =of_parse_phandle (drm->dev->of_node,"ports" ,0 ); +if (!port) { +DRM_ERROR ("find 'ports' phandle of %s failed\n" , + drm->dev->of_node->full_name); +return -EINVAL ; + } +of_node_put (port); + crtc->port = port; + + ret =drm_crtc_init_with_planes (drm, crtc, primary,NULL , + &sprd_crtc_funcs,NULL ); +if (ret) { +DRM_ERROR ("failed to init crtc.\n" ); +return ret; + } + +drm_mode_crtc_set_gamma_size (crtc,256 ); + +drm_crtc_helper_add (crtc, &sprd_crtc_helper_funcs); + +return 0 ; +} + +static void sprd_dpu_init (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->init (ctx); + dpu->core->ifconfig (ctx); +} + +static void sprd_dpu_fini (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->fini (ctx); +} + +static irqreturn_t sprd_dpu_isr (int irq,void *data) +{ +struct sprd_dpu *dpu = data; +struct dpu_context *ctx = &dpu->ctx; +u32 int_mask =0 ; + + int_mask = dpu->core->isr (ctx); + +if (int_mask &BIT_DPU_INT_ERR ) +DRM_WARN ("Warning: dpu underflow!\n" ); + +if (int_mask &BIT_DPU_INT_VSYNC ) +drm_crtc_handle_vblank (&dpu->crtc); + +return IRQ_HANDLED ; +} + +static int sprd_dpu_bind (struct device *dev,struct device *master,void *data) +{ +struct drm_device *drm = data; +struct sprd_dpu *dpu =dev_get_drvdata (dev); +struct drm_plane *plane; +int ret; + + plane =sprd_plane_init (drm, dpu); +if (IS_ERR_OR_NULL (plane)) { + ret =PTR_ERR (plane); +return ret; + } + + ret =sprd_crtc_init (drm, &dpu->crtc, plane); +if (ret) +return ret; + +return 0 ; +} + +static void sprd_dpu_unbind (struct device *dev,struct device *master, +void *data) +{ +struct sprd_dpu *dpu =dev_get_drvdata (dev); + +drm_crtc_cleanup (&dpu->crtc); +} + +static const struct component_ops dpu_component_ops = { + .bind = sprd_dpu_bind, + .unbind = sprd_dpu_unbind, +}; + +static int sprd_dpu_context_init (struct sprd_dpu *dpu, +struct device *dev) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dpu_context *ctx = &dpu->ctx; +struct resource *res; +int ret; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + ctx->base =devm_ioremap (dev, res->start,resource_size (res)); +if (!ctx->base) { +DRM_ERROR ("failed to map dpu registers\n" ); +return -EFAULT ; + } + + ctx->irq =platform_get_irq (pdev,0 ); +if (ctx->irq <0 ) { +DRM_ERROR ("failed to get dpu irq\n" ); +return ctx->irq; + } + +irq_set_status_flags (ctx->irq,IRQ_NOAUTOEN ); + ret =devm_request_irq (dev, ctx->irq, sprd_dpu_isr, +0 ,"DPU" , dpu); +if (ret) { +DRM_ERROR ("failed to register dpu irq handler\n" ); +return ret; + } + +init_waitqueue_head (&ctx->wait_queue); + +return 0 ; +} + +static const struct sprd_dpu_ops sharkl3_dpu = { + .core = &dpu_r2p0_core_ops, +}; + +static const struct of_device_id dpu_match_table[] = { + { .compatible ="sprd,sharkl3-dpu" , + .data = &sharkl3_dpu }, + {/* sentinel */ }, +}; + +static int sprd_dpu_probe (struct platform_device *pdev) +{ +const struct sprd_dpu_ops *pdata; +struct sprd_dpu *dpu; +int ret; + + dpu =devm_kzalloc (&pdev->dev,sizeof (*dpu),GFP_KERNEL ); +if (!dpu) +return -ENOMEM ; + + pdata =of_device_get_match_data (&pdev->dev); +if (pdata) { + dpu->core = pdata->core; + }else { +DRM_ERROR ("No matching driver data found\n" ); +return -EINVAL ; + } + + ret =sprd_dpu_context_init (dpu, &pdev->dev); +if (ret) +return ret; + +platform_set_drvdata (pdev, dpu); + +return component_add (&pdev->dev, &dpu_component_ops); +} + +static int sprd_dpu_remove (struct platform_device *pdev) +{ +component_del (&pdev->dev, &dpu_component_ops); +return 0 ; +} + +struct platform_driver sprd_dpu_driver = { + .probe = sprd_dpu_probe, + .remove = sprd_dpu_remove, + .driver = { + .name ="sprd-dpu-drv" , + .of_match_table = dpu_match_table, + }, +}; + +MODULE_AUTHOR ("Leon He <[email protected]>" ); +MODULE_AUTHOR ("Kevin Tang <[email protected]>" ); +MODULE_DESCRIPTION ("Unisoc Display Controller Driver" ); +MODULE_LICENSE ("GPL v2" );drivers/gpu/drm/sprd/sprd_dpu.h new file +187
-0@@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#ifndef __SPRD_DPU_H__ +#define __SPRD_DPU_H__ + +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <video/videomode.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_print.h> +#include <drm/drm_vblank.h> +#include <uapi/drm/drm_mode.h> + +#define BIT_DPU_INT_DONE_ BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_EDPI_TE BIT(3) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_WB_DONE BIT(6) +#define BIT_DPU_INT_WB_ERR BIT(7) + +#define BIT_DPU_LAY_LAYER_ALPHA (0x01 << 2) +#define BIT_DPU_LAY_COMBO_ALPHA (0x02 << 2) +#define BIT_DPU_LAY_FORMAT_YUV422_2PLANE (0x00 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_2PLANE (0x01 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_3PLANE (0x02 << 4) +#define BIT_DPU_LAY_FORMAT_ARGB8888 (0x03 << 4) +#define BIT_DPU_LAY_FORMAT_RGB565 (0x04 << 4) +#define BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 (0x00 << 8) +#define BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 (0x01 << 8) +#define BIT_DPU_LAY_NO_SWITCH (0x00 << 10) +#define BIT_DPU_LAY_RB_OR_UV_SWITCH (0x01 << 10) +#define BIT_DPU_LAY_MODE_BLEND_NORMAL (0x00 << 16) +#define BIT_DPU_LAY_MODE_BLEND_PREMULT (0x01 << 16) + +enum { +SPRD_DPU_IF_DBI =0 , +SPRD_DPU_IF_DPI , +SPRD_DPU_IF_EDPI , +SPRD_DPU_IF_LIMIT +}; + +enum { +DPU_LAYER_ROTATION_0 , +DPU_LAYER_ROTATION_90 , +DPU_LAYER_ROTATION_180 , +DPU_LAYER_ROTATION_270 , +DPU_LAYER_ROTATION_0_M , +DPU_LAYER_ROTATION_90_M , +DPU_LAYER_ROTATION_180_M , +DPU_LAYER_ROTATION_270_M , +}; + +struct dpu_layer { +u8 index; +u8 planes; +u32 addr[4 ]; +u32 pitch[4 ]; +s16 src_x; +s16 src_y; +s16 src_w; +s16 src_h; +s16 dst_x; +s16 dst_y; +u16 dst_w; +u16 dst_h; +u32 format; +u32 alpha; +u32 blending; +u32 rotation; +}; + +/** +* Sprd DPU capability structure +* +* @max_layers: maximum number of layers available +* @fmts_ptr: A pointer to array of supported pixel formats +* @fmts_cnt: the number of format on @fmts_ptr +*/ +struct dpu_capability { +u32 max_layers; +const u32 *fmts_ptr; +u32 fmts_cnt; +}; + +/** +* Sprd DPU core callback ops +* +* This structure decribes the display controller common +* callback ops +* +* @init: initial DPU core +* @fini: cleanup DPU core +* @run: enable DPU output +* @stop: disable DPU output +* @enable_vsync: enable vblank interrupt +* @disable_vsync: disable vblank interrupt +* @isr: function pointer to the isr +* @ifconfig: initial DPI interface +* @flip: commit CRTC planes to DPU +* @capability: callback for DPU capabilities +*/ +struct dpu_context ; +struct dpu_core_ops { +void (*init)(struct dpu_context *ctx); +void (*fini)(struct dpu_context *ctx); +void (*run)(struct dpu_context *ctx); +void (*stop)(struct dpu_context *ctx); +void (*enable_vsync)(struct dpu_context *ctx); +void (*disable_vsync)(struct dpu_context *ctx); +u32 (*isr)(struct dpu_context *ctx); +void (*ifconfig)(struct dpu_context *ctx); +void (*flip)(struct dpu_context *ctx, +struct dpu_layer layers[],u8 count); +void (*capability)(struct dpu_context *ctx, +struct dpu_capability *cap); +}; + +/** +* Sprd DPU context structure +* +* @base: DPU controller base address +* @irq: IRQ number to install the handler for +* @if_type: The type of DPI interface, default is DPI mode. +* @vm: videomode structure to use for DPU and DPI initialization +* @stopped: indicates whether DPU are stopped +* @wait_queue: wait queue, used to wait for DPU shadow register update done and +* DPU stop register done interrupt signal. +* @evt_update: wait queue condition for DPU shadow register +* @evt_stop: wait queue condition for DPU stop register +*/ +struct dpu_context { +void __iomem *base; +int irq; +u8 if_type; +struct videomode vm; +bool stopped; +wait_queue_head_t wait_queue; +bool evt_update; +bool evt_stop; +}; + +/** +* Sprd DPU device structure +* +* @crtc: DRM crtc +* @ctx: A pointer to the DPU's implementation specific context +* @core: pointer to callbacks for DPU core functionality +* @layers: active DPU layers ready to commit +* @pending_planes: the number of layers on @layers +*/ +struct sprd_dpu { +struct drm_crtc crtc; +struct dpu_context ctx; +const struct dpu_core_ops *core; +struct dpu_layer *layers; +u8 pending_planes; +}; + +/** +* Sprd DPU H/W callback ops match table structure +* The structure used for matching a specific device callback ops +* +* @core: pointer to callbacks for DPU core functionality +*/ +struct sprd_dpu_ops { +const struct dpu_core_ops *core; +}; + +static inline struct sprd_dpu *crtc_to_dpu (struct drm_crtc *crtc) +{ + return crtc ? container_of(crtc, struct sprd_dpu, crtc) : NULL; +} + +extern const struct dpu_core_ops dpu_r2p0_core_ops; + +#endif drivers/gpu/drm/sprd/sprd_drm.c +1
-0@@ -200,6 +200,7 @@ static struct platform_driver sprd_drm_driver = {static struct platform_driver *sprd_drm_drivers[] = { &sprd_drm_driver, + &sprd_dpu_driver, };static int __init sprd_drm_init (void )drivers/gpu/drm/sprd/sprd_drm.h +2
-1@@ -13,4 +13,6 @@ struct sprd_drm { struct drm_device *drm; }; +extern struct platform_driver sprd_dpu_driver; +#endif /* _SPRD_DRM_H_ */ --2.7.4
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH RFC v6 4/6] drm/sprd: add Unisoc's drm display controller driver
In reply to Kevin TangQuoted 6 lines · Kevin Tang
From: Kevin Tang <[email protected]>
Adds DPU(Display Processor Unit) support for the Unisoc's display subsystem. It's support multi planes, scaler, rotation, PQ(Picture Quality) and more.
Quoted 8 lines
RFC v6:
- Access registers via readl/writel
- Checking for unsupported KMS properties (format, rotation,blend_mode, etc) onplane_checkops
- Remove always true checks for dpu core opsCc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>
Quickly scrolled through this, and the entire thing very much leaves a midlayer heavy aftertaste. Do we really need stuff like struct dpu_layer and struct dpu_core_ops? They only seem to complicate the code base, and seem to have no real reason. The indirection with first computing register values into a sprd_plane/crtc structure, and then writing it into hardware is also a bit much - I recommend to only do that if you have to compute values in _check to validate them, so that the computation doesn't have to be repeated in the commit phase functions.
Also, the layer and pending_flips stuff in sprd_dpu don't work with atomic, that races. You have to put all that stuff into state objects, or if it's some data shared with interrupt handlers (doesn't seem to be the case here), it needs its own locking, and any data you need in the interrupt handler must be copied over.
Also no devm_kzalloc for anything containined a drm_* structure, that's the wrong lifetime.
So yeah high level review is that I think this driver would benefit a lot from a pile of demidlayer.
Cheers, Daniel
Quoted 1,416 lines
--- drivers/gpu/drm/sprd/Makefile | 5 +- drivers/gpu/drm/sprd/dpu/Makefile | 3 + drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 503 ++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.c | 646 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.h | 187 +++++++++++ drivers/gpu/drm/sprd/sprd_drm.c | 1 + drivers/gpu/drm/sprd/sprd_drm.h | 2 + 7 files changed, 1346 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.hdrivers/gpu/drm/sprd/Makefile +4
-1@@ -2,4 +2,7 @@ subdir-ccflags-y += -I$(srctree)/$(src) -obj-y := sprd_drm.o +obj-y := sprd_drm.o \ + sprd_dpu.o + +obj-y += dpu/drivers/gpu/drm/sprd/dpu/Makefile new file +3
-0@@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += dpu_r2p0.odrivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +503
-0@@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/workqueue.h> + +#include "sprd_dpu.h" + +/* DPU registers size, 4 Bytes(32 Bits) */ +#define DPU_REG_SIZE 0x04 + +/* Layer registers offset */ +#define DPU_LAY_REG_OFFSET 0x0C + +#define DPU_LAY_REG (reg, index) \ + (reg + index * DPU_LAY_REG_OFFSET * DPU_REG_SIZE) + +#define DPU_REG_RD (reg) readl_relaxed(reg) + +#define DPU_REG_WR (reg, mask) writel_relaxed(mask, reg) + +#define DPU_REG_SET (reg, mask) \ + writel_relaxed(readl_relaxed(reg) | mask, reg) + +#define DPU_REG_CLR (reg, mask) \ + writel_relaxed(readl_relaxed(reg) & ~mask, reg) + +/* Global control registers */ +#define REG_DPU_CTRL 0x04 +#define REG_DPU_CFG0 0x08 +#define REG_DPU_CFG1 0x0C +#define REG_DPU_CFG2 0x10 +#define REG_PANEL_SIZE 0x20 +#define REG_BLEND_SIZE 0x24 +#define REG_BG_COLOR 0x2C + +/* Layer0 control registers */ +#define REG_LAY_BASE_ADDR0 0x30 +#define REG_LAY_BASE_ADDR1 0x34 +#define REG_LAY_BASE_ADDR2 0x38 +#define REG_LAY_CTRL 0x40 +#define REG_LAY_SIZE 0x44 +#define REG_LAY_PITCH 0x48 +#define REG_LAY_POS 0x4C +#define REG_LAY_ALPHA 0x50 +#define REG_LAY_PALLETE 0x58 +#define REG_LAY_CROP_START 0x5C + +/* Interrupt control registers */ +#define REG_DPU_INT_EN 0x1E0 +#define REG_DPU_INT_CLR 0x1E4 +#define REG_DPU_INT_STS 0x1E8 + +/* DPI control registers */ +#define REG_DPI_CTRL 0x1F0 +#define REG_DPI_H_TIMING 0x1F4 +#define REG_DPI_V_TIMING 0x1F8 + +/* MMU control registers */ +#define REG_MMU_EN 0x800 +#define REG_MMU_VPN_RANGE 0x80C +#define REG_MMU_VAOR_ADDR_RD 0x818 +#define REG_MMU_VAOR_ADDR_WR 0x81C +#define REG_MMU_INV_ADDR_RD 0x820 +#define REG_MMU_INV_ADDR_WR 0x824 +#define REG_MMU_PPN1 0x83C +#define REG_MMU_RANGE1 0x840 +#define REG_MMU_PPN2 0x844 +#define REG_MMU_RANGE2 0x848 + +/* Global control bits */ +#define BIT_DPU_RUN BIT(0) +#define BIT_DPU_STOP BIT(1) +#define BIT_DPU_REG_UPDATE BIT(2) +#define BIT_DPU_IF_EDPI BIT(0) +#define BIT_DPU_COEF_NARROW_RANGE BIT(4) +#define BIT_DPU_Y2R_COEF_ITU709_STANDARD BIT(5) + +/* Layer control bits */ +#define BIT_DPU_LAY_EN BIT(0) + +/* Interrupt control & status bits */ +#define BIT_DPU_INT_DONE BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_FBC_PLD_ERR BIT(8) +#define BIT_DPU_INT_FBC_HDR_ERR BIT(9) +#define BIT_DPU_INT_MMU_VAOR_RD BIT(16) +#define BIT_DPU_INT_MMU_VAOR_WR BIT(17) +#define BIT_DPU_INT_MMU_INV_RD BIT(18) +#define BIT_DPU_INT_MMU_INV_WR BIT(19) + +/* DPI control bits */ +#define BIT_DPU_EDPI_TE_EN BIT(8) +#define BIT_DPU_EDPI_FROM_EXTERNAL_PAD BIT(10) +#define BIT_DPU_DPI_HALT_EN BIT(16) + + +static u32 check_mmu_isr (struct dpu_context *ctx,u32 reg_val) +{ +u32 mmu_mask =BIT_DPU_INT_MMU_VAOR_RD | +BIT_DPU_INT_MMU_VAOR_WR | +BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +u32 val = reg_val & mmu_mask; +int i; + +if (val) { +DRM_ERROR ("--- iommu interrupt err: 0x%04x ---\n" , val); + +if (val &BIT_DPU_INT_MMU_INV_RD ) +DRM_ERROR ("iommu invalid read error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_INV_ADDR_RD )); +if (val &BIT_DPU_INT_MMU_INV_WR ) +DRM_ERROR ("iommu invalid write error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_INV_ADDR_WR )); +if (val &BIT_DPU_INT_MMU_VAOR_RD ) +DRM_ERROR ("iommu va out of range read error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_VAOR_ADDR_RD )); +if (val &BIT_DPU_INT_MMU_VAOR_WR ) +DRM_ERROR ("iommu va out of range write error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_VAOR_ADDR_WR )); + +for (i =0 ; i <8 ; i++) { + reg_val =DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i)); +if (reg_val &0x1 ) +DRM_INFO ("layer%d: 0x%08x 0x%08x 0x%08x ctrl: 0x%08x\n" , i, +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR0 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR1 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR2 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i))); + } + } + +return val; +} + +static void dpu_clean_all (struct dpu_context *ctx) +{ +int i; + +for (i =0 ; i <8 ; i++) +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i),0x00 ); +} + +static u32 dpu_isr (struct dpu_context *ctx) +{ +u32 reg_val, int_mask =0 ; + + reg_val =DPU_REG_RD (ctx->base +REG_DPU_INT_STS ); + +/* disable err interrupt */ +if (reg_val &BIT_DPU_INT_ERR ) + int_mask |=BIT_DPU_INT_ERR ; + +/* dpu update done isr */ +if (reg_val &BIT_DPU_INT_UPDATE_DONE ) { + ctx->evt_update = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu stop done isr */ +if (reg_val &BIT_DPU_INT_DONE ) { + ctx->evt_stop = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu ifbc payload error isr */ +if (reg_val &BIT_DPU_INT_FBC_PLD_ERR ) { + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +DRM_ERROR ("dpu ifbc payload error\n" ); + } + +/* dpu ifbc header error isr */ +if (reg_val &BIT_DPU_INT_FBC_HDR_ERR ) { + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +DRM_ERROR ("dpu ifbc header error\n" ); + } + + int_mask |=check_mmu_isr (ctx, reg_val); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR , reg_val); +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN , int_mask); + +return reg_val; +} + +static int dpu_wait_stop_done (struct dpu_context *ctx) +{ +int rc; + +if (ctx->stopped) +return 0 ; + + rc =wait_event_interruptible_timeout (ctx->wait_queue, ctx->evt_stop, +msecs_to_jiffies (500 )); + ctx->evt_stop = false; + + ctx->stopped = true; + +if (!rc) { +DRM_ERROR ("dpu wait for stop done time out!\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +static int dpu_wait_update_done (struct dpu_context *ctx) +{ +int rc; + + ctx->evt_update = false; + + rc =wait_event_interruptible_timeout (ctx->wait_queue, ctx->evt_update, +msecs_to_jiffies (500 )); + +if (!rc) { +DRM_ERROR ("dpu wait for reg update done time out!\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +static void dpu_stop (struct dpu_context *ctx) +{ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_STOP ); + +dpu_wait_stop_done (ctx); +} + +static void dpu_run (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; +} + +static void dpu_init (struct dpu_context *ctx) +{ +u32 reg_val, size; + +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + + size = (ctx->vm.vactive <<16 ) | ctx->vm.hactive; + +DPU_REG_WR (ctx->base +REG_PANEL_SIZE , size); +DPU_REG_WR (ctx->base +REG_BLEND_SIZE , size); + + reg_val =BIT_DPU_COEF_NARROW_RANGE |BIT_DPU_Y2R_COEF_ITU709_STANDARD ; +DPU_REG_WR (ctx->base +REG_DPU_CFG0 , reg_val); +DPU_REG_WR (ctx->base +REG_DPU_CFG1 ,0x004466da ); +DPU_REG_WR (ctx->base +REG_DPU_CFG2 ,0x00 ); + +if (ctx->stopped) +dpu_clean_all (ctx); + +DPU_REG_WR (ctx->base +REG_MMU_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_PPN1 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE1 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_PPN2 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE2 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_VPN_RANGE ,0x1ffff ); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xffff ); +} + +static void dpu_fini (struct dpu_context *ctx) +{ +DPU_REG_WR (ctx->base +REG_DPU_INT_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xff ); +} + +static void dpu_layer (struct dpu_context *ctx, +struct dpu_layer *hwlayer) +{ +const struct drm_format_info *info; +u32 size, offset, ctrl, pitch; +int i; + + offset = (hwlayer->dst_x &0xffff ) | ((hwlayer->dst_y) <<16 ); + +if (hwlayer->src_w && hwlayer->src_h) + size = (hwlayer->src_w &0xffff ) | ((hwlayer->src_h) <<16 ); +else + size = (hwlayer->dst_w &0xffff ) | ((hwlayer->dst_h) <<16 ); + +for (i =0 ; i < hwlayer->planes; i++) +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR0 , + hwlayer->index), hwlayer->addr[i]); + +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_POS , + hwlayer->index), offset); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_SIZE , + hwlayer->index), size); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CROP_START , + hwlayer->index), hwlayer->src_y <<16 | hwlayer->src_x); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_ALPHA , + hwlayer->index), hwlayer->alpha); + + info =drm_format_info (hwlayer->format); +if (hwlayer->planes ==3 ) { +/* UV pitch is 1/2 of Y pitch*/ + pitch = (hwlayer->pitch[0 ] / info->cpp[0 ]) | + (hwlayer->pitch[0 ] / info->cpp[0 ] <<15 ); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + }else { + pitch = hwlayer->pitch[0 ] / info->cpp[0 ]; +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + } + + ctrl = hwlayer->format | + hwlayer->blending | + (hwlayer->rotation &0x7 ) <<20 ; + +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index), ctrl); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index),BIT_DPU_LAY_EN ); + +DRM_DEBUG ("dst_x = %d, dst_y = %d, dst_w = %d, dst_h = %d\n" , + hwlayer->dst_x, hwlayer->dst_y, + hwlayer->dst_w, hwlayer->dst_h); +DRM_DEBUG ("start_x = %d, start_y = %d, start_w = %d, start_h = %d\n" , + hwlayer->src_x, hwlayer->src_y, + hwlayer->src_w, hwlayer->src_h); +} + +static void dpu_flip (struct dpu_context *ctx, +struct dpu_layer layers[],u8 count) +{ +int i; +u32 reg_val; + +/* +* Make sure the dpu is in stop status. DPU_R2P0 has no shadow +* registers in EDPI mode. So the config registers can only be +* updated in the rising edge of DPU_RUN bit. +*/ +if (ctx->if_type ==SPRD_DPU_IF_EDPI ) +dpu_wait_stop_done (ctx); + +/* reset the bgcolor to black */ +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + +/* disable all the layers */ +dpu_clean_all (ctx); + +/* start configure dpu layers */ +for (i =0 ; i < count; i++) +dpu_layer (ctx, &layers[i]); + +/* update trigger and wait */ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +if (!ctx->stopped) { +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_REG_UPDATE ); +dpu_wait_update_done (ctx); + } + +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_ERR ); + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; + } + +/* +* If the following interrupt was disabled in isr, +* re-enable it. +*/ + reg_val =BIT_DPU_INT_FBC_PLD_ERR | +BIT_DPU_INT_FBC_HDR_ERR | +BIT_DPU_INT_MMU_VAOR_RD | +BIT_DPU_INT_MMU_VAOR_WR | +BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +DPU_REG_SET (ctx->base +REG_DPU_INT_EN , reg_val); + +} + +static void dpu_dpi_init (struct dpu_context *ctx) +{ +u32 int_mask =0 ; +u32 reg_val; + +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +/* use dpi as interface */ +DPU_REG_CLR (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* disable Halt function for SPRD DSI */ +DPU_REG_CLR (ctx->base +REG_DPI_CTRL ,BIT_DPU_DPI_HALT_EN ); + +/* select te from external pad */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_FROM_EXTERNAL_PAD ); + +/* set dpi timing */ + reg_val = ctx->vm.hsync_len <<0 | + ctx->vm.hback_porch <<8 | + ctx->vm.hfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_H_TIMING , reg_val); + + reg_val = ctx->vm.vsync_len <<0 | + ctx->vm.vback_porch <<8 | + ctx->vm.vfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_V_TIMING , reg_val); + +if (ctx->vm.vsync_len + ctx->vm.vback_porch <32 ) +DRM_WARN ("Warning: (vsync + vbp) < 32, " +"underflow risk!\n" ); + +/* enable dpu update done INT */ + int_mask |=BIT_DPU_INT_UPDATE_DONE ; +/* enable dpu DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable dpu dpi vsync */ + int_mask |=BIT_DPU_INT_VSYNC ; +/* enable dpu TE INT */ + int_mask |=BIT_DPU_INT_TE ; +/* enable underflow err INT */ + int_mask |=BIT_DPU_INT_ERR ; + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +/* use edpi as interface */ +DPU_REG_SET (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* use external te */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_FROM_EXTERNAL_PAD ); + +/* enable te */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_TE_EN ); + +/* enable stop DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable TE INT */ + int_mask |=BIT_DPU_INT_TE ; + } + +/* enable ifbc payload error INT */ + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +/* enable ifbc header error INT */ + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +/* enable iommu va out of range read error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_RD ; +/* enable iommu va out of range write error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_WR ; +/* enable iommu invalid read error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_RD ; +/* enable iommu invalid write error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_WR ; + +DPU_REG_WR (ctx->base +REG_DPU_INT_EN , int_mask); +} + +static void enable_vsync (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} + +static void disable_vsync (struct dpu_context *ctx) +{ +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} + +static const u32 primary_fmts[] = { +DRM_FORMAT_XRGB8888 ,DRM_FORMAT_XBGR8888 , +DRM_FORMAT_ARGB8888 ,DRM_FORMAT_ABGR8888 , +DRM_FORMAT_RGBA8888 ,DRM_FORMAT_BGRA8888 , +DRM_FORMAT_RGBX8888 ,DRM_FORMAT_RGB565 , +DRM_FORMAT_BGR565 ,DRM_FORMAT_NV12 , +DRM_FORMAT_NV21 ,DRM_FORMAT_NV16 , +DRM_FORMAT_NV61 ,DRM_FORMAT_YUV420 , +DRM_FORMAT_YVU420 , +}; + +static void dpu_capability (struct dpu_context *ctx, +struct dpu_capability *cap) +{ + cap->max_layers =6 ; + cap->fmts_ptr = primary_fmts; + cap->fmts_cnt =ARRAY_SIZE (primary_fmts); +} + +const struct dpu_core_ops dpu_r2p0_core_ops = { + .init = dpu_init, + .fini = dpu_fini, + .run = dpu_run, + .stop = dpu_stop, + .isr = dpu_isr, + .ifconfig = dpu_dpi_init, + .capability = dpu_capability, + .flip = dpu_flip, + .enable_vsync = enable_vsync, + .disable_vsync = disable_vsync, +};drivers/gpu/drm/sprd/sprd_dpu.c new file +646
-0@@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/component.h> +#include <linux/dma-buf.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_plane_helper.h> + +#include "sprd_drm.h" +#include "sprd_dpu.h" + +struct sprd_plane { +struct drm_plane plane; +u32 index; +u32 addr[4 ]; +u32 pitch[4 ]; +u32 format; +u32 rotation; +u32 blend_mode; +}; + +static void sprd_dpu_init (struct sprd_dpu *dpu); +static void sprd_dpu_fini (struct sprd_dpu *dpu); + +static inline struct sprd_plane *to_sprd_plane (struct drm_plane *plane) +{ + return container_of(plane, struct sprd_plane, plane); +} + +static int sprd_plane_format_convert (u32 fourcc,u32 *format) +{ +switch (fourcc) { +case DRM_FORMAT_BGRA8888 : +/* BGRA8888 -> ARGB8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_RGBX8888 : +case DRM_FORMAT_RGBA8888 : +/* RGBA8888 -> ABGR8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* FALLTHRU */ +case DRM_FORMAT_ABGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_ARGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_XBGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_XRGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_BGR565 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_RGB565 : + *format |=BIT_DPU_LAY_FORMAT_RGB565 ; +break ; +case DRM_FORMAT_NV12 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_NV21 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV16 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV61 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YUV420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YVU420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_rotation_convert (u32 angle,u32 *rotation) +{ +switch (angle) { +case DRM_MODE_ROTATE_0 : + *rotation =DPU_LAYER_ROTATION_0 ; +break ; +case DRM_MODE_ROTATE_90 : + *rotation =DPU_LAYER_ROTATION_90 ; +break ; +case DRM_MODE_ROTATE_180 : + *rotation =DPU_LAYER_ROTATION_180 ; +break ; +case DRM_MODE_ROTATE_270 : + *rotation =DPU_LAYER_ROTATION_270 ; +break ; +case DRM_MODE_REFLECT_Y : + *rotation =DPU_LAYER_ROTATION_180_M ; +break ; +case (DRM_MODE_REFLECT_Y |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_90_M ; +break ; +case DRM_MODE_REFLECT_X : + *rotation =DPU_LAYER_ROTATION_0_M ; +break ; +case (DRM_MODE_REFLECT_X |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_270_M ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_atomic_check (struct drm_plane *plane, +struct drm_plane_state *state) +{ +struct sprd_plane *p =to_sprd_plane (plane); +struct drm_framebuffer *fb = state->fb; +struct drm_gem_cma_object *cma_obj; +int i, ret; +u32 addr; + +if (!state->fb || !state->crtc) +return 0 ; + + ret =sprd_plane_format_convert (fb->format->format, + &p->format); +if (ret <0 ) { +DRM_ERROR ("Invalid plane format\n" ); +return ret; + } + + ret =sprd_plane_rotation_convert (state->rotation, + &p->rotation); +if (ret <0 ) { +DRM_ERROR ("Invalid plane rotation\n" ); +return ret; + } + +switch (state->pixel_blend_mode) { +case DRM_MODE_BLEND_COVERAGE : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Normal mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_NORMAL ; +break ; +case DRM_MODE_BLEND_PREMULTI : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Pre-mult mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_PREMULT ; +break ; +case DRM_MODE_BLEND_PIXEL_NONE : +default : +/* don't do blending, maybe RGBX */ +/* alpha mode select - layer alpha */ + p->blend_mode |=BIT_DPU_LAY_LAYER_ALPHA ; +break ; + } + +for (i =0 ; i < fb->format->num_planes; i++) { + cma_obj =drm_fb_cma_get_gem_obj (fb, i); + addr = cma_obj->paddr + fb->offsets[i]; +if (addr %16 ) { +DRM_ERROR ("layer addr[%d] is not 16 bytes align, it's 0x%08x\n" , + i, addr); +return -EFAULT ; + } + + p->addr[i] = addr; + p->pitch[i] = fb->pitches[i]; + } + +return 0 ; +} + +static void sprd_plane_atomic_update (struct drm_plane *plane, +struct drm_plane_state *old_state) +{ +struct drm_plane_state *state = plane->state; +struct drm_framebuffer *fb = plane->state->fb; +struct sprd_plane *p =to_sprd_plane (plane); +struct sprd_dpu *dpu =crtc_to_dpu (plane->state->crtc); +struct dpu_layer *layer = &dpu->layers[p->index]; +int i; + +if (!state->crtc || !state->fb) +return ; + + layer->index = p->index; + layer->src_x = state->src_x >>16 ; + layer->src_y = state->src_y >>16 ; + layer->src_w = state->src_w >>16 ; + layer->src_h = state->src_h >>16 ; + layer->dst_x = state->crtc_x; + layer->dst_y = state->crtc_y; + layer->dst_w = state->crtc_w; + layer->dst_h = state->crtc_h; + layer->alpha = state->alpha; + layer->format = p->format; + layer->blending = p->blend_mode; + layer->rotation = p->rotation; + layer->planes = fb->format->num_planes; + +for (i =0 ; i < layer->planes; i++) { + layer->addr[i] = p->addr[i]; + layer->pitch[i] = p->pitch[i]; + } + + dpu->pending_planes++; +} + +static void sprd_plane_create_properties (struct sprd_plane *p,int index) +{ +unsigned int supported_modes =BIT (DRM_MODE_BLEND_PIXEL_NONE ) | +BIT (DRM_MODE_BLEND_PREMULTI ) | +BIT (DRM_MODE_BLEND_COVERAGE ); + +/* create rotation property */ +drm_plane_create_rotation_property (&p->plane, +DRM_MODE_ROTATE_0 , +DRM_MODE_ROTATE_MASK | +DRM_MODE_REFLECT_MASK ); + +/* create alpha property */ +drm_plane_create_alpha_property (&p->plane); + +/* create blend mode property */ +drm_plane_create_blend_mode_property (&p->plane, supported_modes); + +/* create zpos property */ +drm_plane_create_zpos_immutable_property (&p->plane, index); +} + +static const struct drm_plane_helper_funcs sprd_plane_helper_funcs = { + .atomic_check = sprd_plane_atomic_check, + .atomic_update = sprd_plane_atomic_update, +}; + +static const struct drm_plane_funcs sprd_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static struct drm_plane *sprd_plane_init (struct drm_device *drm, +struct sprd_dpu *dpu) +{ +struct drm_plane *primary =NULL ; +struct sprd_plane *p =NULL ; +struct dpu_capability cap = {}; +int ret, i; + + dpu->core->capability (&dpu->ctx, &cap); + + dpu->layers =devm_kcalloc (drm->dev, cap.max_layers, +sizeof (struct dpu_layer ),GFP_KERNEL ); +if (!dpu->layers) +return ERR_PTR (-ENOMEM ); + +for (i =0 ; i < cap.max_layers; i++) { + + p =devm_kzalloc (drm->dev,sizeof (*p),GFP_KERNEL ); +if (!p) +return ERR_PTR (-ENOMEM ); + + ret =drm_universal_plane_init (drm, &p->plane,1 , + &sprd_plane_funcs, cap.fmts_ptr, + cap.fmts_cnt,NULL , +DRM_PLANE_TYPE_PRIMARY ,NULL ); +if (ret) { +DRM_ERROR ("fail to init primary plane\n" ); +return ERR_PTR (ret); + } + +drm_plane_helper_add (&p->plane, &sprd_plane_helper_funcs); + +sprd_plane_create_properties (p, i); + + p->index = i; +if (i ==0 ) + primary = &p->plane; + } + +return primary; +} + +static enum drm_mode_status sprd_crtc_mode_valid (struct drm_crtc *crtc, +const struct drm_display_mode *mode) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +DRM_DEBUG ("%s() mode: " DRM_MODE_FMT "\n" , __func__,DRM_MODE_ARG (mode)); + +if (mode->type &DRM_MODE_TYPE_PREFERRED ) { +drm_display_mode_to_videomode (mode, &dpu->ctx.vm); + +if ((mode->hdisplay == mode->htotal) || + (mode->vdisplay == mode->vtotal)) + dpu->ctx.if_type =SPRD_DPU_IF_EDPI ; +else + dpu->ctx.if_type =SPRD_DPU_IF_DPI ; + } + +return MODE_OK ; +} + +static void sprd_crtc_atomic_enable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +sprd_dpu_init (dpu); + +enable_irq (dpu->ctx.irq); +} + +static void sprd_crtc_atomic_disable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +disable_irq (dpu->ctx.irq); + +sprd_dpu_fini (dpu); + +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_atomic_check (struct drm_crtc *crtc, +struct drm_crtc_state *state) +{ +DRM_DEBUG ("%s()\n" , __func__); + +return 0 ; +} + +static void sprd_crtc_atomic_begin (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +memset (dpu->layers,0 ,sizeof (*dpu->layers) * dpu->pending_planes); + + dpu->pending_planes =0 ; +} + +static void sprd_crtc_atomic_flush (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) + +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +if (dpu->pending_planes) + dpu->core->flip (&dpu->ctx, dpu->layers, dpu->pending_planes); + +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_enable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->enable_vsync (&dpu->ctx); + +return 0 ; +} + +static void sprd_crtc_disable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->disable_vsync (&dpu->ctx); +} + +static const struct drm_crtc_helper_funcs sprd_crtc_helper_funcs = { + .mode_valid = sprd_crtc_mode_valid, + .atomic_check = sprd_crtc_atomic_check, + .atomic_begin = sprd_crtc_atomic_begin, + .atomic_flush = sprd_crtc_atomic_flush, + .atomic_enable = sprd_crtc_atomic_enable, + .atomic_disable = sprd_crtc_atomic_disable, +}; + +static const struct drm_crtc_funcs sprd_crtc_funcs = { + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = sprd_crtc_enable_vblank, + .disable_vblank = sprd_crtc_disable_vblank, +}; + +static int sprd_crtc_init (struct drm_device *drm,struct drm_crtc *crtc, +struct drm_plane *primary) +{ +struct device_node *port; +int ret; + +/* +* set crtc port so that drm_of_find_possible_crtcs call works +*/ + port =of_parse_phandle (drm->dev->of_node,"ports" ,0 ); +if (!port) { +DRM_ERROR ("find 'ports' phandle of %s failed\n" , + drm->dev->of_node->full_name); +return -EINVAL ; + } +of_node_put (port); + crtc->port = port; + + ret =drm_crtc_init_with_planes (drm, crtc, primary,NULL , + &sprd_crtc_funcs,NULL ); +if (ret) { +DRM_ERROR ("failed to init crtc.\n" ); +return ret; + } + +drm_mode_crtc_set_gamma_size (crtc,256 ); + +drm_crtc_helper_add (crtc, &sprd_crtc_helper_funcs); + +return 0 ; +} + +static void sprd_dpu_init (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->init (ctx); + dpu->core->ifconfig (ctx); +} + +static void sprd_dpu_fini (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->fini (ctx); +} + +static irqreturn_t sprd_dpu_isr (int irq,void *data) +{ +struct sprd_dpu *dpu = data; +struct dpu_context *ctx = &dpu->ctx; +u32 int_mask =0 ; + + int_mask = dpu->core->isr (ctx); + +if (int_mask &BIT_DPU_INT_ERR ) +DRM_WARN ("Warning: dpu underflow!\n" ); + +if (int_mask &BIT_DPU_INT_VSYNC ) +drm_crtc_handle_vblank (&dpu->crtc); + +return IRQ_HANDLED ; +} + +static int sprd_dpu_bind (struct device *dev,struct device *master,void *data) +{ +struct drm_device *drm = data; +struct sprd_dpu *dpu =dev_get_drvdata (dev); +struct drm_plane *plane; +int ret; + + plane =sprd_plane_init (drm, dpu); +if (IS_ERR_OR_NULL (plane)) { + ret =PTR_ERR (plane); +return ret; + } + + ret =sprd_crtc_init (drm, &dpu->crtc, plane); +if (ret) +return ret; + +return 0 ; +} + +static void sprd_dpu_unbind (struct device *dev,struct device *master, +void *data) +{ +struct sprd_dpu *dpu =dev_get_drvdata (dev); + +drm_crtc_cleanup (&dpu->crtc); +} + +static const struct component_ops dpu_component_ops = { + .bind = sprd_dpu_bind, + .unbind = sprd_dpu_unbind, +}; + +static int sprd_dpu_context_init (struct sprd_dpu *dpu, +struct device *dev) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dpu_context *ctx = &dpu->ctx; +struct resource *res; +int ret; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + ctx->base =devm_ioremap (dev, res->start,resource_size (res)); +if (!ctx->base) { +DRM_ERROR ("failed to map dpu registers\n" ); +return -EFAULT ; + } + + ctx->irq =platform_get_irq (pdev,0 ); +if (ctx->irq <0 ) { +DRM_ERROR ("failed to get dpu irq\n" ); +return ctx->irq; + } + +irq_set_status_flags (ctx->irq,IRQ_NOAUTOEN ); + ret =devm_request_irq (dev, ctx->irq, sprd_dpu_isr, +0 ,"DPU" , dpu); +if (ret) { +DRM_ERROR ("failed to register dpu irq handler\n" ); +return ret; + } + +init_waitqueue_head (&ctx->wait_queue); + +return 0 ; +} + +static const struct sprd_dpu_ops sharkl3_dpu = { + .core = &dpu_r2p0_core_ops, +}; + +static const struct of_device_id dpu_match_table[] = { + { .compatible ="sprd,sharkl3-dpu" , + .data = &sharkl3_dpu }, + {/* sentinel */ }, +}; + +static int sprd_dpu_probe (struct platform_device *pdev) +{ +const struct sprd_dpu_ops *pdata; +struct sprd_dpu *dpu; +int ret; + + dpu =devm_kzalloc (&pdev->dev,sizeof (*dpu),GFP_KERNEL ); +if (!dpu) +return -ENOMEM ; + + pdata =of_device_get_match_data (&pdev->dev); +if (pdata) { + dpu->core = pdata->core; + }else { +DRM_ERROR ("No matching driver data found\n" ); +return -EINVAL ; + } + + ret =sprd_dpu_context_init (dpu, &pdev->dev); +if (ret) +return ret; + +platform_set_drvdata (pdev, dpu); + +return component_add (&pdev->dev, &dpu_component_ops); +} + +static int sprd_dpu_remove (struct platform_device *pdev) +{ +component_del (&pdev->dev, &dpu_component_ops); +return 0 ; +} + +struct platform_driver sprd_dpu_driver = { + .probe = sprd_dpu_probe, + .remove = sprd_dpu_remove, + .driver = { + .name ="sprd-dpu-drv" , + .of_match_table = dpu_match_table, + }, +}; + +MODULE_AUTHOR ("Leon He <[email protected]>" ); +MODULE_AUTHOR ("Kevin Tang <[email protected]>" ); +MODULE_DESCRIPTION ("Unisoc Display Controller Driver" ); +MODULE_LICENSE ("GPL v2" );drivers/gpu/drm/sprd/sprd_dpu.h new file +187
-0@@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#ifndef __SPRD_DPU_H__ +#define __SPRD_DPU_H__ + +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <video/videomode.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_print.h> +#include <drm/drm_vblank.h> +#include <uapi/drm/drm_mode.h> + +#define BIT_DPU_INT_DONE_ BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_EDPI_TE BIT(3) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_WB_DONE BIT(6) +#define BIT_DPU_INT_WB_ERR BIT(7) + +#define BIT_DPU_LAY_LAYER_ALPHA (0x01 << 2) +#define BIT_DPU_LAY_COMBO_ALPHA (0x02 << 2) +#define BIT_DPU_LAY_FORMAT_YUV422_2PLANE (0x00 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_2PLANE (0x01 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_3PLANE (0x02 << 4) +#define BIT_DPU_LAY_FORMAT_ARGB8888 (0x03 << 4) +#define BIT_DPU_LAY_FORMAT_RGB565 (0x04 << 4) +#define BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 (0x00 << 8) +#define BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 (0x01 << 8) +#define BIT_DPU_LAY_NO_SWITCH (0x00 << 10) +#define BIT_DPU_LAY_RB_OR_UV_SWITCH (0x01 << 10) +#define BIT_DPU_LAY_MODE_BLEND_NORMAL (0x00 << 16) +#define BIT_DPU_LAY_MODE_BLEND_PREMULT (0x01 << 16) + +enum { +SPRD_DPU_IF_DBI =0 , +SPRD_DPU_IF_DPI , +SPRD_DPU_IF_EDPI , +SPRD_DPU_IF_LIMIT +}; + +enum { +DPU_LAYER_ROTATION_0 , +DPU_LAYER_ROTATION_90 , +DPU_LAYER_ROTATION_180 , +DPU_LAYER_ROTATION_270 , +DPU_LAYER_ROTATION_0_M , +DPU_LAYER_ROTATION_90_M , +DPU_LAYER_ROTATION_180_M , +DPU_LAYER_ROTATION_270_M , +}; + +struct dpu_layer { +u8 index; +u8 planes; +u32 addr[4 ]; +u32 pitch[4 ]; +s16 src_x; +s16 src_y; +s16 src_w; +s16 src_h; +s16 dst_x; +s16 dst_y; +u16 dst_w; +u16 dst_h; +u32 format; +u32 alpha; +u32 blending; +u32 rotation; +}; + +/** +* Sprd DPU capability structure +* +* @max_layers: maximum number of layers available +* @fmts_ptr: A pointer to array of supported pixel formats +* @fmts_cnt: the number of format on @fmts_ptr +*/ +struct dpu_capability { +u32 max_layers; +const u32 *fmts_ptr; +u32 fmts_cnt; +}; + +/** +* Sprd DPU core callback ops +* +* This structure decribes the display controller common +* callback ops +* +* @init: initial DPU core +* @fini: cleanup DPU core +* @run: enable DPU output +* @stop: disable DPU output +* @enable_vsync: enable vblank interrupt +* @disable_vsync: disable vblank interrupt +* @isr: function pointer to the isr +* @ifconfig: initial DPI interface +* @flip: commit CRTC planes to DPU +* @capability: callback for DPU capabilities +*/ +struct dpu_context ; +struct dpu_core_ops { +void (*init)(struct dpu_context *ctx); +void (*fini)(struct dpu_context *ctx); +void (*run)(struct dpu_context *ctx); +void (*stop)(struct dpu_context *ctx); +void (*enable_vsync)(struct dpu_context *ctx); +void (*disable_vsync)(struct dpu_context *ctx); +u32 (*isr)(struct dpu_context *ctx); +void (*ifconfig)(struct dpu_context *ctx); +void (*flip)(struct dpu_context *ctx, +struct dpu_layer layers[],u8 count); +void (*capability)(struct dpu_context *ctx, +struct dpu_capability *cap); +}; + +/** +* Sprd DPU context structure +* +* @base: DPU controller base address +* @irq: IRQ number to install the handler for +* @if_type: The type of DPI interface, default is DPI mode. +* @vm: videomode structure to use for DPU and DPI initialization +* @stopped: indicates whether DPU are stopped +* @wait_queue: wait queue, used to wait for DPU shadow register update done and +* DPU stop register done interrupt signal. +* @evt_update: wait queue condition for DPU shadow register +* @evt_stop: wait queue condition for DPU stop register +*/ +struct dpu_context { +void __iomem *base; +int irq; +u8 if_type; +struct videomode vm; +bool stopped; +wait_queue_head_t wait_queue; +bool evt_update; +bool evt_stop; +}; + +/** +* Sprd DPU device structure +* +* @crtc: DRM crtc +* @ctx: A pointer to the DPU's implementation specific context +* @core: pointer to callbacks for DPU core functionality +* @layers: active DPU layers ready to commit +* @pending_planes: the number of layers on @layers +*/ +struct sprd_dpu { +struct drm_crtc crtc; +struct dpu_context ctx; +const struct dpu_core_ops *core; +struct dpu_layer *layers; +u8 pending_planes; +}; + +/** +* Sprd DPU H/W callback ops match table structure +* The structure used for matching a specific device callback ops +* +* @core: pointer to callbacks for DPU core functionality +*/ +struct sprd_dpu_ops { +const struct dpu_core_ops *core; +}; + +static inline struct sprd_dpu *crtc_to_dpu (struct drm_crtc *crtc) +{ + return crtc ? container_of(crtc, struct sprd_dpu, crtc) : NULL; +} + +extern const struct dpu_core_ops dpu_r2p0_core_ops; + +#endif drivers/gpu/drm/sprd/sprd_drm.c +1
-0@@ -200,6 +200,7 @@ static struct platform_driver sprd_drm_driver = {static struct platform_driver *sprd_drm_drivers[] = { &sprd_drm_driver, + &sprd_dpu_driver, };static int __init sprd_drm_init (void )drivers/gpu/drm/sprd/sprd_drm.h +2
-1@@ -13,4 +13,6 @@ struct sprd_drm { struct drm_device *drm; }; +extern struct platform_driver sprd_dpu_driver; +#endif /* _SPRD_DRM_H_ */ --2.7.4
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH RFC v6 4/6] drm/sprd: add Unisoc's drm display controller driver
Quoted 17 lines · Daniel Vetter <[email protected]> 于2020年7月29日周三 上午5:51写道:
Quoted 6 lines · Kevin Tang
From: Kevin Tang <[email protected]>
Adds DPU(Display Processor Unit) support for the Unisoc's display subsystem. It's support multi planes, scaler, rotation, PQ(Picture Quality) and more.
Quoted 8 lines
RFC v6:
- Access registers via readl/writel
- Checking for unsupported KMS properties (format, rotation,blend_mode, etc) onplane_checkops
- Remove always true checks for dpu core opsCc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>
Quoted 8 lines
Quickly scrolled through this, and the entire thing very much leaves a midlayer heavy aftertaste. Do we really need stuff like struct
dpu_layerand structdpu_core_ops? They only seem to complicate the code base, and seem to have no real reason. The indirection with first computing register values into a sprd_plane/crtc structure, and then writing it into hardware is also a bit much - I recommend to only do that if you have to compute values in_checkto validate them, so that the computation doesn't have to be repeated in the commit phase functions.
Hi daniel,
Maybe some DPU's IP verison, there will be some differences in the DPU on each Soc. Not only control registers, there will be some differences in control logic and functions
If access H/W registers all put into crtc or plane driver, how did others deal with it? Add Soc's macro?
When there are too many H/W IPs, split into different files(dpu_core_ops) according to different IP, I think the code project will be more convenient to keeping.
For multiple H/W IP, the popular design method is?
Quoted 6 lines
Also, the layer and
pending_flipsstuff insprd_dpudon't work with atomic, that races. You have to put all that stuff into state objects, or if it's some data shared with interrupt handlers (doesn't seem to be the case here), it needs its own locking, and any data you need in the interrupt handler must be copied over.
the layer and pending_flips, we put into atomic_flush, We do have some features related to interrupt handlers, but it has not been submitted yet. So pending_flips lock have not been added.
Quoted 1,431 lines
Also no
devm_kzallocfor anything containined a drm_* structure, that's the wrong lifetime.So yeah high level review is that I think this driver would benefit a lot from a pile of demidlayer.
Cheers, Daniel
Quoted 1,414 lines
--- drivers/gpu/drm/sprd/Makefile | 5 +- drivers/gpu/drm/sprd/dpu/Makefile | 3 + drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 503 ++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.c | 646 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.h | 187 +++++++++++ drivers/gpu/drm/sprd/sprd_drm.c | 1 + drivers/gpu/drm/sprd/sprd_drm.h | 2 + 7 files changed, 1346 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.hdrivers/gpu/drm/sprd/Makefile +4
-1@@ -2,4 +2,7 @@ subdir-ccflags-y += -I$(srctree)/$(src) -obj-y := sprd_drm.o +obj-y := sprd_drm.o \ + sprd_dpu.o + +obj-y += dpu/drivers/gpu/drm/sprd/dpu/Makefile new file +3
-0@@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += dpu_r2p0.odrivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +503
-0@@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/workqueue.h> + +#include "sprd_dpu.h" + +/* DPU registers size, 4 Bytes(32 Bits) */ +#define DPU_REG_SIZE 0x04 + +/* Layer registers offset */ +#define DPU_LAY_REG_OFFSET 0x0C + +#define DPU_LAY_REG (reg, index) \ + (reg + index * DPU_LAY_REG_OFFSET * DPU_REG_SIZE) + +#define DPU_REG_RD (reg) readl_relaxed(reg) + +#define DPU_REG_WR (reg, mask) writel_relaxed(mask, reg) + +#define DPU_REG_SET (reg, mask) \ + writel_relaxed(readl_relaxed(reg) | mask, reg) + +#define DPU_REG_CLR (reg, mask) \ + writel_relaxed(readl_relaxed(reg) & ~mask, reg) + +/* Global control registers */ +#define REG_DPU_CTRL 0x04 +#define REG_DPU_CFG0 0x08 +#define REG_DPU_CFG1 0x0C +#define REG_DPU_CFG2 0x10 +#define REG_PANEL_SIZE 0x20 +#define REG_BLEND_SIZE 0x24 +#define REG_BG_COLOR 0x2C + +/* Layer0 control registers */ +#define REG_LAY_BASE_ADDR0 0x30 +#define REG_LAY_BASE_ADDR1 0x34 +#define REG_LAY_BASE_ADDR2 0x38 +#define REG_LAY_CTRL 0x40 +#define REG_LAY_SIZE 0x44 +#define REG_LAY_PITCH 0x48 +#define REG_LAY_POS 0x4C +#define REG_LAY_ALPHA 0x50 +#define REG_LAY_PALLETE 0x58 +#define REG_LAY_CROP_START 0x5C + +/* Interrupt control registers */ +#define REG_DPU_INT_EN 0x1E0 +#define REG_DPU_INT_CLR 0x1E4 +#define REG_DPU_INT_STS 0x1E8 + +/* DPI control registers */ +#define REG_DPI_CTRL 0x1F0 +#define REG_DPI_H_TIMING 0x1F4 +#define REG_DPI_V_TIMING 0x1F8 + +/* MMU control registers */ +#define REG_MMU_EN 0x800 +#define REG_MMU_VPN_RANGE 0x80C +#define REG_MMU_VAOR_ADDR_RD 0x818 +#define REG_MMU_VAOR_ADDR_WR 0x81C +#define REG_MMU_INV_ADDR_RD 0x820 +#define REG_MMU_INV_ADDR_WR 0x824 +#define REG_MMU_PPN1 0x83C +#define REG_MMU_RANGE1 0x840 +#define REG_MMU_PPN2 0x844 +#define REG_MMU_RANGE2 0x848 + +/* Global control bits */ +#define BIT_DPU_RUN BIT(0) +#define BIT_DPU_STOP BIT(1) +#define BIT_DPU_REG_UPDATE BIT(2) +#define BIT_DPU_IF_EDPI BIT(0) +#define BIT_DPU_COEF_NARROW_RANGE BIT(4) +#define BIT_DPU_Y2R_COEF_ITU709_STANDARD BIT(5) + +/* Layer control bits */ +#define BIT_DPU_LAY_EN BIT(0) + +/* Interrupt control & status bits */ +#define BIT_DPU_INT_DONE BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_FBC_PLD_ERR BIT(8) +#define BIT_DPU_INT_FBC_HDR_ERR BIT(9) +#define BIT_DPU_INT_MMU_VAOR_RD BIT(16) +#define BIT_DPU_INT_MMU_VAOR_WR BIT(17) +#define BIT_DPU_INT_MMU_INV_RD BIT(18) +#define BIT_DPU_INT_MMU_INV_WR BIT(19) + +/* DPI control bits */ +#define BIT_DPU_EDPI_TE_EN BIT(8) +#define BIT_DPU_EDPI_FROM_EXTERNAL_PAD BIT(10) +#define BIT_DPU_DPI_HALT_EN BIT(16) + + +static u32 check_mmu_isr (struct dpu_context *ctx,u32 reg_val) +{ +u32 mmu_mask =BIT_DPU_INT_MMU_VAOR_RD | +BIT_DPU_INT_MMU_VAOR_WR | +BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +u32 val = reg_val & mmu_mask; +int i; + +if (val) { +DRM_ERROR ("--- iommu interrupt err: 0x%04x ---\n" , val); + +if (val &BIT_DPU_INT_MMU_INV_RD ) +DRM_ERROR ("iommu invalid read error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_INV_ADDR_RD )); +if (val &BIT_DPU_INT_MMU_INV_WR ) +DRM_ERROR ("iommu invalid write error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_INV_ADDR_WR )); +if (val &BIT_DPU_INT_MMU_VAOR_RD ) +DRM_ERROR ("iommu va out of range read error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_VAOR_ADDR_RD )); +if (val &BIT_DPU_INT_MMU_VAOR_WR ) +DRM_ERROR ("iommu va out of range write error, addr: 0x%08x\n" , +DPU_REG_RD (ctx->base +REG_MMU_VAOR_ADDR_WR )); + +for (i =0 ; i <8 ; i++) { + reg_val =DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i)); +if (reg_val &0x1 ) +DRM_INFO ("layer%d: 0x%08x 0x%08x 0x%08x ctrl: 0x%08x\n" , i, +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR0 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR1 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR2 , i)), +DPU_REG_RD (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i))); + } + } + +return val; +} + +static void dpu_clean_all (struct dpu_context *ctx) +{ +int i; + +for (i =0 ; i <8 ; i++) +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , i),0x00 ); +} + +static u32 dpu_isr (struct dpu_context *ctx) +{ +u32 reg_val, int_mask =0 ; + + reg_val =DPU_REG_RD (ctx->base +REG_DPU_INT_STS ); + +/* disable err interrupt */ +if (reg_val &BIT_DPU_INT_ERR ) + int_mask |=BIT_DPU_INT_ERR ; + +/* dpu update done isr */ +if (reg_val &BIT_DPU_INT_UPDATE_DONE ) { + ctx->evt_update = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu stop done isr */ +if (reg_val &BIT_DPU_INT_DONE ) { + ctx->evt_stop = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu ifbc payload error isr */ +if (reg_val &BIT_DPU_INT_FBC_PLD_ERR ) { + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +DRM_ERROR ("dpu ifbc payload error\n" ); + } + +/* dpu ifbc header error isr */ +if (reg_val &BIT_DPU_INT_FBC_HDR_ERR ) { + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +DRM_ERROR ("dpu ifbc header error\n" ); + } + + int_mask |=check_mmu_isr (ctx, reg_val); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR , reg_val); +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN , int_mask); + +return reg_val; +} + +static int dpu_wait_stop_done (struct dpu_context *ctx) +{ +int rc; + +if (ctx->stopped) +return 0 ; + + rc =wait_event_interruptible_timeout (ctx->wait_queue, ctx->evt_stop, +msecs_to_jiffies (500 )); + ctx->evt_stop = false; + + ctx->stopped = true; + +if (!rc) { +DRM_ERROR ("dpu wait for stop done time out!\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +static int dpu_wait_update_done (struct dpu_context *ctx) +{ +int rc; + + ctx->evt_update = false; + + rc =wait_event_interruptible_timeout (ctx->wait_queue, ctx->evt_update, +msecs_to_jiffies (500 )); + +if (!rc) { +DRM_ERROR ("dpu wait for reg update done time out!\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +static void dpu_stop (struct dpu_context *ctx) +{ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_STOP ); + +dpu_wait_stop_done (ctx); +} + +static void dpu_run (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; +} + +static void dpu_init (struct dpu_context *ctx) +{ +u32 reg_val, size; + +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + + size = (ctx->vm.vactive <<16 ) | ctx->vm.hactive; + +DPU_REG_WR (ctx->base +REG_PANEL_SIZE , size); +DPU_REG_WR (ctx->base +REG_BLEND_SIZE , size); + + reg_val =BIT_DPU_COEF_NARROW_RANGE |BIT_DPU_Y2R_COEF_ITU709_STANDARD ; +DPU_REG_WR (ctx->base +REG_DPU_CFG0 , reg_val); +DPU_REG_WR (ctx->base +REG_DPU_CFG1 ,0x004466da ); +DPU_REG_WR (ctx->base +REG_DPU_CFG2 ,0x00 ); + +if (ctx->stopped) +dpu_clean_all (ctx); + +DPU_REG_WR (ctx->base +REG_MMU_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_PPN1 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE1 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_PPN2 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE2 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_VPN_RANGE ,0x1ffff ); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xffff ); +} + +static void dpu_fini (struct dpu_context *ctx) +{ +DPU_REG_WR (ctx->base +REG_DPU_INT_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xff ); +} + +static void dpu_layer (struct dpu_context *ctx, +struct dpu_layer *hwlayer) +{ +const struct drm_format_info *info; +u32 size, offset, ctrl, pitch; +int i; + + offset = (hwlayer->dst_x &0xffff ) | ((hwlayer->dst_y) <<16 ); + +if (hwlayer->src_w && hwlayer->src_h) + size = (hwlayer->src_w &0xffff ) | ((hwlayer->src_h) <<16 ); +else + size = (hwlayer->dst_w &0xffff ) | ((hwlayer->dst_h) <<16 ); + +for (i =0 ; i < hwlayer->planes; i++) +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR0 , + hwlayer->index), hwlayer->addr[i]); + +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_POS , + hwlayer->index), offset); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_SIZE , + hwlayer->index), size); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CROP_START , + hwlayer->index), hwlayer->src_y <<16 | hwlayer->src_x); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_ALPHA , + hwlayer->index), hwlayer->alpha); + + info =drm_format_info (hwlayer->format); +if (hwlayer->planes ==3 ) { +/* UV pitch is 1/2 of Y pitch*/ + pitch = (hwlayer->pitch[0 ] / info->cpp[0 ]) | + (hwlayer->pitch[0 ] / info->cpp[0 ] <<15 ); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + }else { + pitch = hwlayer->pitch[0 ] / info->cpp[0 ]; +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + } + + ctrl = hwlayer->format | + hwlayer->blending | + (hwlayer->rotation &0x7 ) <<20 ; + +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index), ctrl); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index),BIT_DPU_LAY_EN ); + +DRM_DEBUG ("dst_x = %d, dst_y = %d, dst_w = %d, dst_h = %d\n" , + hwlayer->dst_x, hwlayer->dst_y, + hwlayer->dst_w, hwlayer->dst_h); +DRM_DEBUG ("start_x = %d, start_y = %d, start_w = %d, start_h = %d\n" , + hwlayer->src_x, hwlayer->src_y, + hwlayer->src_w, hwlayer->src_h); +} + +static void dpu_flip (struct dpu_context *ctx, +struct dpu_layer layers[],u8 count) +{ +int i; +u32 reg_val; + +/* +* Make sure the dpu is in stop status. DPU_R2P0 has no shadow +* registers in EDPI mode. So the config registers can only be +* updated in the rising edge of DPU_RUN bit. +*/ +if (ctx->if_type ==SPRD_DPU_IF_EDPI ) +dpu_wait_stop_done (ctx); + +/* reset the bgcolor to black */ +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + +/* disable all the layers */ +dpu_clean_all (ctx); + +/* start configure dpu layers */ +for (i =0 ; i < count; i++) +dpu_layer (ctx, &layers[i]); + +/* update trigger and wait */ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +if (!ctx->stopped) { +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_REG_UPDATE ); +dpu_wait_update_done (ctx); + } + +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_ERR ); + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; + } + +/* +* If the following interrupt was disabled in isr, +* re-enable it. +*/ + reg_val =BIT_DPU_INT_FBC_PLD_ERR | +BIT_DPU_INT_FBC_HDR_ERR | +BIT_DPU_INT_MMU_VAOR_RD | +BIT_DPU_INT_MMU_VAOR_WR | +BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +DPU_REG_SET (ctx->base +REG_DPU_INT_EN , reg_val); + +} + +static void dpu_dpi_init (struct dpu_context *ctx) +{ +u32 int_mask =0 ; +u32 reg_val; + +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +/* use dpi as interface */ +DPU_REG_CLR (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* disable Halt function for SPRD DSI */ +DPU_REG_CLR (ctx->base +REG_DPI_CTRL ,BIT_DPU_DPI_HALT_EN ); + +/* select te from external pad */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_FROM_EXTERNAL_PAD ); + +/* set dpi timing */ + reg_val = ctx->vm.hsync_len <<0 | + ctx->vm.hback_porch <<8 | + ctx->vm.hfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_H_TIMING , reg_val); + + reg_val = ctx->vm.vsync_len <<0 | + ctx->vm.vback_porch <<8 | + ctx->vm.vfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_V_TIMING , reg_val); + +if (ctx->vm.vsync_len + ctx->vm.vback_porch <32 ) +DRM_WARN ("Warning: (vsync + vbp) < 32, " +"underflow risk!\n" ); + +/* enable dpu update done INT */ + int_mask |=BIT_DPU_INT_UPDATE_DONE ; +/* enable dpu DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable dpu dpi vsync */ + int_mask |=BIT_DPU_INT_VSYNC ; +/* enable dpu TE INT */ + int_mask |=BIT_DPU_INT_TE ; +/* enable underflow err INT */ + int_mask |=BIT_DPU_INT_ERR ; + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +/* use edpi as interface */ +DPU_REG_SET (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* use external te */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_FROM_EXTERNAL_PAD ); + +/* enable te */ +DPU_REG_SET (ctx->base +REG_DPI_CTRL ,BIT_DPU_EDPI_TE_EN ); + +/* enable stop DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable TE INT */ + int_mask |=BIT_DPU_INT_TE ; + } + +/* enable ifbc payload error INT */ + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +/* enable ifbc header error INT */ + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +/* enable iommu va out of range read error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_RD ; +/* enable iommu va out of range write error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_WR ; +/* enable iommu invalid read error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_RD ; +/* enable iommu invalid write error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_WR ; + +DPU_REG_WR (ctx->base +REG_DPU_INT_EN , int_mask); +} + +static void enable_vsync (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} + +static void disable_vsync (struct dpu_context *ctx) +{ +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} + +static const u32 primary_fmts[] = { +DRM_FORMAT_XRGB8888 ,DRM_FORMAT_XBGR8888 , +DRM_FORMAT_ARGB8888 ,DRM_FORMAT_ABGR8888 , +DRM_FORMAT_RGBA8888 ,DRM_FORMAT_BGRA8888 , +DRM_FORMAT_RGBX8888 ,DRM_FORMAT_RGB565 , +DRM_FORMAT_BGR565 ,DRM_FORMAT_NV12 , +DRM_FORMAT_NV21 ,DRM_FORMAT_NV16 , +DRM_FORMAT_NV61 ,DRM_FORMAT_YUV420 , +DRM_FORMAT_YVU420 , +}; + +static void dpu_capability (struct dpu_context *ctx, +struct dpu_capability *cap) +{ + cap->max_layers =6 ; + cap->fmts_ptr = primary_fmts; + cap->fmts_cnt =ARRAY_SIZE (primary_fmts); +} + +const struct dpu_core_ops dpu_r2p0_core_ops = { + .init = dpu_init, + .fini = dpu_fini, + .run = dpu_run, + .stop = dpu_stop, + .isr = dpu_isr, + .ifconfig = dpu_dpi_init, + .capability = dpu_capability, + .flip = dpu_flip, + .enable_vsync = enable_vsync, + .disable_vsync = disable_vsync, +};drivers/gpu/drm/sprd/sprd_dpu.c new file +646
-0@@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/component.h> +#include <linux/dma-buf.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_plane_helper.h> + +#include "sprd_drm.h" +#include "sprd_dpu.h" + +struct sprd_plane { +struct drm_plane plane; +u32 index; +u32 addr[4 ]; +u32 pitch[4 ]; +u32 format; +u32 rotation; +u32 blend_mode; +}; + +static void sprd_dpu_init (struct sprd_dpu *dpu); +static void sprd_dpu_fini (struct sprd_dpu *dpu); + +static inline struct sprd_plane *to_sprd_plane (struct drm_plane *plane) +{ + return container_of(plane, struct sprd_plane, plane); +} + +static int sprd_plane_format_convert (u32 fourcc,u32 *format) +{ +switch (fourcc) { +case DRM_FORMAT_BGRA8888 : +/* BGRA8888 -> ARGB8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_RGBX8888 : +case DRM_FORMAT_RGBA8888 : +/* RGBA8888 -> ABGR8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* FALLTHRU */ +case DRM_FORMAT_ABGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_ARGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_XBGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_XRGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_BGR565 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_RGB565 : + *format |=BIT_DPU_LAY_FORMAT_RGB565 ; +break ; +case DRM_FORMAT_NV12 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_NV21 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV16 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV61 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YUV420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YVU420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_rotation_convert (u32 angle,u32 *rotation) +{ +switch (angle) { +case DRM_MODE_ROTATE_0 : + *rotation =DPU_LAYER_ROTATION_0 ; +break ; +case DRM_MODE_ROTATE_90 : + *rotation =DPU_LAYER_ROTATION_90 ; +break ; +case DRM_MODE_ROTATE_180 : + *rotation =DPU_LAYER_ROTATION_180 ; +break ; +case DRM_MODE_ROTATE_270 : + *rotation =DPU_LAYER_ROTATION_270 ; +break ; +case DRM_MODE_REFLECT_Y : + *rotation =DPU_LAYER_ROTATION_180_M ; +break ; +case (DRM_MODE_REFLECT_Y |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_90_M ; +break ; +case DRM_MODE_REFLECT_X : + *rotation =DPU_LAYER_ROTATION_0_M ; +break ; +case (DRM_MODE_REFLECT_X |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_270_M ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_atomic_check (struct drm_plane *plane, +struct drm_plane_state *state) +{ +struct sprd_plane *p =to_sprd_plane (plane); +struct drm_framebuffer *fb = state->fb; +struct drm_gem_cma_object *cma_obj; +int i, ret; +u32 addr; + +if (!state->fb || !state->crtc) +return 0 ; + + ret =sprd_plane_format_convert (fb->format->format, + &p->format); +if (ret <0 ) { +DRM_ERROR ("Invalid plane format\n" ); +return ret; + } + + ret =sprd_plane_rotation_convert (state->rotation, + &p->rotation); +if (ret <0 ) { +DRM_ERROR ("Invalid plane rotation\n" ); +return ret; + } + +switch (state->pixel_blend_mode) { +case DRM_MODE_BLEND_COVERAGE : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Normal mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_NORMAL ; +break ; +case DRM_MODE_BLEND_PREMULTI : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Pre-mult mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_PREMULT ; +break ; +case DRM_MODE_BLEND_PIXEL_NONE : +default : +/* don't do blending, maybe RGBX */ +/* alpha mode select - layer alpha */ + p->blend_mode |=BIT_DPU_LAY_LAYER_ALPHA ; +break ; + } + +for (i =0 ; i < fb->format->num_planes; i++) { + cma_obj =drm_fb_cma_get_gem_obj (fb, i); + addr = cma_obj->paddr + fb->offsets[i]; +if (addr %16 ) { +DRM_ERROR ("layer addr[%d] is not 16 bytes align, it's 0x%08x\n" , + i, addr); +return -EFAULT ; + } + + p->addr[i] = addr; + p->pitch[i] = fb->pitches[i]; + } + +return 0 ; +} + +static void sprd_plane_atomic_update (struct drm_plane *plane, +struct drm_plane_state *old_state) +{ +struct drm_plane_state *state = plane->state; +struct drm_framebuffer *fb = plane->state->fb; +struct sprd_plane *p =to_sprd_plane (plane); +struct sprd_dpu *dpu =crtc_to_dpu (plane->state->crtc); +struct dpu_layer *layer = &dpu->layers[p->index]; +int i; + +if (!state->crtc || !state->fb) +return ; + + layer->index = p->index; + layer->src_x = state->src_x >>16 ; + layer->src_y = state->src_y >>16 ; + layer->src_w = state->src_w >>16 ; + layer->src_h = state->src_h >>16 ; + layer->dst_x = state->crtc_x; + layer->dst_y = state->crtc_y; + layer->dst_w = state->crtc_w; + layer->dst_h = state->crtc_h; + layer->alpha = state->alpha; + layer->format = p->format; + layer->blending = p->blend_mode; + layer->rotation = p->rotation; + layer->planes = fb->format->num_planes; + +for (i =0 ; i < layer->planes; i++) { + layer->addr[i] = p->addr[i]; + layer->pitch[i] = p->pitch[i]; + } + + dpu->pending_planes++; +} + +static void sprd_plane_create_properties (struct sprd_plane *p,int index) +{ +unsigned int supported_modes =BIT (DRM_MODE_BLEND_PIXEL_NONE ) | +BIT (DRM_MODE_BLEND_PREMULTI ) | +BIT (DRM_MODE_BLEND_COVERAGE ); + +/* create rotation property */ +drm_plane_create_rotation_property (&p->plane, +DRM_MODE_ROTATE_0 , +DRM_MODE_ROTATE_MASK | +DRM_MODE_REFLECT_MASK ); + +/* create alpha property */ +drm_plane_create_alpha_property (&p->plane); + +/* create blend mode property */ +drm_plane_create_blend_mode_property (&p->plane, supported_modes); + +/* create zpos property */ +drm_plane_create_zpos_immutable_property (&p->plane, index); +} + +static const struct drm_plane_helper_funcs sprd_plane_helper_funcs = { + .atomic_check = sprd_plane_atomic_check, + .atomic_update = sprd_plane_atomic_update, +}; + +static const struct drm_plane_funcs sprd_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static struct drm_plane *sprd_plane_init (struct drm_device *drm, +struct sprd_dpu *dpu) +{ +struct drm_plane *primary =NULL ; +struct sprd_plane *p =NULL ; +struct dpu_capability cap = {}; +int ret, i; + + dpu->core->capability (&dpu->ctx, &cap); + + dpu->layers =devm_kcalloc (drm->dev, cap.max_layers, +sizeof (struct dpu_layer ),GFP_KERNEL ); +if (!dpu->layers) +return ERR_PTR (-ENOMEM ); + +for (i =0 ; i < cap.max_layers; i++) { + + p =devm_kzalloc (drm->dev,sizeof (*p),GFP_KERNEL ); +if (!p) +return ERR_PTR (-ENOMEM ); + + ret =drm_universal_plane_init (drm, &p->plane,1 , + &sprd_plane_funcs, cap.fmts_ptr, + cap.fmts_cnt,NULL , +DRM_PLANE_TYPE_PRIMARY ,NULL ); +if (ret) { +DRM_ERROR ("fail to init primary plane\n" ); +return ERR_PTR (ret); + } + +drm_plane_helper_add (&p->plane, &sprd_plane_helper_funcs); + +sprd_plane_create_properties (p, i); + + p->index = i; +if (i ==0 ) + primary = &p->plane; + } + +return primary; +} + +static enum drm_mode_status sprd_crtc_mode_valid (struct drm_crtc *crtc, +const struct drm_display_mode *mode) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +DRM_DEBUG ("%s() mode: " DRM_MODE_FMT "\n" , __func__,DRM_MODE_ARG (mode)); + +if (mode->type &DRM_MODE_TYPE_PREFERRED ) { +drm_display_mode_to_videomode (mode, &dpu->ctx.vm); + +if ((mode->hdisplay == mode->htotal) || + (mode->vdisplay == mode->vtotal)) + dpu->ctx.if_type =SPRD_DPU_IF_EDPI ; +else + dpu->ctx.if_type =SPRD_DPU_IF_DPI ; + } + +return MODE_OK ; +} + +static void sprd_crtc_atomic_enable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +sprd_dpu_init (dpu); + +enable_irq (dpu->ctx.irq); +} + +static void sprd_crtc_atomic_disable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +disable_irq (dpu->ctx.irq); + +sprd_dpu_fini (dpu); + +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_atomic_check (struct drm_crtc *crtc, +struct drm_crtc_state *state) +{ +DRM_DEBUG ("%s()\n" , __func__); + +return 0 ; +} + +static void sprd_crtc_atomic_begin (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +memset (dpu->layers,0 ,sizeof (*dpu->layers) * dpu->pending_planes); + + dpu->pending_planes =0 ; +} + +static void sprd_crtc_atomic_flush (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) + +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +if (dpu->pending_planes) + dpu->core->flip (&dpu->ctx, dpu->layers, dpu->pending_planes); + +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_enable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->enable_vsync (&dpu->ctx); + +return 0 ; +} + +static void sprd_crtc_disable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->disable_vsync (&dpu->ctx); +} + +static const struct drm_crtc_helper_funcs sprd_crtc_helper_funcs = { + .mode_valid = sprd_crtc_mode_valid, + .atomic_check = sprd_crtc_atomic_check, + .atomic_begin = sprd_crtc_atomic_begin, + .atomic_flush = sprd_crtc_atomic_flush, + .atomic_enable = sprd_crtc_atomic_enable, + .atomic_disable = sprd_crtc_atomic_disable, +}; + +static const struct drm_crtc_funcs sprd_crtc_funcs = { + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = sprd_crtc_enable_vblank, + .disable_vblank = sprd_crtc_disable_vblank, +}; + +static int sprd_crtc_init (struct drm_device *drm,struct drm_crtc *crtc, +struct drm_plane *primary) +{ +struct device_node *port; +int ret; + +/* +* set crtc port so that drm_of_find_possible_crtcs call works +*/ + port =of_parse_phandle (drm->dev->of_node,"ports" ,0 ); +if (!port) { +DRM_ERROR ("find 'ports' phandle of %s failed\n" , + drm->dev->of_node->full_name); +return -EINVAL ; + } +of_node_put (port); + crtc->port = port; + + ret =drm_crtc_init_with_planes (drm, crtc, primary,NULL , + &sprd_crtc_funcs,NULL ); +if (ret) { +DRM_ERROR ("failed to init crtc.\n" ); +return ret; + } + +drm_mode_crtc_set_gamma_size (crtc,256 ); + +drm_crtc_helper_add (crtc, &sprd_crtc_helper_funcs); + +return 0 ; +} + +static void sprd_dpu_init (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->init (ctx); + dpu->core->ifconfig (ctx); +} + +static void sprd_dpu_fini (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->fini (ctx); +} + +static irqreturn_t sprd_dpu_isr (int irq,void *data) +{ +struct sprd_dpu *dpu = data; +struct dpu_context *ctx = &dpu->ctx; +u32 int_mask =0 ; + + int_mask = dpu->core->isr (ctx); + +if (int_mask &BIT_DPU_INT_ERR ) +DRM_WARN ("Warning: dpu underflow!\n" ); + +if (int_mask &BIT_DPU_INT_VSYNC ) +drm_crtc_handle_vblank (&dpu->crtc); + +return IRQ_HANDLED ; +} + +static int sprd_dpu_bind (struct device *dev,struct device *master,void *data) +{ +struct drm_device *drm = data; +struct sprd_dpu *dpu =dev_get_drvdata (dev); +struct drm_plane *plane; +int ret; + + plane =sprd_plane_init (drm, dpu); +if (IS_ERR_OR_NULL (plane)) { + ret =PTR_ERR (plane); +return ret; + } + + ret =sprd_crtc_init (drm, &dpu->crtc, plane); +if (ret) +return ret; + +return 0 ; +} + +static void sprd_dpu_unbind (struct device *dev,struct device *master, +void *data) +{ +struct sprd_dpu *dpu =dev_get_drvdata (dev); + +drm_crtc_cleanup (&dpu->crtc); +} + +static const struct component_ops dpu_component_ops = { + .bind = sprd_dpu_bind, + .unbind = sprd_dpu_unbind, +}; + +static int sprd_dpu_context_init (struct sprd_dpu *dpu, +struct device *dev) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dpu_context *ctx = &dpu->ctx; +struct resource *res; +int ret; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + ctx->base =devm_ioremap (dev, res->start,resource_size (res)); +if (!ctx->base) { +DRM_ERROR ("failed to map dpu registers\n" ); +return -EFAULT ; + } + + ctx->irq =platform_get_irq (pdev,0 ); +if (ctx->irq <0 ) { +DRM_ERROR ("failed to get dpu irq\n" ); +return ctx->irq; + } + +irq_set_status_flags (ctx->irq,IRQ_NOAUTOEN ); + ret =devm_request_irq (dev, ctx->irq, sprd_dpu_isr, +0 ,"DPU" , dpu); +if (ret) { +DRM_ERROR ("failed to register dpu irq handler\n" ); +return ret; + } + +init_waitqueue_head (&ctx->wait_queue); + +return 0 ; +} + +static const struct sprd_dpu_ops sharkl3_dpu = { + .core = &dpu_r2p0_core_ops, +}; + +static const struct of_device_id dpu_match_table[] = { + { .compatible ="sprd,sharkl3-dpu" , + .data = &sharkl3_dpu }, + {/* sentinel */ }, +}; + +static int sprd_dpu_probe (struct platform_device *pdev) +{ +const struct sprd_dpu_ops *pdata; +struct sprd_dpu *dpu; +int ret; + + dpu =devm_kzalloc (&pdev->dev,sizeof (*dpu),GFP_KERNEL ); +if (!dpu) +return -ENOMEM ; + + pdata =of_device_get_match_data (&pdev->dev); +if (pdata) { + dpu->core = pdata->core; + }else { +DRM_ERROR ("No matching driver data found\n" ); +return -EINVAL ; + } + + ret =sprd_dpu_context_init (dpu, &pdev->dev); +if (ret) +return ret; + +platform_set_drvdata (pdev, dpu); + +return component_add (&pdev->dev, &dpu_component_ops); +} + +static int sprd_dpu_remove (struct platform_device *pdev) +{ +component_del (&pdev->dev, &dpu_component_ops); +return 0 ; +} + +struct platform_driver sprd_dpu_driver = { + .probe = sprd_dpu_probe, + .remove = sprd_dpu_remove, + .driver = { + .name ="sprd-dpu-drv" , + .of_match_table = dpu_match_table, + }, +}; + +MODULE_AUTHOR ("Leon He <[email protected]>" ); +MODULE_AUTHOR ("Kevin Tang <[email protected]>" ); +MODULE_DESCRIPTION ("Unisoc Display Controller Driver" ); +MODULE_LICENSE ("GPL v2" );drivers/gpu/drm/sprd/sprd_dpu.h new file +187
-0@@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#ifndef __SPRD_DPU_H__ +#define __SPRD_DPU_H__ + +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <video/videomode.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_print.h> +#include <drm/drm_vblank.h> +#include <uapi/drm/drm_mode.h> + +#define BIT_DPU_INT_DONE_ BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_EDPI_TE BIT(3) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_WB_DONE BIT(6) +#define BIT_DPU_INT_WB_ERR BIT(7) + +#define BIT_DPU_LAY_LAYER_ALPHA (0x01 << 2) +#define BIT_DPU_LAY_COMBO_ALPHA (0x02 << 2) +#define BIT_DPU_LAY_FORMAT_YUV422_2PLANE (0x00 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_2PLANE (0x01 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_3PLANE (0x02 << 4) +#define BIT_DPU_LAY_FORMAT_ARGB8888 (0x03 << 4) +#define BIT_DPU_LAY_FORMAT_RGB565 (0x04 << 4) +#define BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 (0x00 << 8) +#define BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 (0x01 << 8) +#define BIT_DPU_LAY_NO_SWITCH (0x00 << 10) +#define BIT_DPU_LAY_RB_OR_UV_SWITCH (0x01 << 10) +#define BIT_DPU_LAY_MODE_BLEND_NORMAL (0x00 << 16) +#define BIT_DPU_LAY_MODE_BLEND_PREMULT (0x01 << 16) + +enum { +SPRD_DPU_IF_DBI =0 , +SPRD_DPU_IF_DPI , +SPRD_DPU_IF_EDPI , +SPRD_DPU_IF_LIMIT +}; + +enum { +DPU_LAYER_ROTATION_0 , +DPU_LAYER_ROTATION_90 , +DPU_LAYER_ROTATION_180 , +DPU_LAYER_ROTATION_270 , +DPU_LAYER_ROTATION_0_M , +DPU_LAYER_ROTATION_90_M , +DPU_LAYER_ROTATION_180_M , +DPU_LAYER_ROTATION_270_M , +}; + +struct dpu_layer { +u8 index; +u8 planes; +u32 addr[4 ]; +u32 pitch[4 ]; +s16 src_x; +s16 src_y; +s16 src_w; +s16 src_h; +s16 dst_x; +s16 dst_y; +u16 dst_w; +u16 dst_h; +u32 format; +u32 alpha; +u32 blending; +u32 rotation; +}; + +/** +* Sprd DPU capability structure +* +* @max_layers: maximum number of layers available +* @fmts_ptr: A pointer to array of supported pixel formats +* @fmts_cnt: the number of format on @fmts_ptr +*/ +struct dpu_capability { +u32 max_layers; +const u32 *fmts_ptr; +u32 fmts_cnt; +}; + +/** +* Sprd DPU core callback ops +* +* This structure decribes the display controller common +* callback ops +* +* @init: initial DPU core +* @fini: cleanup DPU core +* @run: enable DPU output +* @stop: disable DPU output +* @enable_vsync: enable vblank interrupt +* @disable_vsync: disable vblank interrupt +* @isr: function pointer to the isr +* @ifconfig: initial DPI interface +* @flip: commit CRTC planes to DPU +* @capability: callback for DPU capabilities +*/ +struct dpu_context ; +struct dpu_core_ops { +void (*init)(struct dpu_context *ctx); +void (*fini)(struct dpu_context *ctx); +void (*run)(struct dpu_context *ctx); +void (*stop)(struct dpu_context *ctx); +void (*enable_vsync)(struct dpu_context *ctx); +void (*disable_vsync)(struct dpu_context *ctx); +u32 (*isr)(struct dpu_context *ctx); +void (*ifconfig)(struct dpu_context *ctx); +void (*flip)(struct dpu_context *ctx, +struct dpu_layer layers[],u8 count); +void (*capability)(struct dpu_context *ctx, +struct dpu_capability *cap); +}; + +/** +* Sprd DPU context structure +* +* @base: DPU controller base address +* @irq: IRQ number to install the handler for +* @if_type: The type of DPI interface, default is DPI mode. +* @vm: videomode structure to use for DPU and DPI initialization +* @stopped: indicates whether DPU are stopped +* @wait_queue: wait queue, used to wait for DPU shadow register update done and +* DPU stop register done interrupt signal. +* @evt_update: wait queue condition for DPU shadow register +* @evt_stop: wait queue condition for DPU stop register +*/ +struct dpu_context { +void __iomem *base; +int irq; +u8 if_type; +struct videomode vm; +bool stopped; +wait_queue_head_t wait_queue; +bool evt_update; +bool evt_stop; +}; + +/** +* Sprd DPU device structure +* +* @crtc: DRM crtc +* @ctx: A pointer to the DPU's implementation specific context +* @core: pointer to callbacks for DPU core functionality +* @layers: active DPU layers ready to commit +* @pending_planes: the number of layers on @layers +*/ +struct sprd_dpu { +struct drm_crtc crtc; +struct dpu_context ctx; +const struct dpu_core_ops *core; +struct dpu_layer *layers; +u8 pending_planes; +}; + +/** +* Sprd DPU H/W callback ops match table structure +* The structure used for matching a specific device callback ops +* +* @core: pointer to callbacks for DPU core functionality +*/ +struct sprd_dpu_ops { +const struct dpu_core_ops *core; +}; + +static inline struct sprd_dpu *crtc_to_dpu (struct drm_crtc *crtc) +{ + return crtc ? container_of(crtc, struct sprd_dpu, crtc) : NULL; +} + +extern const struct dpu_core_ops dpu_r2p0_core_ops; + +#endif drivers/gpu/drm/sprd/sprd_drm.c +1
-0@@ -200,6 +200,7 @@ static struct platform_driver sprd_drm_driver = {static struct platform_driver *sprd_drm_drivers[] = { &sprd_drm_driver, + &sprd_dpu_driver, };static int __init sprd_drm_init (void )drivers/gpu/drm/sprd/sprd_drm.h +2
-1@@ -13,4 +13,6 @@ struct sprd_drm { struct drm_device *drm; }; +extern struct platform_driver sprd_dpu_driver; +#endif /* _SPRD_DRM_H_ */ --Quoted 2 lines
2.7.4
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
Re: [PATCH RFC v6 4/6] drm/sprd: add Unisoc's drm display controller driver
In reply to Daniel VetterQuoted 34 lines · Daniel Vetter <[email protected]> 于2020年7月29日周三 上午5:51写道:
Quoted 4 lines · Kevin Tang
From: Kevin Tang <[email protected]>
Adds DPU(Display Processor Unit) support for the Unisoc's display
subsystem.
Quoted 1 line
It's support multi planes, scaler, rotation, PQ(Picture Quality) and
more.
Quoted 4 lines
RFC v6:
- Access registers via readl/writel
- Checking for unsupported KMS properties (format, rotation,
blend_mode, etc) onplane_checkopsQuoted 5 lines
- Remove always true checks for dpu core ops
Cc Orson Zhai <[email protected]>Cc Chunyan Zhang <[email protected]>Signed-off-by Kevin Tang <[email protected]>Quickly scrolled through this, and the entire thing very much leaves a midlayer heavy aftertaste. Do we really need stuff like struct
dpu_layerand structdpu_core_ops? They only seem to complicate the code base, and seem to have no real reason. The indirection with first computing register values into a sprd_plane/crtc structure, and then writing it into hardware is also a bit much - I recommend to only do that if you have to compute values in_checkto validate them, so that the computation doesn't have to be repeated in the commit phase functions.Also, the layer and
pending_flipsstuff insprd_dpudon't work with atomic, that races. You have to put all that stuff into state objects, or if it's some data shared with interrupt handlers (doesn't seem to be the case here), it needs its own locking, and any data you need in the interrupt handler must be copied over.
Quoted 8 lines
Also no
devm_kzallocfor anything containined a drm_* structure, that's the wrong lifetime.So yeah high level review is that I think this driver would benefit a lot from a pile of demidlayer.
Cheers, Daniel
Hi Daniel,
After a long time of thinking, I think you are right, the stuff layer of dpu_layer and dpu_core_ops
maybe no need for us now. So i will delete "dpu_layer" on patch v3, and commit layer information directly
in atomic_update.
Because only one dpu h/w verison been submitt now, so i have delete "dpu_core_ops" on patch v2.
After the basic version is submitted, I will start preparing for the support of multiple h/w versions,
but it will take some time, because our different h/w versions all have some differences.
Only drm format convert to dpu format need to check on atomic_check, i'm not sure if drm framework
will help filter out illegal formats, so i add layer format check on atomic_check,
as for rotation, blend mode, i think it just give a default value, it maybe work well.
Best Wishes
Quoted 1,458 lines
Quoted 6 lines
--- drivers/gpu/drm/sprd/Makefile | 5 +- drivers/gpu/drm/sprd/dpu/Makefile | 3 + drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 503 ++++++++++++++++++++++++++++ drivers/gpu/drm/sprd/sprd_dpu.c | 646++++++++++++++++++++++++++++++++++++
Review
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_dpu.h | 187 +++++++++++ drivers/gpu/drm/sprd/sprd_drm.c | 1 + drivers/gpu/drm/sprd/sprd_drm.h | 2 + 7 files changed, 1346 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.h(quoted diff) +0
-0b/drivers/gpu/drm/sprd/Makefile
Review
Quoted 13 lines
index 86d95d9..88ab32a 100644
drivers/gpu/drm/sprd/Makefile +4
-1@@ -2,4 +2,7 @@ subdir-ccflags-y += -I$(srctree)/$(src) -obj-y := sprd_drm.o +obj-y := sprd_drm.o \ + sprd_dpu.o + +obj-y += dpu/(quoted diff) +0
-0b/drivers/gpu/drm/sprd/dpu/Makefile
Review
Quoted 9 lines
new file mode 100644
index 0000000..40278b6drivers/gpu/drm/sprd/dpu/Makefile new file +3
-0@@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += dpu_r2p0.o(quoted diff) +0
-0
b/drivers/gpu/drm/sprd/dpu/dpu_r2p0.cQuoted 113 lines
new file mode 100644
index 0000000..4b9521ddrivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +108
-0@@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/workqueue.h> + +#include "sprd_dpu.h" + +/* DPU registers size, 4 Bytes(32 Bits) */ +#define DPU_REG_SIZE 0x04 + +/* Layer registers offset */ +#define DPU_LAY_REG_OFFSET 0x0C + +#define DPU_LAY_REG (reg, index) \ + (reg + index * DPU_LAY_REG_OFFSET * DPU_REG_SIZE) + +#define DPU_REG_RD (reg) readl_relaxed(reg) + +#define DPU_REG_WR (reg, mask) writel_relaxed(mask, reg) + +#define DPU_REG_SET (reg, mask) \ + writel_relaxed(readl_relaxed(reg) | mask, reg) + +#define DPU_REG_CLR (reg, mask) \ + writel_relaxed(readl_relaxed(reg) & ~mask, reg) + +/* Global control registers */ +#define REG_DPU_CTRL 0x04 +#define REG_DPU_CFG0 0x08 +#define REG_DPU_CFG1 0x0C +#define REG_DPU_CFG2 0x10 +#define REG_PANEL_SIZE 0x20 +#define REG_BLEND_SIZE 0x24 +#define REG_BG_COLOR 0x2C + +/* Layer0 control registers */ +#define REG_LAY_BASE_ADDR0 0x30 +#define REG_LAY_BASE_ADDR1 0x34 +#define REG_LAY_BASE_ADDR2 0x38 +#define REG_LAY_CTRL 0x40 +#define REG_LAY_SIZE 0x44 +#define REG_LAY_PITCH 0x48 +#define REG_LAY_POS 0x4C +#define REG_LAY_ALPHA 0x50 +#define REG_LAY_PALLETE 0x58 +#define REG_LAY_CROP_START 0x5C + +/* Interrupt control registers */ +#define REG_DPU_INT_EN 0x1E0 +#define REG_DPU_INT_CLR 0x1E4 +#define REG_DPU_INT_STS 0x1E8 + +/* DPI control registers */ +#define REG_DPI_CTRL 0x1F0 +#define REG_DPI_H_TIMING 0x1F4 +#define REG_DPI_V_TIMING 0x1F8 + +/* MMU control registers */ +#define REG_MMU_EN 0x800 +#define REG_MMU_VPN_RANGE 0x80C +#define REG_MMU_VAOR_ADDR_RD 0x818 +#define REG_MMU_VAOR_ADDR_WR 0x81C +#define REG_MMU_INV_ADDR_RD 0x820 +#define REG_MMU_INV_ADDR_WR 0x824 +#define REG_MMU_PPN1 0x83C +#define REG_MMU_RANGE1 0x840 +#define REG_MMU_PPN2 0x844 +#define REG_MMU_RANGE2 0x848 + +/* Global control bits */ +#define BIT_DPU_RUN BIT(0) +#define BIT_DPU_STOP BIT(1) +#define BIT_DPU_REG_UPDATE BIT(2) +#define BIT_DPU_IF_EDPI BIT(0) +#define BIT_DPU_COEF_NARROW_RANGE BIT(4) +#define BIT_DPU_Y2R_COEF_ITU709_STANDARD BIT(5) + +/* Layer control bits */ +#define BIT_DPU_LAY_EN BIT(0) + +/* Interrupt control & status bits */ +#define BIT_DPU_INT_DONE BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_FBC_PLD_ERR BIT(8) +#define BIT_DPU_INT_FBC_HDR_ERR BIT(9) +#define BIT_DPU_INT_MMU_VAOR_RD BIT(16) +#define BIT_DPU_INT_MMU_VAOR_WR BIT(17) +#define BIT_DPU_INT_MMU_INV_RD BIT(18) +#define BIT_DPU_INT_MMU_INV_WR BIT(19) + +/* DPI control bits */ +#define BIT_DPU_EDPI_TE_EN BIT(8) +#define BIT_DPU_EDPI_FROM_EXTERNAL_PAD BIT(10) +#define BIT_DPU_DPI_HALT_EN BIT(16) + + +static u32 check_mmu_isr (struct dpu_context *ctx,u32 reg_val) +{ +u32 mmu_mask =BIT_DPU_INT_MMU_VAOR_RD | + BIT_DPU_INT_MMU_VAOR_WR |drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 118
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +u32 val = reg_val & mmu_mask; +int i; + +if (val) { +DRM_ERROR ("--- iommu interrupt err: 0x%04x ---\n" , val); + +if (val &BIT_DPU_INT_MMU_INV_RD ) + DRM_ERROR("iommu invalid read error, addr:0x%08x\n",
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 119
Quoted 1 line
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +1
-0+ DPU_REG_RD(ctx->base +
REG_MMU_INV_ADDR_RD));drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 121
Quoted 2 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +2
-0+if (val &BIT_DPU_INT_MMU_INV_WR ) + DRM_ERROR("iommu invalid write error, addr:0x%08x\n",
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 122
Quoted 1 line
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +1
-0+ DPU_REG_RD(ctx->base +
REG_MMU_INV_ADDR_WR));drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 124
Quoted 2 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +2
-0+if (val &BIT_DPU_INT_MMU_VAOR_RD ) + DRM_ERROR("iommu va out of range read error,addr: 0x%08x\n",
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 125
Quoted 1 line
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +1
-0+ DPU_REG_RD(ctx->base +
REG_MMU_VAOR_ADDR_RD));drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 127
Quoted 2 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +2
-0+if (val &BIT_DPU_INT_MMU_VAOR_WR ) + DRM_ERROR("iommu va out of range write error,addr: 0x%08x\n",
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 128
Quoted 1 line
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +1
-0+ DPU_REG_RD(ctx->base +
REG_MMU_VAOR_ADDR_WR));drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 3 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +3
-0+ +for (i =0 ; i <8 ; i++) { + reg_val = DPU_REG_RD(ctx->base +
DPU_LAY_REG(REG_LAY_CTRL, i));drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 133
Quoted 2 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +2
-0+if (reg_val &0x1 ) + DRM_INFO("layer%d: 0x%08x 0x%08x 0x%08xctrl: 0x%08x\n", i,
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 134
Quoted 1 line
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +1
-0+ DPU_REG_RD(ctx->base +
DPU_LAY_REG(REG_LAY_BASE_ADDR0, i)),drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 135
Quoted 1 line
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +1
-0+ DPU_REG_RD(ctx->base +
DPU_LAY_REG(REG_LAY_BASE_ADDR1, i)),drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 136
Quoted 1 line
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +1
-0+ DPU_REG_RD(ctx->base +
DPU_LAY_REG(REG_LAY_BASE_ADDR2, i)),drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 137
Quoted 1 line
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +1
-0+ DPU_REG_RD(ctx->base +
DPU_LAY_REG(REG_LAY_CTRL, i)));drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 12 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +12
-0+ } + } + +return val; +} + +static void dpu_clean_all (struct dpu_context *ctx) +{ +int i; + +for (i =0 ; i <8 ; i++) + DPU_REG_WR(ctx->base + DPU_LAY_REG(REG_LAY_CTRL, i),
0x00);Quoted 42 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +42
-0+} + +static u32 dpu_isr (struct dpu_context *ctx) +{ +u32 reg_val, int_mask =0 ; + + reg_val =DPU_REG_RD (ctx->base +REG_DPU_INT_STS ); + +/* disable err interrupt */ +if (reg_val &BIT_DPU_INT_ERR ) + int_mask |=BIT_DPU_INT_ERR ; + +/* dpu update done isr */ +if (reg_val &BIT_DPU_INT_UPDATE_DONE ) { + ctx->evt_update = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu stop done isr */ +if (reg_val &BIT_DPU_INT_DONE ) { + ctx->evt_stop = true; +wake_up_interruptible_all (&ctx->wait_queue); + } + +/* dpu ifbc payload error isr */ +if (reg_val &BIT_DPU_INT_FBC_PLD_ERR ) { + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +DRM_ERROR ("dpu ifbc payload error\n" ); + } + +/* dpu ifbc header error isr */ +if (reg_val &BIT_DPU_INT_FBC_HDR_ERR ) { + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +DRM_ERROR ("dpu ifbc header error\n" ); + } + + int_mask |=check_mmu_isr (ctx, reg_val); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR , reg_val); +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN , int_mask); + +return reg_val;drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+} + +static int dpu_wait_stop_done (struct dpu_context *ctx) +{ +int rc; + +if (ctx->stopped) +return 0 ; + + rc = wait_event_interruptible_timeout(ctx->wait_queue,
ctx->evt_stop,Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+ msecs_to_jiffies(500)); + ctx->evt_stop = false; + + ctx->stopped = true; + +if (!rc) { +DRM_ERROR ("dpu wait for stop done time out!\n" ); +return -ETIMEDOUT ; + } +drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+return 0 ; +} + +static int dpu_wait_update_done (struct dpu_context *ctx) +{ +int rc; + + ctx->evt_update = false; + + rc = wait_event_interruptible_timeout(ctx->wait_queue,
ctx->evt_update,Quoted 27 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +27
-0+ msecs_to_jiffies(500)); + +if (!rc) { +DRM_ERROR ("dpu wait for reg update done time out!\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +static void dpu_stop (struct dpu_context *ctx) +{ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_STOP ); + +dpu_wait_stop_done (ctx); +} + +static void dpu_run (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; +} + +static void dpu_init (struct dpu_context *ctx) +{drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+u32 reg_val, size; + +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + + size = (ctx->vm.vactive <<16 ) | ctx->vm.hactive; + +DPU_REG_WR (ctx->base +REG_PANEL_SIZE , size); +DPU_REG_WR (ctx->base +REG_BLEND_SIZE , size); + + reg_val = BIT_DPU_COEF_NARROW_RANGE |
BIT_DPU_Y2R_COEF_ITU709_STANDARD;Quoted 24 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +24
-0+DPU_REG_WR (ctx->base +REG_DPU_CFG0 , reg_val); +DPU_REG_WR (ctx->base +REG_DPU_CFG1 ,0x004466da ); +DPU_REG_WR (ctx->base +REG_DPU_CFG2 ,0x00 ); + +if (ctx->stopped) +dpu_clean_all (ctx); + +DPU_REG_WR (ctx->base +REG_MMU_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_PPN1 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE1 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_PPN2 ,0x00 ); +DPU_REG_WR (ctx->base +REG_MMU_RANGE2 ,0xffff ); +DPU_REG_WR (ctx->base +REG_MMU_VPN_RANGE ,0x1ffff ); + +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xffff ); +} + +static void dpu_fini (struct dpu_context *ctx) +{ +DPU_REG_WR (ctx->base +REG_DPU_INT_EN ,0x00 ); +DPU_REG_WR (ctx->base +REG_DPU_INT_CLR ,0xff ); +} + +static void dpu_layer(struct dpu_context *ctx,drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+ struct dpu_layer *hwlayer) +{ +const struct drm_format_info *info; +u32 size, offset, ctrl, pitch; +int i; + + offset = (hwlayer->dst_x &0xffff ) | ((hwlayer->dst_y) <<16 ); + +if (hwlayer->src_w && hwlayer->src_h) + size = (hwlayer->src_w & 0xffff) | ((hwlayer->src_h) <<16);
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c line 294
Quoted 2 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +2
-0+else + size = (hwlayer->dst_w & 0xffff) | ((hwlayer->dst_h) <<16);
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 11 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +11
-0+ +for (i =0 ; i < hwlayer->planes; i++) +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_BASE_ADDR0 , + hwlayer->index), hwlayer->addr[i]); + +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_POS , + hwlayer->index), offset); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_SIZE , + hwlayer->index), size); + DPU_REG_WR(ctx->base + DPU_LAY_REG(REG_LAY_CROP_START, + hwlayer->index), hwlayer->src_y << 16 |
hwlayer->src_x);Quoted 19 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +19
-0+DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_ALPHA , + hwlayer->index), hwlayer->alpha); + + info =drm_format_info (hwlayer->format); +if (hwlayer->planes ==3 ) { +/* UV pitch is 1/2 of Y pitch*/ + pitch = (hwlayer->pitch[0 ] / info->cpp[0 ]) | + (hwlayer->pitch[0 ] / info->cpp[0 ] <<15 ); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + }else { + pitch = hwlayer->pitch[0 ] / info->cpp[0 ]; +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_PITCH , + hwlayer->index), pitch); + } + + ctrl = hwlayer->format | + hwlayer->blending | + (hwlayer->rotation &0x7 ) <<20 ;drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+ +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index), ctrl); +DPU_REG_WR (ctx->base +DPU_LAY_REG (REG_LAY_CTRL , + hwlayer->index),BIT_DPU_LAY_EN ); + +DRM_DEBUG ("dst_x = %d, dst_y = %d, dst_w = %d, dst_h = %d\n" , + hwlayer->dst_x, hwlayer->dst_y, + hwlayer->dst_w, hwlayer->dst_h); + DRM_DEBUG("start_x = %d, start_y = %d, start_w = %d, start_h =%d\n",
Quoted 22 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +22
-0+ hwlayer->src_x, hwlayer->src_y, + hwlayer->src_w, hwlayer->src_h); +} + +static void dpu_flip (struct dpu_context *ctx, +struct dpu_layer layers[],u8 count) +{ +int i; +u32 reg_val; + +/* +* Make sure the dpu is in stop status. DPU_R2P0 has no shadow +* registers in EDPI mode. So the config registers can only be +* updated in the rising edge of DPU_RUN bit. +*/ +if (ctx->if_type ==SPRD_DPU_IF_EDPI ) +dpu_wait_stop_done (ctx); + +/* reset the bgcolor to black */ +DPU_REG_WR (ctx->base +REG_BG_COLOR ,0x00 ); + +/* disable all the layers */ drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+dpu_clean_all (ctx); + +/* start configure dpu layers */ +for (i =0 ; i < count; i++) +dpu_layer (ctx, &layers[i]); + +/* update trigger and wait */ +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +if (!ctx->stopped) { + DPU_REG_SET(ctx->base + REG_DPU_CTRL,
BIT_DPU_REG_UPDATE);Quoted 25 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +25
-0+dpu_wait_update_done (ctx); + } + +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_ERR ); + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +DPU_REG_SET (ctx->base +REG_DPU_CTRL ,BIT_DPU_RUN ); + + ctx->stopped = false; + } + +/* +* If the following interrupt was disabled in isr, +* re-enable it. +*/ + reg_val =BIT_DPU_INT_FBC_PLD_ERR | +BIT_DPU_INT_FBC_HDR_ERR | +BIT_DPU_INT_MMU_VAOR_RD | +BIT_DPU_INT_MMU_VAOR_WR | +BIT_DPU_INT_MMU_INV_RD | +BIT_DPU_INT_MMU_INV_WR ; +DPU_REG_SET (ctx->base +REG_DPU_INT_EN , reg_val); + +} + +static void dpu_dpi_init (struct dpu_context *ctx)drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+{ +u32 int_mask =0 ; +u32 reg_val; + +if (ctx->if_type ==SPRD_DPU_IF_DPI ) { +/* use dpi as interface */ +DPU_REG_CLR (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* disable Halt function for SPRD DSI */ + DPU_REG_CLR(ctx->base + REG_DPI_CTRL,
BIT_DPU_DPI_HALT_EN);drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 3 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +3
-0+ +/* select te from external pad */ + DPU_REG_SET(ctx->base + REG_DPI_CTRL,
BIT_DPU_EDPI_FROM_EXTERNAL_PAD);Quoted 22 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +22
-0+ +/* set dpi timing */ + reg_val = ctx->vm.hsync_len <<0 | + ctx->vm.hback_porch <<8 | + ctx->vm.hfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_H_TIMING , reg_val); + + reg_val = ctx->vm.vsync_len <<0 | + ctx->vm.vback_porch <<8 | + ctx->vm.vfront_porch <<20 ; +DPU_REG_WR (ctx->base +REG_DPI_V_TIMING , reg_val); + +if (ctx->vm.vsync_len + ctx->vm.vback_porch <32 ) +DRM_WARN ("Warning: (vsync + vbp) < 32, " +"underflow risk!\n" ); + +/* enable dpu update done INT */ + int_mask |=BIT_DPU_INT_UPDATE_DONE ; +/* enable dpu DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable dpu dpi vsync */ + int_mask |=BIT_DPU_INT_VSYNC ;drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 10 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +10
-0+/* enable dpu TE INT */ + int_mask |=BIT_DPU_INT_TE ; +/* enable underflow err INT */ + int_mask |=BIT_DPU_INT_ERR ; + }else if (ctx->if_type ==SPRD_DPU_IF_EDPI ) { +/* use edpi as interface */ +DPU_REG_SET (ctx->base +REG_DPU_CFG0 ,BIT_DPU_IF_EDPI ); + +/* use external te */ + DPU_REG_SET(ctx->base + REG_DPI_CTRL,
BIT_DPU_EDPI_FROM_EXTERNAL_PAD);drivers/gpu/drm/sprd/dpu/dpu_r2p0.c
Quoted 3 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +3
-0+ +/* enable te */ + DPU_REG_SET(ctx->base + REG_DPI_CTRL,
BIT_DPU_EDPI_TE_EN);Review
Quoted 65 lines
drivers/gpu/drm/sprd/dpu/dpu_r2p0.c new file +64
-0+ +/* enable stop DONE INT */ + int_mask |=BIT_DPU_INT_DONE ; +/* enable TE INT */ + int_mask |=BIT_DPU_INT_TE ; + } + +/* enable ifbc payload error INT */ + int_mask |=BIT_DPU_INT_FBC_PLD_ERR ; +/* enable ifbc header error INT */ + int_mask |=BIT_DPU_INT_FBC_HDR_ERR ; +/* enable iommu va out of range read error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_RD ; +/* enable iommu va out of range write error INT */ + int_mask |=BIT_DPU_INT_MMU_VAOR_WR ; +/* enable iommu invalid read error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_RD ; +/* enable iommu invalid write error INT */ + int_mask |=BIT_DPU_INT_MMU_INV_WR ; + +DPU_REG_WR (ctx->base +REG_DPU_INT_EN , int_mask); +} + +static void enable_vsync (struct dpu_context *ctx) +{ +DPU_REG_SET (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} + +static void disable_vsync (struct dpu_context *ctx) +{ +DPU_REG_CLR (ctx->base +REG_DPU_INT_EN ,BIT_DPU_INT_VSYNC ); +} + +static const u32 primary_fmts[] = { +DRM_FORMAT_XRGB8888 ,DRM_FORMAT_XBGR8888 , +DRM_FORMAT_ARGB8888 ,DRM_FORMAT_ABGR8888 , +DRM_FORMAT_RGBA8888 ,DRM_FORMAT_BGRA8888 , +DRM_FORMAT_RGBX8888 ,DRM_FORMAT_RGB565 , +DRM_FORMAT_BGR565 ,DRM_FORMAT_NV12 , +DRM_FORMAT_NV21 ,DRM_FORMAT_NV16 , +DRM_FORMAT_NV61 ,DRM_FORMAT_YUV420 , +DRM_FORMAT_YVU420 , +}; + +static void dpu_capability (struct dpu_context *ctx, +struct dpu_capability *cap) +{ + cap->max_layers =6 ; + cap->fmts_ptr = primary_fmts; + cap->fmts_cnt =ARRAY_SIZE (primary_fmts); +} + +const struct dpu_core_ops dpu_r2p0_core_ops = { + .init = dpu_init, + .fini = dpu_fini, + .run = dpu_run, + .stop = dpu_stop, + .isr = dpu_isr, + .ifconfig = dpu_dpi_init, + .capability = dpu_capability, + .flip = dpu_flip, + .enable_vsync = enable_vsync, + .disable_vsync = disable_vsync, +};(quoted diff) +0
-0
b/drivers/gpu/drm/sprd/sprd_dpu.cQuoted 209 lines
new file mode 100644
index 0000000..5ec8e7cdrivers/gpu/drm/sprd/sprd_dpu.c new file +204
-0@@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#include <linux/component.h> +#include <linux/dma-buf.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_plane_helper.h> + +#include "sprd_drm.h" +#include "sprd_dpu.h" + +struct sprd_plane { +struct drm_plane plane; +u32 index; +u32 addr[4 ]; +u32 pitch[4 ]; +u32 format; +u32 rotation; +u32 blend_mode; +}; + +static void sprd_dpu_init (struct sprd_dpu *dpu); +static void sprd_dpu_fini (struct sprd_dpu *dpu); + +static inline struct sprd_plane *to_sprd_plane (struct drm_plane *plane) +{ + return container_of(plane, struct sprd_plane, plane); +} + +static int sprd_plane_format_convert (u32 fourcc,u32 *format) +{ +switch (fourcc) { +case DRM_FORMAT_BGRA8888 : +/* BGRA8888 -> ARGB8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_RGBX8888 : +case DRM_FORMAT_RGBA8888 : +/* RGBA8888 -> ABGR8888 */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* FALLTHRU */ +case DRM_FORMAT_ABGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_ARGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_XBGR8888 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_XRGB8888 : + *format |=BIT_DPU_LAY_FORMAT_ARGB8888 ; +break ; +case DRM_FORMAT_BGR565 : +/* RB switch */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +/* FALLTHRU */ +case DRM_FORMAT_RGB565 : + *format |=BIT_DPU_LAY_FORMAT_RGB565 ; +break ; +case DRM_FORMAT_NV12 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_NV21 : +/* 2-Lane: Yuv420 */ + *format |=BIT_DPU_LAY_FORMAT_YUV420_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV16 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +case DRM_FORMAT_NV61 : +/* 2-Lane: Yuv422 */ + *format |=BIT_DPU_LAY_FORMAT_YUV422_2PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YUV420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_NO_SWITCH ; +break ; +case DRM_FORMAT_YVU420 : + *format |=BIT_DPU_LAY_FORMAT_YUV420_3PLANE ; +/* Y endian */ + *format |=BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 ; +/* UV endian */ + *format |=BIT_DPU_LAY_RB_OR_UV_SWITCH ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_rotation_convert (u32 angle,u32 *rotation) +{ +switch (angle) { +case DRM_MODE_ROTATE_0 : + *rotation =DPU_LAYER_ROTATION_0 ; +break ; +case DRM_MODE_ROTATE_90 : + *rotation =DPU_LAYER_ROTATION_90 ; +break ; +case DRM_MODE_ROTATE_180 : + *rotation =DPU_LAYER_ROTATION_180 ; +break ; +case DRM_MODE_ROTATE_270 : + *rotation =DPU_LAYER_ROTATION_270 ; +break ; +case DRM_MODE_REFLECT_Y : + *rotation =DPU_LAYER_ROTATION_180_M ; +break ; +case (DRM_MODE_REFLECT_Y |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_90_M ; +break ; +case DRM_MODE_REFLECT_X : + *rotation =DPU_LAYER_ROTATION_0_M ; +break ; +case (DRM_MODE_REFLECT_X |DRM_MODE_ROTATE_90 ): + *rotation =DPU_LAYER_ROTATION_270_M ; +break ; +default : +return -EINVAL ; + } + +return 0 ; +} + +static int sprd_plane_atomic_check (struct drm_plane *plane, +struct drm_plane_state *state) +{ +struct sprd_plane *p =to_sprd_plane (plane); +struct drm_framebuffer *fb = state->fb; +struct drm_gem_cma_object *cma_obj; +int i, ret; +u32 addr; + +if (!state->fb || !state->crtc) +return 0 ; + + ret =sprd_plane_format_convert (fb->format->format, + &p->format); +if (ret <0 ) { +DRM_ERROR ("Invalid plane format\n" ); +return ret; + } + + ret =sprd_plane_rotation_convert (state->rotation, + &p->rotation); +if (ret <0 ) { +DRM_ERROR ("Invalid plane rotation\n" ); +return ret; + } + +switch (state->pixel_blend_mode) { +case DRM_MODE_BLEND_COVERAGE : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Normal mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_NORMAL ; +break ; +case DRM_MODE_BLEND_PREMULTI : +/* alpha mode select - combo alpha */ + p->blend_mode |=BIT_DPU_LAY_COMBO_ALPHA ; +/* Pre-mult mode */ + p->blend_mode |=BIT_DPU_LAY_MODE_BLEND_PREMULT ; +break ; +case DRM_MODE_BLEND_PIXEL_NONE : +default : +/* don't do blending, maybe RGBX */ drivers/gpu/drm/sprd/sprd_dpu.c line 214
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +10
-0+/* alpha mode select - layer alpha */ + p->blend_mode |=BIT_DPU_LAY_LAYER_ALPHA ; +break ; + } + +for (i =0 ; i < fb->format->num_planes; i++) { + cma_obj =drm_fb_cma_get_gem_obj (fb, i); + addr = cma_obj->paddr + fb->offsets[i]; +if (addr %16 ) { + DRM_ERROR("layer addr[%d] is not 16 bytes align,it's 0x%08x\n",
Quoted 38 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +38
-0+ i, addr); +return -EFAULT ; + } + + p->addr[i] = addr; + p->pitch[i] = fb->pitches[i]; + } + +return 0 ; +} + +static void sprd_plane_atomic_update (struct drm_plane *plane, +struct drm_plane_state *old_state) +{ +struct drm_plane_state *state = plane->state; +struct drm_framebuffer *fb = plane->state->fb; +struct sprd_plane *p =to_sprd_plane (plane); +struct sprd_dpu *dpu =crtc_to_dpu (plane->state->crtc); +struct dpu_layer *layer = &dpu->layers[p->index]; +int i; + +if (!state->crtc || !state->fb) +return ; + + layer->index = p->index; + layer->src_x = state->src_x >>16 ; + layer->src_y = state->src_y >>16 ; + layer->src_w = state->src_w >>16 ; + layer->src_h = state->src_h >>16 ; + layer->dst_x = state->crtc_x; + layer->dst_y = state->crtc_y; + layer->dst_w = state->crtc_w; + layer->dst_h = state->crtc_h; + layer->alpha = state->alpha; + layer->format = p->format; + layer->blending = p->blend_mode; + layer->rotation = p->rotation; + layer->planes = fb->format->num_planes;drivers/gpu/drm/sprd/sprd_dpu.c
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +10
-0+ +for (i =0 ; i < layer->planes; i++) { + layer->addr[i] = p->addr[i]; + layer->pitch[i] = p->pitch[i]; + } + + dpu->pending_planes++; +} + +static void sprd_plane_create_properties(struct sprd_plane *p, intindex)
Quoted 22 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +22
-0+{ +unsigned int supported_modes =BIT (DRM_MODE_BLEND_PIXEL_NONE ) | +BIT (DRM_MODE_BLEND_PREMULTI ) | +BIT (DRM_MODE_BLEND_COVERAGE ); + +/* create rotation property */ +drm_plane_create_rotation_property (&p->plane, +DRM_MODE_ROTATE_0 , +DRM_MODE_ROTATE_MASK | +DRM_MODE_REFLECT_MASK ); + +/* create alpha property */ +drm_plane_create_alpha_property (&p->plane); + +/* create blend mode property */ +drm_plane_create_blend_mode_property (&p->plane, supported_modes); + +/* create zpos property */ +drm_plane_create_zpos_immutable_property (&p->plane, index); +} + +static const struct drm_plane_helper_funcs sprd_plane_helper_funcs = {drivers/gpu/drm/sprd/sprd_dpu.c
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +10
-0+ .atomic_check = sprd_plane_atomic_check, + .atomic_update = sprd_plane_atomic_update, +}; + +static const struct drm_plane_funcs sprd_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state =
drm_atomic_helper_plane_duplicate_state,Quoted 16 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +16
-0+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static struct drm_plane *sprd_plane_init (struct drm_device *drm, +struct sprd_dpu *dpu) +{ +struct drm_plane *primary =NULL ; +struct sprd_plane *p =NULL ; +struct dpu_capability cap = {}; +int ret, i; + + dpu->core->capability (&dpu->ctx, &cap); + + dpu->layers =devm_kcalloc (drm->dev, cap.max_layers, +sizeof (struct dpu_layer ),GFP_KERNEL ); +if (!dpu->layers)drivers/gpu/drm/sprd/sprd_dpu.c
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +10
-0+return ERR_PTR (-ENOMEM ); + +for (i =0 ; i < cap.max_layers; i++) { + + p =devm_kzalloc (drm->dev,sizeof (*p),GFP_KERNEL ); +if (!p) +return ERR_PTR (-ENOMEM ); + + ret = drm_universal_plane_init(drm, &p->plane, 1, + &sprd_plane_funcs,cap.fmts_ptr,
drivers/gpu/drm/sprd/sprd_dpu.c line 322
Quoted 2 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +2
-0+ cap.fmts_cnt,NULL , + DRM_PLANE_TYPE_PRIMARY,NULL);
drivers/gpu/drm/sprd/sprd_dpu.c
Quoted 6 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +6
-0+if (ret) { +DRM_ERROR ("fail to init primary plane\n" ); +return ERR_PTR (ret); + } + + drm_plane_helper_add(&p->plane,
&sprd_plane_helper_funcs);drivers/gpu/drm/sprd/sprd_dpu.c
Quoted 13 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +13
-0+ +sprd_plane_create_properties (p, i); + + p->index = i; +if (i ==0 ) + primary = &p->plane; + } + +return primary; +} + +static enum drm_mode_status sprd_crtc_mode_valid (struct drm_crtc *crtc, + const struct drm_display_mode*mode)
drivers/gpu/drm/sprd/sprd_dpu.c
Quoted 4 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +4
-0+{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + DRM_DEBUG("%s() mode: "DRM_MODE_FMT"\n", __func__,
DRM_MODE_ARG(mode));Quoted 46 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +46
-0+ +if (mode->type &DRM_MODE_TYPE_PREFERRED ) { +drm_display_mode_to_videomode (mode, &dpu->ctx.vm); + +if ((mode->hdisplay == mode->htotal) || + (mode->vdisplay == mode->vtotal)) + dpu->ctx.if_type =SPRD_DPU_IF_EDPI ; +else + dpu->ctx.if_type =SPRD_DPU_IF_DPI ; + } + +return MODE_OK ; +} + +static void sprd_crtc_atomic_enable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + +sprd_dpu_init (dpu); + +enable_irq (dpu->ctx.irq); +} + +static void sprd_crtc_atomic_disable (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +disable_irq (dpu->ctx.irq); + +sprd_dpu_fini (dpu); + +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_atomic_check (struct drm_crtc *crtc, +struct drm_crtc_state *state) +{ +DRM_DEBUG ("%s()\n" , __func__);drivers/gpu/drm/sprd/sprd_dpu.c
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +10
-0+ +return 0 ; +} + +static void sprd_crtc_atomic_begin (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + memset(dpu->layers, 0, sizeof(*dpu->layers) *
dpu->pending_planes);drivers/gpu/drm/sprd/sprd_dpu.c
Quoted 13 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +13
-0+ + dpu->pending_planes =0 ; +} + +static void sprd_crtc_atomic_flush (struct drm_crtc *crtc, +struct drm_crtc_state *old_state) + +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); +struct drm_device *drm = dpu->crtc.dev; + +if (dpu->pending_planes) + dpu->core->flip(&dpu->ctx, dpu->layers,
dpu->pending_planes);Quoted 100 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +100
-0+ +spin_lock_irq (&drm->event_lock); +if (crtc->state->event) { +drm_crtc_send_vblank_event (crtc, crtc->state->event); + crtc->state->event =NULL ; + } +spin_unlock_irq (&drm->event_lock); +} + +static int sprd_crtc_enable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->enable_vsync (&dpu->ctx); + +return 0 ; +} + +static void sprd_crtc_disable_vblank (struct drm_crtc *crtc) +{ +struct sprd_dpu *dpu =crtc_to_dpu (crtc); + + dpu->core->disable_vsync (&dpu->ctx); +} + +static const struct drm_crtc_helper_funcs sprd_crtc_helper_funcs = { + .mode_valid = sprd_crtc_mode_valid, + .atomic_check = sprd_crtc_atomic_check, + .atomic_begin = sprd_crtc_atomic_begin, + .atomic_flush = sprd_crtc_atomic_flush, + .atomic_enable = sprd_crtc_atomic_enable, + .atomic_disable = sprd_crtc_atomic_disable, +}; + +static const struct drm_crtc_funcs sprd_crtc_funcs = { + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = sprd_crtc_enable_vblank, + .disable_vblank = sprd_crtc_disable_vblank, +}; + +static int sprd_crtc_init (struct drm_device *drm,struct drm_crtc *crtc, +struct drm_plane *primary) +{ +struct device_node *port; +int ret; + +/* +* set crtc port so that drm_of_find_possible_crtcs call works +*/ + port =of_parse_phandle (drm->dev->of_node,"ports" ,0 ); +if (!port) { +DRM_ERROR ("find 'ports' phandle of %s failed\n" , + drm->dev->of_node->full_name); +return -EINVAL ; + } +of_node_put (port); + crtc->port = port; + + ret =drm_crtc_init_with_planes (drm, crtc, primary,NULL , + &sprd_crtc_funcs,NULL ); +if (ret) { +DRM_ERROR ("failed to init crtc.\n" ); +return ret; + } + +drm_mode_crtc_set_gamma_size (crtc,256 ); + +drm_crtc_helper_add (crtc, &sprd_crtc_helper_funcs); + +return 0 ; +} + +static void sprd_dpu_init (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->init (ctx); + dpu->core->ifconfig (ctx); +} + +static void sprd_dpu_fini (struct sprd_dpu *dpu) +{ +struct dpu_context *ctx = &dpu->ctx; + + dpu->core->fini (ctx); +} + +static irqreturn_t sprd_dpu_isr (int irq,void *data) +{ +struct sprd_dpu *dpu = data; +struct dpu_context *ctx = &dpu->ctx; +u32 int_mask =0 ; + + int_mask = dpu->core->isr (ctx); +drivers/gpu/drm/sprd/sprd_dpu.c
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +10
-0+if (int_mask &BIT_DPU_INT_ERR ) +DRM_WARN ("Warning: dpu underflow!\n" ); + +if (int_mask &BIT_DPU_INT_VSYNC ) +drm_crtc_handle_vblank (&dpu->crtc); + +return IRQ_HANDLED ; +} + +static int sprd_dpu_bind(struct device *dev, struct device *master,void *data)
Review
Quoted 123 lines
drivers/gpu/drm/sprd/sprd_dpu.c new file +122
-0+{ +struct drm_device *drm = data; +struct sprd_dpu *dpu =dev_get_drvdata (dev); +struct drm_plane *plane; +int ret; + + plane =sprd_plane_init (drm, dpu); +if (IS_ERR_OR_NULL (plane)) { + ret =PTR_ERR (plane); +return ret; + } + + ret =sprd_crtc_init (drm, &dpu->crtc, plane); +if (ret) +return ret; + +return 0 ; +} + +static void sprd_dpu_unbind (struct device *dev,struct device *master, +void *data) +{ +struct sprd_dpu *dpu =dev_get_drvdata (dev); + +drm_crtc_cleanup (&dpu->crtc); +} + +static const struct component_ops dpu_component_ops = { + .bind = sprd_dpu_bind, + .unbind = sprd_dpu_unbind, +}; + +static int sprd_dpu_context_init (struct sprd_dpu *dpu, +struct device *dev) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dpu_context *ctx = &dpu->ctx; +struct resource *res; +int ret; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + ctx->base =devm_ioremap (dev, res->start,resource_size (res)); +if (!ctx->base) { +DRM_ERROR ("failed to map dpu registers\n" ); +return -EFAULT ; + } + + ctx->irq =platform_get_irq (pdev,0 ); +if (ctx->irq <0 ) { +DRM_ERROR ("failed to get dpu irq\n" ); +return ctx->irq; + } + +irq_set_status_flags (ctx->irq,IRQ_NOAUTOEN ); + ret =devm_request_irq (dev, ctx->irq, sprd_dpu_isr, +0 ,"DPU" , dpu); +if (ret) { +DRM_ERROR ("failed to register dpu irq handler\n" ); +return ret; + } + +init_waitqueue_head (&ctx->wait_queue); + +return 0 ; +} + +static const struct sprd_dpu_ops sharkl3_dpu = { + .core = &dpu_r2p0_core_ops, +}; + +static const struct of_device_id dpu_match_table[] = { + { .compatible ="sprd,sharkl3-dpu" , + .data = &sharkl3_dpu }, + {/* sentinel */ }, +}; + +static int sprd_dpu_probe (struct platform_device *pdev) +{ +const struct sprd_dpu_ops *pdata; +struct sprd_dpu *dpu; +int ret; + + dpu =devm_kzalloc (&pdev->dev,sizeof (*dpu),GFP_KERNEL ); +if (!dpu) +return -ENOMEM ; + + pdata =of_device_get_match_data (&pdev->dev); +if (pdata) { + dpu->core = pdata->core; + }else { +DRM_ERROR ("No matching driver data found\n" ); +return -EINVAL ; + } + + ret =sprd_dpu_context_init (dpu, &pdev->dev); +if (ret) +return ret; + +platform_set_drvdata (pdev, dpu); + +return component_add (&pdev->dev, &dpu_component_ops); +} + +static int sprd_dpu_remove (struct platform_device *pdev) +{ +component_del (&pdev->dev, &dpu_component_ops); +return 0 ; +} + +struct platform_driver sprd_dpu_driver = { + .probe = sprd_dpu_probe, + .remove = sprd_dpu_remove, + .driver = { + .name ="sprd-dpu-drv" , + .of_match_table = dpu_match_table, + }, +}; + +MODULE_AUTHOR ("Leon He <[email protected]>" ); +MODULE_AUTHOR ("Kevin Tang <[email protected]>" ); +MODULE_DESCRIPTION ("Unisoc Display Controller Driver" ); +MODULE_LICENSE ("GPL v2" );(quoted diff) +0
-0
b/drivers/gpu/drm/sprd/sprd_dpu.hQuoted 132 lines
new file mode 100644
index 0000000..7d3c5e4drivers/gpu/drm/sprd/sprd_dpu.h new file +127
-0@@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#ifndef __SPRD_DPU_H__ +#define __SPRD_DPU_H__ + +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <video/videomode.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_print.h> +#include <drm/drm_vblank.h> +#include <uapi/drm/drm_mode.h> + +#define BIT_DPU_INT_DONE_ BIT(0) +#define BIT_DPU_INT_TE BIT(1) +#define BIT_DPU_INT_ERR BIT(2) +#define BIT_DPU_INT_EDPI_TE BIT(3) +#define BIT_DPU_INT_UPDATE_DONE BIT(4) +#define BIT_DPU_INT_VSYNC BIT(5) +#define BIT_DPU_INT_WB_DONE BIT(6) +#define BIT_DPU_INT_WB_ERR BIT(7) + +#define BIT_DPU_LAY_LAYER_ALPHA (0x01 << 2) +#define BIT_DPU_LAY_COMBO_ALPHA (0x02 << 2) +#define BIT_DPU_LAY_FORMAT_YUV422_2PLANE (0x00 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_2PLANE (0x01 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_3PLANE (0x02 << 4) +#define BIT_DPU_LAY_FORMAT_ARGB8888 (0x03 << 4) +#define BIT_DPU_LAY_FORMAT_RGB565 (0x04 << 4) +#define BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 (0x00 << 8) +#define BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 (0x01 << 8) +#define BIT_DPU_LAY_NO_SWITCH (0x00 << 10) +#define BIT_DPU_LAY_RB_OR_UV_SWITCH (0x01 << 10) +#define BIT_DPU_LAY_MODE_BLEND_NORMAL (0x00 << 16) +#define BIT_DPU_LAY_MODE_BLEND_PREMULT (0x01 << 16) + +enum { +SPRD_DPU_IF_DBI =0 , +SPRD_DPU_IF_DPI , +SPRD_DPU_IF_EDPI , +SPRD_DPU_IF_LIMIT +}; + +enum { +DPU_LAYER_ROTATION_0 , +DPU_LAYER_ROTATION_90 , +DPU_LAYER_ROTATION_180 , +DPU_LAYER_ROTATION_270 , +DPU_LAYER_ROTATION_0_M , +DPU_LAYER_ROTATION_90_M , +DPU_LAYER_ROTATION_180_M , +DPU_LAYER_ROTATION_270_M , +}; + +struct dpu_layer { +u8 index; +u8 planes; +u32 addr[4 ]; +u32 pitch[4 ]; +s16 src_x; +s16 src_y; +s16 src_w; +s16 src_h; +s16 dst_x; +s16 dst_y; +u16 dst_w; +u16 dst_h; +u32 format; +u32 alpha; +u32 blending; +u32 rotation; +}; + +/** +* Sprd DPU capability structure +* +* @max_layers: maximum number of layers available +* @fmts_ptr: A pointer to array of supported pixel formats +* @fmts_cnt: the number of format on @fmts_ptr +*/ +struct dpu_capability { +u32 max_layers; +const u32 *fmts_ptr; +u32 fmts_cnt; +}; + +/** +* Sprd DPU core callback ops +* +* This structure decribes the display controller common +* callback ops +* +* @init: initial DPU core +* @fini: cleanup DPU core +* @run: enable DPU output +* @stop: disable DPU output +* @enable_vsync: enable vblank interrupt +* @disable_vsync: disable vblank interrupt +* @isr: function pointer to the isr +* @ifconfig: initial DPI interface +* @flip: commit CRTC planes to DPU +* @capability: callback for DPU capabilities +*/ +struct dpu_context ; +struct dpu_core_ops { +void (*init)(struct dpu_context *ctx); +void (*fini)(struct dpu_context *ctx); +void (*run)(struct dpu_context *ctx); +void (*stop)(struct dpu_context *ctx); +void (*enable_vsync)(struct dpu_context *ctx); +void (*disable_vsync)(struct dpu_context *ctx); +u32 (*isr)(struct dpu_context *ctx); +void (*ifconfig)(struct dpu_context *ctx); +void (*flip)(struct dpu_context *ctx, +struct dpu_layer layers[],u8 count); +void (*capability)(struct dpu_context *ctx, +struct dpu_capability *cap); +};drivers/gpu/drm/sprd/sprd_dpu.h line 137
Quoted 10 lines
drivers/gpu/drm/sprd/sprd_dpu.h new file +10
-0+ +/** +* Sprd DPU context structure +* +* @base: DPU controller base address +* @irq: IRQ number to install the handler for +* @if_type: The type of DPI interface, default is DPI mode. +* @vm: videomode structure to use for DPU and DPI initialization +* @stopped: indicates whether DPU are stopped +* @wait_queue: wait queue, used to wait for DPU shadow register update done and
Review
Quoted 51 lines
drivers/gpu/drm/sprd/sprd_dpu.h new file +50
-0+* DPU stop register done interrupt signal. +* @evt_update: wait queue condition for DPU shadow register +* @evt_stop: wait queue condition for DPU stop register +*/ +struct dpu_context { +void __iomem *base; +int irq; +u8 if_type; +struct videomode vm; +bool stopped; +wait_queue_head_t wait_queue; +bool evt_update; +bool evt_stop; +}; + +/** +* Sprd DPU device structure +* +* @crtc: DRM crtc +* @ctx: A pointer to the DPU's implementation specific context +* @core: pointer to callbacks for DPU core functionality +* @layers: active DPU layers ready to commit +* @pending_planes: the number of layers on @layers +*/ +struct sprd_dpu { +struct drm_crtc crtc; +struct dpu_context ctx; +const struct dpu_core_ops *core; +struct dpu_layer *layers; +u8 pending_planes; +}; + +/** +* Sprd DPU H/W callback ops match table structure +* The structure used for matching a specific device callback ops +* +* @core: pointer to callbacks for DPU core functionality +*/ +struct sprd_dpu_ops { +const struct dpu_core_ops *core; +}; + +static inline struct sprd_dpu *crtc_to_dpu (struct drm_crtc *crtc) +{ + return crtc ? container_of(crtc, struct sprd_dpu, crtc) : NULL; +} + +extern const struct dpu_core_ops dpu_r2p0_core_ops; + +#endif (quoted diff) +0
-0
b/drivers/gpu/drm/sprd/sprd_drm.cReview
Quoted 12 lines
index 4706185..200020f 100644
drivers/gpu/drm/sprd/sprd_drm.c +1
-0@@ -200,6 +200,7 @@ static struct platform_driver sprd_drm_driver = {static struct platform_driver *sprd_drm_drivers[] = { &sprd_drm_driver, + &sprd_dpu_driver, };static int __init sprd_drm_init (void )(quoted diff) +0
-0
b/drivers/gpu/drm/sprd/sprd_drm.hQuoted 7 lines
index edf0881..3c32f3a 100644
drivers/gpu/drm/sprd/sprd_drm.h +0
-0@@ -13,4 +13,6 @@ struct sprd_drm {struct drm_device *drm; };
Quoted 13 lines
Quoted 6 lines
drivers/gpu/drm/sprd/sprd_drm.h +2
-1+extern struct platform_driver sprd_dpu_driver; +#endif /* _SPRD_DRM_H_ */ --2.7.4
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
RFC PATCH v6 5/6 dt-bindings: display: add Unisoc's mipi dsi&dphy bindings
In reply to Kevin TangFrom: Kevin Tang <[email protected]>
Adds MIPI DSI Master and MIPI DSI-PHY (D-PHY)
support for Unisoc's display subsystem.
--- .../devicetree/bindings/display/sprd/dphy.yaml | 75 +++++++++++++++++ .../devicetree/bindings/display/sprd/dsi.yaml | 98 ++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/dphy.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/dsi.yaml
Documentation/devicetree/bindings/display/sprd/dphy.yaml new file +75 -0
@@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/sprd/dphy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc MIPI DSI-PHY (D-PHY) + +maintainers: + - Mark Rutland <[email protected]> + +properties: + compatible: + const: sprd,sharkl3-dsi-phy + + reg: + maxItems: 1 + description: + Must be the dsi controller base address. + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + port@0: + type: object + description: + A port node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + That port should be the output endpoint, usually output to + the associated panel. + port@1: + type: object + description: + A port node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + That port should be the input endpoint, usually coming from + the associated DSI controller. + +required: + - compatible + - reg + - port@0 + - port@1 + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + dphy: dphy { + compatible = "sprd,sharkl3-dsi-phy"; + reg = <0x0 0x63100000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + /* input port*/ + port@1 { + reg = <1>; + dphy_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + + /* output port */ + port@0 { + reg = <0>; + dphy_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + };
Documentation/devicetree/bindings/display/sprd/dsi.yaml new file +98 -0
98 lines not on this page · raw message
Signature · 1 line
2.7.4
RFC PATCH v6 6/6 drm/sprd: add Unisoc's drm mipi dsi&dphy driver
In reply to Kevin TangFrom: Kevin Tang <[email protected]>
Adds dsi host controller support for the Unisoc's display subsystem. Adds dsi phy support for the Unisoc's display subsystem. Only MIPI DSI Displays supported, DP/TV/HMDI will be support in the feature.
--- drivers/gpu/drm/sprd/Makefile | 7 +- drivers/gpu/drm/sprd/disp_lib.c | 57 + drivers/gpu/drm/sprd/disp_lib.h | 16 + drivers/gpu/drm/sprd/dphy/Makefile | 7 + drivers/gpu/drm/sprd/dphy/pll/Makefile | 3 + drivers/gpu/drm/sprd/dphy/pll/megacores_sharkle.c | 473 +++++++ drivers/gpu/drm/sprd/dphy/sprd_dphy_api.c | 201 +++ drivers/gpu/drm/sprd/dphy/sprd_dphy_api.h | 22 + drivers/gpu/drm/sprd/dsi/Makefile | 8 + drivers/gpu/drm/sprd/dsi/core/Makefile | 4 + drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.c | 964 ++++++++++++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.h | 1477 +++++++++++++++++++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.c | 328 +++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.h | 32 + drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c | 590 ++++++++ drivers/gpu/drm/sprd/dsi/sprd_dsi_api.h | 26 + drivers/gpu/drm/sprd/sprd_dphy.c | 209 +++ drivers/gpu/drm/sprd/sprd_dphy.h | 50 + drivers/gpu/drm/sprd/sprd_dpu.c | 22 + drivers/gpu/drm/sprd/sprd_dpu.h | 3 + drivers/gpu/drm/sprd/sprd_dsi.c | 571 ++++++++ drivers/gpu/drm/sprd/sprd_dsi.h | 108 ++ 22 files changed, 5177 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/sprd/disp_lib.c create mode 100644 drivers/gpu/drm/sprd/disp_lib.h create mode 100644 drivers/gpu/drm/sprd/dphy/Makefile create mode 100644 drivers/gpu/drm/sprd/dphy/pll/Makefile create mode 100644 drivers/gpu/drm/sprd/dphy/pll/megacores_sharkle.c create mode 100644 drivers/gpu/drm/sprd/dphy/sprd_dphy_api.c create mode 100644 drivers/gpu/drm/sprd/dphy/sprd_dphy_api.h create mode 100644 drivers/gpu/drm/sprd/dsi/Makefile create mode 100644 drivers/gpu/drm/sprd/dsi/core/Makefile create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.c create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.h create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.c create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.h create mode 100644 drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c create mode 100644 drivers/gpu/drm/sprd/dsi/sprd_dsi_api.h create mode 100644 drivers/gpu/drm/sprd/sprd_dphy.c create mode 100644 drivers/gpu/drm/sprd/sprd_dphy.h create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.c create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.h
drivers/gpu/drm/sprd/Makefile +6 -1
@@ -3,6 +3,11 @@ subdir-ccflags-y += -I$(srctree)/$(src) obj-y := sprd_drm.o \ - sprd_dpu.o + sprd_dpu.o \ + sprd_dsi.o \ + sprd_dphy.o +obj-y += disp_lib.o obj-y += dpu/ +obj-y += dsi/ +obj-y += dphy/
drivers/gpu/drm/sprd/disp_lib.c new file +57 -0
57 lines not on this page · raw message
drivers/gpu/drm/sprd/disp_lib.h new file +16 -0
@@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#ifndef _DISP_LIB_H_ +#define _DISP_LIB_H_ + +#include <linux/list.h> +#include <drm/drm_print.h> + +struct device *sprd_disp_pipe_get_by_port (struct device *dev,int port); +struct device *sprd_disp_pipe_get_input (struct device *dev); +struct device *sprd_disp_pipe_get_output (struct device *dev); + +#endif /* _DISP_LIB_H_ */
drivers/gpu/drm/sprd/dphy/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 + +subdir-ccflags-y += -I$(srctree)/$(src) + +obj-y := sprd_dphy_api.o + +obj-y += pll/
drivers/gpu/drm/sprd/dphy/pll/Makefile new file +3 -0
@@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += megacores_sharkle.o
drivers/gpu/drm/sprd/dphy/pll/megacores_sharkle.c new file +473 -0
473 lines not on this page · raw message
drivers/gpu/drm/sprd/dphy/sprd_dphy_api.c new file +201 -0
201 lines not on this page · raw message
drivers/gpu/drm/sprd/dphy/sprd_dphy_api.h new file +22 -0
@@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 Unisoc Inc. +*/ + +#ifndef _SPRD_DPHY_API_H_ +#define _SPRD_DPHY_API_H_ + +#include "sprd_dphy.h" + +int sprd_dphy_power_on (struct sprd_dphy *dphy); +void sprd_dphy_power_off (struct sprd_dphy *dphy); +void sprd_dphy_data_ulps_enter (struct sprd_dphy *dphy); +void sprd_dphy_data_ulps_exit (struct sprd_dphy *dphy); +void sprd_dphy_clk_ulps_enter (struct sprd_dphy *dphy); +void sprd_dphy_clk_ulps_exit (struct sprd_dphy *dphy); +void sprd_dphy_force_pll (struct sprd_dphy *dphy,bool enable); +void sprd_dphy_hs_clk_en (struct sprd_dphy *dphy,bool enable); +void sprd_dphy_test_write (struct sprd_dphy *dphy,u8 address,u8 data); +u8 sprd_dphy_test_read (struct sprd_dphy *dphy,u8 address); + +#endif /* _SPRD_DPHY_API_H_ */
drivers/gpu/drm/sprd/dsi/Makefile new file +8 -0
@@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +subdir-ccflags-y += -I$(srctree)/$(src) + +obj-y += sprd_dsi_api.o + +obj-y += core/ +
drivers/gpu/drm/sprd/dsi/core/Makefile new file +4 -0
@@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += dsi_ctrl_r1p0.o dsi_ctrl_r1p0_ppi.o +
drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.c new file +964 -0
964 lines not on this page · raw message
drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.h new file +1477 -0
1,232 lines not on this page · raw message
drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.c new file +328 -0
328 lines not on this page · raw message
drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.h new file +32 -0
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c new file +590 -0
590 lines not on this page · raw message
drivers/gpu/drm/sprd/dsi/sprd_dsi_api.h new file +26 -0
Lines of this file are not shown. View the raw message.
drivers/gpu/drm/sprd/sprd_dphy.c new file +209 -0
209 lines not on this page · raw message
drivers/gpu/drm/sprd/sprd_dphy.h new file +50 -0
50 lines not on this page · raw message
drivers/gpu/drm/sprd/sprd_dsi.c new file +571 -0
571 lines not on this page · raw message
drivers/gpu/drm/sprd/sprd_dsi.h new file +108 -0
108 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.7.4
Part of the diff is not shown here. View the raw message.
kernel test robot
build botRe: [PATCH RFC v6 6/6] drm/sprd: add Unisoc's drm mipi dsi&dphy driver
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch]
Hi Kevin,
[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v5.8-rc7]
[cannot apply to next-20200728]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Kevin-Tang/Add-Unisoc-s-drm-kms-module/20200728-181033 base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next config: arc-allyesconfig (attached as .config) compiler: arc-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc
If you fix the issue, kindly add following tag as appropriate
All warnings (new ones prefixed by >>):
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:163:6: warning: no previous prototype for 'sprd_dsi_power_on' [-Wmissing-prototypes]
163 | void sprd_dsi_power_on(struct sprd_dsi *dsi)
| ^~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:206:6: warning: no previous prototype for 'sprd_dsi_power_off' [-Wmissing-prototypes]
206 | void sprd_dsi_power_off(struct sprd_dsi *dsi)
| ^~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:225:5: warning: no previous prototype for 'sprd_dsi_dpi_video' [-Wmissing-prototypes]
225 | int sprd_dsi_dpi_video(struct sprd_dsi *dsi)
| ^~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:355:5: warning: no previous prototype for 'sprd_dsi_edpi_video' [-Wmissing-prototypes]
355 | int sprd_dsi_edpi_video(struct sprd_dsi *dsi)
| ^~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:400:5: warning: no previous prototype for 'sprd_dsi_wr_pkt' [-Wmissing-prototypes]
400 | int sprd_dsi_wr_pkt(struct sprd_dsi *dsi, u8 vc, u8 type,
| ^~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:463:5: warning: no previous prototype for 'sprd_dsi_rd_pkt' [-Wmissing-prototypes]
463 | int sprd_dsi_rd_pkt(struct sprd_dsi *dsi, u8 vc, u8 type,
| ^~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:517:6: warning: no previous prototype for 'sprd_dsi_set_work_mode' [-Wmissing-prototypes]
517 | void sprd_dsi_set_work_mode(struct sprd_dsi *dsi, u8 mode)
| ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:527:5: warning: no previous prototype for 'sprd_dsi_get_work_mode' [-Wmissing-prototypes]
527 | int sprd_dsi_get_work_mode(struct sprd_dsi *dsi)
| ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:537:6: warning: no previous prototype for 'sprd_dsi_lp_cmd_enable' [-Wmissing-prototypes]
537 | void sprd_dsi_lp_cmd_enable(struct sprd_dsi *dsi, bool enable)
| ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:547:6: warning: no previous prototype for 'sprd_dsi_nc_clk_en' [-Wmissing-prototypes]
547 | void sprd_dsi_nc_clk_en(struct sprd_dsi *dsi, bool enable)
| ^~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:554:6: warning: no previous prototype for 'sprd_dsi_state_reset' [-Wmissing-prototypes]
554 | void sprd_dsi_state_reset(struct sprd_dsi *dsi)
| ^~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:563:5: warning: no previous prototype for 'sprd_dsi_int_status' [-Wmissing-prototypes]
563 | u32 sprd_dsi_int_status(struct sprd_dsi *dsi, int index)
| ^~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c:580:6: warning: no previous prototype for 'sprd_dsi_int_mask' [-Wmissing-prototypes] 580 | void sprd_dsi_int_mask(struct sprd_dsi *dsi, int index)
| ^~~~~~~~~~~~~~~~~
vim +/sprd_dsi_power_on +163 drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c
159
160 #define ns_to_cycle(ns, byte_clk) \
161 DIV_ROUND_UP((ns) * (byte_clk), 1000000)
162
> 163 void sprd_dsi_power_on(struct sprd_dsi *dsi)
164 {
165 int div;
166 struct dsi_context *ctx = &dsi->ctx;
167 u16 max_rd_time;
168 u16 data_hs2lp, data_lp2hs, clk_hs2lp, clk_lp2hs;
169
170 dsi_power_enable(ctx, 0);
171 dsi_int0_mask(ctx, 0xffffffff);
172 dsi_int1_mask(ctx, 0xffffffff);
173 dsi_cmd_mode(ctx);
174 dsi_eotp_rx_en(ctx, 0);
175 dsi_eotp_tx_en(ctx, 0);
176 dsi_ecc_rx_en(ctx, 1);
177 dsi_crc_rx_en(ctx, 1);
178 dsi_bta_en(ctx, 1);
179 dsi_video_vcid(ctx, 0);
180 dsi_rx_vcid(ctx, 0);
181
182 div = DIV_ROUND_UP(ctx->byte_clk, ctx->esc_clk);
183 dsi_tx_escape_division(ctx, div);
184
185 max_rd_time = ns_to_cycle(ctx->max_rd_time, ctx->byte_clk);
186 dsi_max_read_time(ctx, max_rd_time);
187
188 data_hs2lp = ns_to_cycle(ctx->data_hs2lp, ctx->byte_clk);
189 data_lp2hs = ns_to_cycle(ctx->data_lp2hs, ctx->byte_clk);
190 clk_hs2lp = ns_to_cycle(ctx->clk_hs2lp, ctx->byte_clk);
191 clk_lp2hs = ns_to_cycle(ctx->clk_lp2hs, ctx->byte_clk);
192 dsi_datalane_hs2lp_config(ctx, data_hs2lp);
193 dsi_datalane_lp2hs_config(ctx, data_lp2hs);
194 dsi_clklane_hs2lp_config(ctx, clk_hs2lp);
195 dsi_clklane_lp2hs_config(ctx, clk_lp2hs);
196
197 dsi_power_enable(ctx, 1);
198 }
199
200 /**
201 * Close DSI Host driver
202 * - Free up resources and shutdown host controller and PHY
203 * @param dsi pointer to structure holding the DSI Host core information
204 * @return
205 */
> 206 void sprd_dsi_power_off(struct sprd_dsi *dsi)
207 {
208 struct dsi_context *ctx = &dsi->ctx;
209
210 dsi_int0_mask(ctx, 0xffffffff);
211 dsi_int1_mask(ctx, 0xffffffff);
212 dsi_power_enable(ctx, 0);
213 }
214
215 /**
216 * Configure DPI video interface
217 * - If not in burst mode, it will compute the video and null packet sizes
218 * according to necessity
219 * - Configure timers for data lanes and/or clock lane to return to LP when
220 * bandwidth is not filled by data
221 * @param dsi pointer to structure holding the DSI Host core information
222 * @param param pointer to video stream-to-send information
223 * @return error code
224 */
> 225 int sprd_dsi_dpi_video(struct sprd_dsi *dsi)
226 {
227 struct dsi_context *ctx = &dsi->ctx;
228 struct videomode *vm = &dsi->ctx.vm;
229 u16 Bpp_x100;
230 u16 video_size;
231 u32 ratio_x1000;
232 u16 null_pkt_size = 0;
233 u8 video_size_step;
234 u32 hs_to;
235 u32 total_bytes;
236 u32 bytes_per_chunk;
237 u32 chunks = 0;
238 u32 bytes_left = 0;
239 u32 chunk_overhead;
240 const u8 pkt_header = 6;
241 u8 coding;
242 int div;
243 u16 hline;
244
245 coding = fmt_to_coding(ctx->format);
246 video_size = round_video_size(coding, vm->hactive);
247 Bpp_x100 = calc_bytes_per_pixel_x100(coding);
248 video_size_step = calc_video_size_step(coding);
249 ratio_x1000 = ctx->byte_clk * 1000 / (vm->pixelclock / 1000);
250 hline = vm->hactive + vm->hsync_len + vm->hfront_porch +
251 vm->hback_porch;
252
253 dsi_power_enable(ctx, 0);
254 dsi_dpi_frame_ack_en(ctx, ctx->frame_ack_en);
255 dsi_dpi_color_coding(ctx, coding);
256 dsi_dpi_video_burst_mode(ctx, ctx->burst_mode);
257 dsi_dpi_sig_delay(ctx, 95 * hline * ratio_x1000 / 100000);
258 dsi_dpi_hline_time(ctx, hline * ratio_x1000 / 1000);
259 dsi_dpi_hsync_time(ctx, vm->hsync_len * ratio_x1000 / 1000);
260 dsi_dpi_hbp_time(ctx, vm->hback_porch * ratio_x1000 / 1000);
261 dsi_dpi_vact(ctx, vm->vactive);
262 dsi_dpi_vfp(ctx, vm->vfront_porch);
263 dsi_dpi_vbp(ctx, vm->vback_porch);
264 dsi_dpi_vsync(ctx, vm->vsync_len);
265 dsi_dpi_hporch_lp_en(ctx, 1);
266 dsi_dpi_vporch_lp_en(ctx, 1);
267
268 hs_to = (hline * vm->vactive) + (2 * Bpp_x100) / 100;
269 for (div = 0x80; (div < hs_to) && (div > 2); div--) {
270 if ((hs_to % div) == 0) {
271 dsi_timeout_clock_division(ctx, div);
272 dsi_lp_rx_timeout(ctx, hs_to / div);
273 dsi_hs_tx_timeout(ctx, hs_to / div);
274 break;
275 }
276 }
277
278 if (ctx->burst_mode == VIDEO_BURST_WITH_SYNC_PULSES) {
279 dsi_dpi_video_packet_size(ctx, video_size);
280 dsi_dpi_null_packet_size(ctx, 0);
281 dsi_dpi_chunk_num(ctx, 0);
282 } else {
283 /* non burst transmission */
284 null_pkt_size = 0;
285
286 /* bytes to be sent - first as one chunk */
287 bytes_per_chunk = vm->hactive * Bpp_x100 / 100 + pkt_header;
288
289 /* hline total bytes from the DPI interface */
290 total_bytes = (vm->hactive + vm->hfront_porch) *
291 ratio_x1000 / ctx->lanes / 1000;
292
293 /* check if the pixels actually fit on the DSI link */
294 if (total_bytes < bytes_per_chunk) {
295 DRM_ERROR("current resolution can not be set\n");
296 return -EINVAL;
297 }
298
299 chunk_overhead = total_bytes - bytes_per_chunk;
300
301 /* overhead higher than 1 -> enable multi packets */
302 if (chunk_overhead > 1) {
303
304 /* multi packets */
305 for (video_size = video_size_step;
306 video_size < vm->hactive;
307 video_size += video_size_step) {
308
309 if (vm->hactive * 1000 / video_size % 1000)
310 continue;
311
312 chunks = vm->hactive / video_size;
313 bytes_per_chunk = Bpp_x100 * video_size / 100
314 + pkt_header;
315 if (total_bytes >= (bytes_per_chunk * chunks)) {
316 bytes_left = total_bytes -
317 bytes_per_chunk * chunks;
318 break;
319 }
320 }
321
322 /* prevent overflow (unsigned - unsigned) */
323 if (bytes_left > (pkt_header * chunks)) {
324 null_pkt_size = (bytes_left -
325 pkt_header * chunks) / chunks;
326 /* avoid register overflow */
327 if (null_pkt_size > 1023)
328 null_pkt_size = 1023;
329 }
330
331 } else {
332
333 /* single packet */
334 chunks = 1;
335
336 /* must be a multiple of 4 except 18 loosely */
337 for (video_size = vm->hactive;
338 (video_size % video_size_step) != 0;
339 video_size++)
340 ;
341 }
342
343 dsi_dpi_video_packet_size(ctx, video_size);
344 dsi_dpi_null_packet_size(ctx, null_pkt_size);
345 dsi_dpi_chunk_num(ctx, chunks);
346 }
347
348 dsi_int0_mask(ctx, ctx->int0_mask);
349 dsi_int1_mask(ctx, ctx->int1_mask);
350 dsi_power_enable(ctx, 1);
351
352 return 0;
353 }
354
> 355 int sprd_dsi_edpi_video(struct sprd_dsi *dsi) 356 {
357 struct dsi_context *ctx = &dsi->ctx;
358 const u32 fifo_depth = 1096;
359 const u32 word_length = 4;
360 u32 hactive = ctx->vm.hactive;
361 u32 Bpp_x100;
362 u32 max_fifo_len;
363 u8 coding;
364
365 coding = fmt_to_coding(ctx->format);
366 Bpp_x100 = calc_bytes_per_pixel_x100(coding);
367 max_fifo_len = word_length * fifo_depth * 100 / Bpp_x100;
368
369 dsi_power_enable(ctx, 0);
370 dsi_dpi_color_coding(ctx, coding);
371 dsi_tear_effect_ack_en(ctx, ctx->te_ack_en);
372
373 if (max_fifo_len > hactive)
374 dsi_edpi_max_pkt_size(ctx, hactive);
375 else
376 dsi_edpi_max_pkt_size(ctx, max_fifo_len);
377
378 dsi_int0_mask(ctx, ctx->int0_mask);
379 dsi_int1_mask(ctx, ctx->int1_mask);
380 dsi_power_enable(ctx, 1);
381
382 return 0;
383 }
384
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
Quoted 2 lines · Kevin Tang
From: Kevin Tang <[email protected]>
Hm still no ack for dt bindings? We need that for merging.
Also what's the maintainer plan here? Imo best would be to put this into the drm-misc group maintainer model, with commit rights and all:
https://drm.pages.freedesktop.org/maintainer-tools/drm-misc.html
MAINTAINERS patch to do that would be good.
-Daniel
Quoted 120 lines
ChangeList:
v1:
1. only upstream modeset and atomic at first commit.
2. remove some unused code;
3. use alpha andblend_modeproperties;
3. add yaml support;
4. remove auto-adaptive panel driver;
5. bugfixv2:
1. add sprd crtc and plane module for KMS, preparing for multi crtc&encoder
2. remove gem drivers, use generic CMA handlers
3. remove redundant "module_init", all the sub modules loading by KMSv3:
1. multi crtc&encoder design have problem, so rollback to v1v4:
1. update to gcc-linaro-7.5.0
2. update to Linux 5.6-rc3
3. removepm_runtimesupport
4. addCOMPILE_TEST, remove unused kconfig
5. "drm_dev_put" ondrm_unbind
6. fix some naming convention issue
7. remove semaphore lock for crtc flip
8. remove static variablesv5:
1. optimize encoder and connector code implementation
2. use "platform_get_irq" and "platform_get_resource"
3. drop useless function return type, drop unless debug log
4. custom properties should be separate, so drop it
5. useDRM_XXXreplasepr_xxx
6. drop dsi&dphy hal callback ops
7. drop unless callback ops checking
8. add comments for sprd dpu structurev6:
1. Access registers via readl/writel
2. Checking for unsupported KMS properties (format, rotation,blend_mode, etc) onplane_checkops
3. Remove always true checks for dpu core opsKevin Tang (6):
dt-bindings: display: add Unisoc's drm master bindings drm/sprd: add Unisoc's drm kms master
dt-bindings: display: add Unisoc's dpu bindings drm/sprd: add Unisoc's drm display controller driver
dt-bindings: display: add Unisoc's mipi dsi&dphy bindings drm/sprd: add Unisoc's drm mipi dsi&dphy driver.../devicetree/bindings/display/sprd/dphy.yaml | 75 + .../devicetree/bindings/display/sprd/dpu.yaml | 82 ++ .../devicetree/bindings/display/sprd/drm.yaml | 36 + .../devicetree/bindings/display/sprd/dsi.yaml | 98 ++ drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/sprd/Kconfig | 12 + drivers/gpu/drm/sprd/Makefile | 13 + drivers/gpu/drm/sprd/disp_lib.c | 57 + drivers/gpu/drm/sprd/disp_lib.h | 16 + drivers/gpu/drm/sprd/dphy/Makefile | 7 + drivers/gpu/drm/sprd/dphy/pll/Makefile | 3 + drivers/gpu/drm/sprd/dphy/pll/megacores_sharkle.c | 473 +++++++ drivers/gpu/drm/sprd/dphy/sprd_dphy_api.c | 201 +++ drivers/gpu/drm/sprd/dphy/sprd_dphy_api.h | 22 + drivers/gpu/drm/sprd/dpu/Makefile | 3 + drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 503 +++++++ drivers/gpu/drm/sprd/dsi/Makefile | 8 + drivers/gpu/drm/sprd/dsi/core/Makefile | 4 + drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.c | 964 +++++++++++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.h | 1477 ++++++++++++++++++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.c | 328 +++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.h | 32 + drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c | 590 ++++++++ drivers/gpu/drm/sprd/dsi/sprd_dsi_api.h | 26 + drivers/gpu/drm/sprd/sprd_dphy.c | 209 +++ drivers/gpu/drm/sprd/sprd_dphy.h | 50 + drivers/gpu/drm/sprd/sprd_dpu.c | 668 +++++++++ drivers/gpu/drm/sprd/sprd_dpu.h | 190 +++ drivers/gpu/drm/sprd/sprd_drm.c | 227 +++ drivers/gpu/drm/sprd/sprd_drm.h | 18 + drivers/gpu/drm/sprd/sprd_dsi.c | 571 ++++++++ drivers/gpu/drm/sprd/sprd_dsi.h | 108 ++ 33 files changed, 7074 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/dphy.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/dpu.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/drm.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/dsi.yaml create mode 100644 drivers/gpu/drm/sprd/Kconfig create mode 100644 drivers/gpu/drm/sprd/Makefile create mode 100644 drivers/gpu/drm/sprd/disp_lib.c create mode 100644 drivers/gpu/drm/sprd/disp_lib.h create mode 100644 drivers/gpu/drm/sprd/dphy/Makefile create mode 100644 drivers/gpu/drm/sprd/dphy/pll/Makefile create mode 100644 drivers/gpu/drm/sprd/dphy/pll/megacores_sharkle.c create mode 100644 drivers/gpu/drm/sprd/dphy/sprd_dphy_api.c create mode 100644 drivers/gpu/drm/sprd/dphy/sprd_dphy_api.h create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c create mode 100644 drivers/gpu/drm/sprd/dsi/Makefile create mode 100644 drivers/gpu/drm/sprd/dsi/core/Makefile create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.c create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.h create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.c create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.h create mode 100644 drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c create mode 100644 drivers/gpu/drm/sprd/dsi/sprd_dsi_api.h create mode 100644 drivers/gpu/drm/sprd/sprd_dphy.c create mode 100644 drivers/gpu/drm/sprd/sprd_dphy.h create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.h create mode 100644 drivers/gpu/drm/sprd/sprd_drm.c create mode 100644 drivers/gpu/drm/sprd/sprd_drm.h create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.c create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.h--
2.7.4
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Quoted 6 lines · Daniel Vetter
Quoted 2 lines · Kevin Tang
From: Kevin Tang <[email protected]>
Hm still no ack for dt bindings? We need that for merging.
If it's not sent to the DT list so it gets into patchwork that's never going to happen. Nor are any semi-automated tests of the schema.
Quoted 130 lines
Also what's the maintainer plan here? Imo best would be to put this into the drm-misc group maintainer model, with commit rights and all:
https://drm.pages.freedesktop.org/maintainer-tools/drm-misc.html
MAINTAINERSpatch to do that would be good.
-DanielQuoted 117 lines
ChangeList:
v1:
1. only upstream modeset and atomic at first commit.
2. remove some unused code;
3. use alpha andblend_modeproperties;
3. add yaml support;
4. remove auto-adaptive panel driver;
5. bugfixv2:
1. add sprd crtc and plane module for KMS, preparing for multi crtc&encoder
2. remove gem drivers, use generic CMA handlers
3. remove redundant "module_init", all the sub modules loading by KMSv3:
1. multi crtc&encoder design have problem, so rollback to v1v4:
1. update to gcc-linaro-7.5.0
2. update to Linux 5.6-rc3
3. removepm_runtimesupport
4. addCOMPILE_TEST, remove unused kconfig
5. "drm_dev_put" ondrm_unbind
6. fix some naming convention issue
7. remove semaphore lock for crtc flip
8. remove static variablesv5:
1. optimize encoder and connector code implementation
2. use "platform_get_irq" and "platform_get_resource"
3. drop useless function return type, drop unless debug log
4. custom properties should be separate, so drop it
5. useDRM_XXXreplasepr_xxx
6. drop dsi&dphy hal callback ops
7. drop unless callback ops checking
8. add comments for sprd dpu structurev6:
1. Access registers via readl/writel
2. Checking for unsupported KMS properties (format, rotation,blend_mode, etc) onplane_checkops
3. Remove always true checks for dpu core opsKevin Tang (6):
dt-bindings: display: add Unisoc's drm master bindings drm/sprd: add Unisoc's drm kms master
dt-bindings: display: add Unisoc's dpu bindings drm/sprd: add Unisoc's drm display controller driver
dt-bindings: display: add Unisoc's mipi dsi&dphy bindings drm/sprd: add Unisoc's drm mipi dsi&dphy driver.../devicetree/bindings/display/sprd/dphy.yaml | 75 + .../devicetree/bindings/display/sprd/dpu.yaml | 82 ++ .../devicetree/bindings/display/sprd/drm.yaml | 36 + .../devicetree/bindings/display/sprd/dsi.yaml | 98 ++ drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/sprd/Kconfig | 12 + drivers/gpu/drm/sprd/Makefile | 13 + drivers/gpu/drm/sprd/disp_lib.c | 57 + drivers/gpu/drm/sprd/disp_lib.h | 16 + drivers/gpu/drm/sprd/dphy/Makefile | 7 + drivers/gpu/drm/sprd/dphy/pll/Makefile | 3 + drivers/gpu/drm/sprd/dphy/pll/megacores_sharkle.c | 473 +++++++ drivers/gpu/drm/sprd/dphy/sprd_dphy_api.c | 201 +++ drivers/gpu/drm/sprd/dphy/sprd_dphy_api.h | 22 + drivers/gpu/drm/sprd/dpu/Makefile | 3 + drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 503 +++++++ drivers/gpu/drm/sprd/dsi/Makefile | 8 + drivers/gpu/drm/sprd/dsi/core/Makefile | 4 + drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.c | 964 +++++++++++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.h | 1477 ++++++++++++++++++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.c | 328 +++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.h | 32 + drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c | 590 ++++++++ drivers/gpu/drm/sprd/dsi/sprd_dsi_api.h | 26 + drivers/gpu/drm/sprd/sprd_dphy.c | 209 +++ drivers/gpu/drm/sprd/sprd_dphy.h | 50 + drivers/gpu/drm/sprd/sprd_dpu.c | 668 +++++++++ drivers/gpu/drm/sprd/sprd_dpu.h | 190 +++ drivers/gpu/drm/sprd/sprd_drm.c | 227 +++ drivers/gpu/drm/sprd/sprd_drm.h | 18 + drivers/gpu/drm/sprd/sprd_dsi.c | 571 ++++++++ drivers/gpu/drm/sprd/sprd_dsi.h | 108 ++ 33 files changed, 7074 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/dphy.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/dpu.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/drm.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/dsi.yaml create mode 100644 drivers/gpu/drm/sprd/Kconfig create mode 100644 drivers/gpu/drm/sprd/Makefile create mode 100644 drivers/gpu/drm/sprd/disp_lib.c create mode 100644 drivers/gpu/drm/sprd/disp_lib.h create mode 100644 drivers/gpu/drm/sprd/dphy/Makefile create mode 100644 drivers/gpu/drm/sprd/dphy/pll/Makefile create mode 100644 drivers/gpu/drm/sprd/dphy/pll/megacores_sharkle.c create mode 100644 drivers/gpu/drm/sprd/dphy/sprd_dphy_api.c create mode 100644 drivers/gpu/drm/sprd/dphy/sprd_dphy_api.h create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c create mode 100644 drivers/gpu/drm/sprd/dsi/Makefile create mode 100644 drivers/gpu/drm/sprd/dsi/core/Makefile create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.c create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.h create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.c create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.h create mode 100644 drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c create mode 100644 drivers/gpu/drm/sprd/dsi/sprd_dsi_api.h create mode 100644 drivers/gpu/drm/sprd/sprd_dphy.c create mode 100644 drivers/gpu/drm/sprd/sprd_dphy.h create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.h create mode 100644 drivers/gpu/drm/sprd/sprd_drm.c create mode 100644 drivers/gpu/drm/sprd/sprd_drm.h create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.c create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.hQuoted 3 lines
--
2.7.4
Quoted 4 lines
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Hi Kevin.
Thanks for submitting this set of drivers.
To better review the pataches can you please give some kind of high level overview.
An ascii block diagram that identifies all the relevant blocks and how they relate would be great.
This makes it easier to verify if the right modelling is used.
Sam
Quoted 109 lines · Kevin Tang
From: Kevin Tang <[email protected]>
ChangeList:
v1:
1. only upstream modeset and atomic at first commit.
2. remove some unused code;
3. use alpha andblend_modeproperties;
3. add yaml support;
4. remove auto-adaptive panel driver;
5. bugfixv2:
1. add sprd crtc and plane module for KMS, preparing for multi crtc&encoder
2. remove gem drivers, use generic CMA handlers
3. remove redundant "module_init", all the sub modules loading by KMSv3:
1. multi crtc&encoder design have problem, so rollback to v1v4:
1. update to gcc-linaro-7.5.0
2. update to Linux 5.6-rc3
3. removepm_runtimesupport
4. addCOMPILE_TEST, remove unused kconfig
5. "drm_dev_put" ondrm_unbind
6. fix some naming convention issue
7. remove semaphore lock for crtc flip
8. remove static variablesv5:
1. optimize encoder and connector code implementation
2. use "platform_get_irq" and "platform_get_resource"
3. drop useless function return type, drop unless debug log
4. custom properties should be separate, so drop it
5. useDRM_XXXreplasepr_xxx
6. drop dsi&dphy hal callback ops
7. drop unless callback ops checking
8. add comments for sprd dpu structurev6:
1. Access registers via readl/writel
2. Checking for unsupported KMS properties (format, rotation,blend_mode, etc) onplane_checkops
3. Remove always true checks for dpu core opsKevin Tang (6):
dt-bindings: display: add Unisoc's drm master bindings drm/sprd: add Unisoc's drm kms master
dt-bindings: display: add Unisoc's dpu bindings drm/sprd: add Unisoc's drm display controller driver
dt-bindings: display: add Unisoc's mipi dsi&dphy bindings drm/sprd: add Unisoc's drm mipi dsi&dphy driver.../devicetree/bindings/display/sprd/dphy.yaml | 75 + .../devicetree/bindings/display/sprd/dpu.yaml | 82 ++ .../devicetree/bindings/display/sprd/drm.yaml | 36 + .../devicetree/bindings/display/sprd/dsi.yaml | 98 ++ drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/sprd/Kconfig | 12 + drivers/gpu/drm/sprd/Makefile | 13 + drivers/gpu/drm/sprd/disp_lib.c | 57 + drivers/gpu/drm/sprd/disp_lib.h | 16 + drivers/gpu/drm/sprd/dphy/Makefile | 7 + drivers/gpu/drm/sprd/dphy/pll/Makefile | 3 + drivers/gpu/drm/sprd/dphy/pll/megacores_sharkle.c | 473 +++++++ drivers/gpu/drm/sprd/dphy/sprd_dphy_api.c | 201 +++ drivers/gpu/drm/sprd/dphy/sprd_dphy_api.h | 22 + drivers/gpu/drm/sprd/dpu/Makefile | 3 + drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 503 +++++++ drivers/gpu/drm/sprd/dsi/Makefile | 8 + drivers/gpu/drm/sprd/dsi/core/Makefile | 4 + drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.c | 964 +++++++++++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.h | 1477 ++++++++++++++++++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.c | 328 +++++ drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.h | 32 + drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c | 590 ++++++++ drivers/gpu/drm/sprd/dsi/sprd_dsi_api.h | 26 + drivers/gpu/drm/sprd/sprd_dphy.c | 209 +++ drivers/gpu/drm/sprd/sprd_dphy.h | 50 + drivers/gpu/drm/sprd/sprd_dpu.c | 668 +++++++++ drivers/gpu/drm/sprd/sprd_dpu.h | 190 +++ drivers/gpu/drm/sprd/sprd_drm.c | 227 +++ drivers/gpu/drm/sprd/sprd_drm.h | 18 + drivers/gpu/drm/sprd/sprd_dsi.c | 571 ++++++++ drivers/gpu/drm/sprd/sprd_dsi.h | 108 ++ 33 files changed, 7074 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/dphy.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/dpu.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/drm.yaml create mode 100644 Documentation/devicetree/bindings/display/sprd/dsi.yaml create mode 100644 drivers/gpu/drm/sprd/Kconfig create mode 100644 drivers/gpu/drm/sprd/Makefile create mode 100644 drivers/gpu/drm/sprd/disp_lib.c create mode 100644 drivers/gpu/drm/sprd/disp_lib.h create mode 100644 drivers/gpu/drm/sprd/dphy/Makefile create mode 100644 drivers/gpu/drm/sprd/dphy/pll/Makefile create mode 100644 drivers/gpu/drm/sprd/dphy/pll/megacores_sharkle.c create mode 100644 drivers/gpu/drm/sprd/dphy/sprd_dphy_api.c create mode 100644 drivers/gpu/drm/sprd/dphy/sprd_dphy_api.h create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c create mode 100644 drivers/gpu/drm/sprd/dsi/Makefile create mode 100644 drivers/gpu/drm/sprd/dsi/core/Makefile create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.c create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0.h create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.c create mode 100644 drivers/gpu/drm/sprd/dsi/core/dsi_ctrl_r1p0_ppi.h create mode 100644 drivers/gpu/drm/sprd/dsi/sprd_dsi_api.c create mode 100644 drivers/gpu/drm/sprd/dsi/sprd_dsi_api.h
Quoted 16 lines
create mode 100644 drivers/gpu/drm/sprd/sprd_dphy.c create mode 100644 drivers/gpu/drm/sprd/sprd_dphy.h create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.h create mode 100644 drivers/gpu/drm/sprd/sprd_drm.c create mode 100644 drivers/gpu/drm/sprd/sprd_drm.h create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.c create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.hSignature · 6 lines
2.7.4 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel