All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] drm/sun4i: Support the Display Engine frontend
@ 2017-12-13 15:33   ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni, thomas

Hi,

This is a first serie to enable the display engine frontend.

This hardware block is found in the first generation Display Engine from
Allwinner. Its role is to implement more advanced features that the
associated backend, even though the backend alone can be used (and was used
so far) for basic composition.

Among those features, we will find hardware scaling, that is supported in
this serie, colorspace conversions, or more exotic formats support such as
the one output by the VPU.

Let me know what you think,
Maxime

Maxime Ripard (8):
  drm/sun4i: backend: Move line stride setup to buffer setup function
  drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
  drm/sun4i: sun4i_layer: Add a custom plane state
  drm/sun4i: crtc: Add a custom crtc atomic_check
  drm/sun4i: Add a driver for the display frontend
  drm/sun4i: sun4i_layer: Wire in the frontend
  drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
  ARM: dts: sun8i: a33 Enable our display frontend

 arch/arm/boot/dts/sun8i-a33.dtsi       |   1 +-
 drivers/gpu/drm/sun4i/Makefile         |   3 +-
 drivers/gpu/drm/sun4i/sun4i_backend.c  | 139 +++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h  |   6 +-
 drivers/gpu/drm/sun4i/sun4i_crtc.c     |  14 +-
 drivers/gpu/drm/sun4i/sun4i_drv.c      |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
 drivers/gpu/drm/sun4i/sun4i_layer.c    |  75 ++++-
 drivers/gpu/drm/sun4i/sun4i_layer.h    |  11 +-
 drivers/gpu/drm/sun4i/sunxi_engine.h   |   2 +-
 12 files changed, 727 insertions(+), 20 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h

base-commit: 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323
-- 
git-series 0.9.1

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

* [PATCH 0/8] drm/sun4i: Support the Display Engine frontend
@ 2017-12-13 15:33   ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This is a first serie to enable the display engine frontend.

This hardware block is found in the first generation Display Engine from
Allwinner. Its role is to implement more advanced features that the
associated backend, even though the backend alone can be used (and was used
so far) for basic composition.

Among those features, we will find hardware scaling, that is supported in
this serie, colorspace conversions, or more exotic formats support such as
the one output by the VPU.

Let me know what you think,
Maxime

Maxime Ripard (8):
  drm/sun4i: backend: Move line stride setup to buffer setup function
  drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
  drm/sun4i: sun4i_layer: Add a custom plane state
  drm/sun4i: crtc: Add a custom crtc atomic_check
  drm/sun4i: Add a driver for the display frontend
  drm/sun4i: sun4i_layer: Wire in the frontend
  drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
  ARM: dts: sun8i: a33 Enable our display frontend

 arch/arm/boot/dts/sun8i-a33.dtsi       |   1 +-
 drivers/gpu/drm/sun4i/Makefile         |   3 +-
 drivers/gpu/drm/sun4i/sun4i_backend.c  | 139 +++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h  |   6 +-
 drivers/gpu/drm/sun4i/sun4i_crtc.c     |  14 +-
 drivers/gpu/drm/sun4i/sun4i_drv.c      |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
 drivers/gpu/drm/sun4i/sun4i_layer.c    |  75 ++++-
 drivers/gpu/drm/sun4i/sun4i_layer.h    |  11 +-
 drivers/gpu/drm/sun4i/sunxi_engine.h   |   2 +-
 12 files changed, 727 insertions(+), 20 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h

base-commit: 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323
-- 
git-series 0.9.1

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

* [PATCH 0/8] drm/sun4i: Support the Display Engine frontend
@ 2017-12-13 15:33   ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

Hi,

This is a first serie to enable the display engine frontend.

This hardware block is found in the first generation Display Engine from
Allwinner. Its role is to implement more advanced features that the
associated backend, even though the backend alone can be used (and was used
so far) for basic composition.

Among those features, we will find hardware scaling, that is supported in
this serie, colorspace conversions, or more exotic formats support such as
the one output by the VPU.

Let me know what you think,
Maxime

Maxime Ripard (8):
  drm/sun4i: backend: Move line stride setup to buffer setup function
  drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
  drm/sun4i: sun4i_layer: Add a custom plane state
  drm/sun4i: crtc: Add a custom crtc atomic_check
  drm/sun4i: Add a driver for the display frontend
  drm/sun4i: sun4i_layer: Wire in the frontend
  drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
  ARM: dts: sun8i: a33 Enable our display frontend

 arch/arm/boot/dts/sun8i-a33.dtsi       |   1 +-
 drivers/gpu/drm/sun4i/Makefile         |   3 +-
 drivers/gpu/drm/sun4i/sun4i_backend.c  | 139 +++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h  |   6 +-
 drivers/gpu/drm/sun4i/sun4i_crtc.c     |  14 +-
 drivers/gpu/drm/sun4i/sun4i_drv.c      |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
 drivers/gpu/drm/sun4i/sun4i_layer.c    |  75 ++++-
 drivers/gpu/drm/sun4i/sun4i_layer.h    |  11 +-
 drivers/gpu/drm/sun4i/sunxi_engine.h   |   2 +-
 12 files changed, 727 insertions(+), 20 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h

base-commit: 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323
-- 
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH 1/8] drm/sun4i: backend: Move line stride setup to buffer setup function
  2017-12-13 15:33   ` Maxime Ripard
  (?)
@ 2017-12-13 15:33     ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni, thomas

Setup the line stride in the buffer setup function, since it's tied to the
buffer itself, and is not needed when we do not set the buffer in the
backend.

This is for example the case when using the frontend and then routing its
output to the backend.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 847eecbe4d14..c99d1a7e815a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -141,7 +141,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
 				     int layer, struct drm_plane *plane)
 {
 	struct drm_plane_state *state = plane->state;
-	struct drm_framebuffer *fb = state->fb;
 
 	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
 
@@ -153,12 +152,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
 						   state->crtc_h));
 	}
 
-	/* Set the line width */
-	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
-	regmap_write(backend->engine.regs,
-		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
-		     fb->pitches[0] * 8);
-
 	/* Set height and width */
 	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
 			 state->crtc_w, state->crtc_h);
@@ -218,6 +211,13 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	u32 lo_paddr, hi_paddr;
 	dma_addr_t paddr;
 
+	/* Set the line width */
+	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
+	regmap_write(backend->engine.regs,
+		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
+		     fb->pitches[0] * 8);
+
+
 	/* Get the start of the displayed memory */
 	paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
 	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
-- 
git-series 0.9.1

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

* [PATCH 1/8] drm/sun4i: backend: Move line stride setup to buffer setup function
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

Setup the line stride in the buffer setup function, since it's tied to the
buffer itself, and is not needed when we do not set the buffer in the
backend.

This is for example the case when using the frontend and then routing its
output to the backend.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 847eecbe4d14..c99d1a7e815a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -141,7 +141,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
 				     int layer, struct drm_plane *plane)
 {
 	struct drm_plane_state *state = plane->state;
-	struct drm_framebuffer *fb = state->fb;
 
 	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
 
@@ -153,12 +152,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
 						   state->crtc_h));
 	}
 
-	/* Set the line width */
-	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
-	regmap_write(backend->engine.regs,
-		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
-		     fb->pitches[0] * 8);
-
 	/* Set height and width */
 	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
 			 state->crtc_w, state->crtc_h);
@@ -218,6 +211,13 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	u32 lo_paddr, hi_paddr;
 	dma_addr_t paddr;
 
+	/* Set the line width */
+	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
+	regmap_write(backend->engine.regs,
+		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
+		     fb->pitches[0] * 8);
+
+
 	/* Get the start of the displayed memory */
 	paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
 	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
-- 
git-series 0.9.1

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

* [PATCH 1/8] drm/sun4i: backend: Move line stride setup to buffer setup function
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

Setup the line stride in the buffer setup function, since it's tied to the
buffer itself, and is not needed when we do not set the buffer in the
backend.

This is for example the case when using the frontend and then routing its
output to the backend.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 847eecbe4d14..c99d1a7e815a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -141,7 +141,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
 				     int layer, struct drm_plane *plane)
 {
 	struct drm_plane_state *state = plane->state;
-	struct drm_framebuffer *fb = state->fb;
 
 	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
 
@@ -153,12 +152,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
 						   state->crtc_h));
 	}
 
-	/* Set the line width */
-	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
-	regmap_write(backend->engine.regs,
-		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
-		     fb->pitches[0] * 8);
-
 	/* Set height and width */
 	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
 			 state->crtc_w, state->crtc_h);
@@ -218,6 +211,13 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	u32 lo_paddr, hi_paddr;
 	dma_addr_t paddr;
 
+	/* Set the line width */
+	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
+	regmap_write(backend->engine.regs,
+		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
+		     fb->pitches[0] * 8);
+
+
 	/* Get the start of the displayed memory */
 	paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
 	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
-- 
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH 2/8] drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
  2017-12-13 15:33   ` Maxime Ripard
  (?)
@ 2017-12-13 15:33     ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni, thomas

The function converting the DRM format to its equivalent in the backend
registers was assuming that we were having a plane.

However, we might want to use that function when setting up a plane using
the frontend, in which case we will not have a plane associated to the
backend's layer. Yet, we still need to setup the format to the one output
by the frontend.

Test for NULL plane pointers before referencing them, so that we can work
around it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index c99d1a7e815a..f971d3fb5ee4 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -93,7 +93,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
 static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
 					     u32 format, u32 *mode)
 {
-	if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
+	if (plane && (plane->type == DRM_PLANE_TYPE_PRIMARY) &&
 	    (format == DRM_FORMAT_ARGB8888))
 		format = DRM_FORMAT_XRGB8888;
 
-- 
git-series 0.9.1

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

* [PATCH 2/8] drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

The function converting the DRM format to its equivalent in the backend
registers was assuming that we were having a plane.

However, we might want to use that function when setting up a plane using
the frontend, in which case we will not have a plane associated to the
backend's layer. Yet, we still need to setup the format to the one output
by the frontend.

Test for NULL plane pointers before referencing them, so that we can work
around it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index c99d1a7e815a..f971d3fb5ee4 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -93,7 +93,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
 static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
 					     u32 format, u32 *mode)
 {
-	if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
+	if (plane && (plane->type == DRM_PLANE_TYPE_PRIMARY) &&
 	    (format == DRM_FORMAT_ARGB8888))
 		format = DRM_FORMAT_XRGB8888;
 
-- 
git-series 0.9.1

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

* [PATCH 2/8] drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

The function converting the DRM format to its equivalent in the backend
registers was assuming that we were having a plane.

However, we might want to use that function when setting up a plane using
the frontend, in which case we will not have a plane associated to the
backend's layer. Yet, we still need to setup the format to the one output
by the frontend.

Test for NULL plane pointers before referencing them, so that we can work
around it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index c99d1a7e815a..f971d3fb5ee4 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -93,7 +93,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
 static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
 					     u32 format, u32 *mode)
 {
-	if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
+	if (plane && (plane->type == DRM_PLANE_TYPE_PRIMARY) &&
 	    (format == DRM_FORMAT_ARGB8888))
 		format = DRM_FORMAT_XRGB8888;
 
-- 
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH 3/8] drm/sun4i: sun4i_layer: Add a custom plane state
  2017-12-13 15:33   ` Maxime Ripard
  (?)
@ 2017-12-13 15:33     ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni, thomas

We will need to store some additional data in the future to the state.
Create a custom plane state that will embed those data, in order to store
the pipe or whether or not that plane should use the frontend.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_layer.c | 48 ++++++++++++++++++++++++++++--
 drivers/gpu/drm/sun4i/sun4i_layer.h | 10 ++++++-
 2 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 7bddf12548d3..c3afcf888906 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -25,6 +25,48 @@ struct sun4i_plane_desc {
 	       uint32_t                nformats;
 };
 
+static void sun4i_backend_layer_reset(struct drm_plane *plane)
+{
+	struct sun4i_layer_state *state;
+
+	if (plane->state) {
+		state = state_to_sun4i_layer_state(plane->state);
+
+		__drm_atomic_helper_plane_destroy_state(&state->state);
+		kfree(state);
+		plane->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state) {
+		plane->state = &state->state;
+		plane->state->plane = plane;
+	}
+}
+
+static struct drm_plane_state *
+sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
+{
+	struct sun4i_layer_state *copy;
+
+	copy = kzalloc(sizeof(*copy), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
+
+	return &copy->state;
+}
+
+static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
+					      struct drm_plane_state *state)
+{
+	struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
+
+	__drm_atomic_helper_plane_destroy_state(state);
+	kfree(s_state);
+}
+
 static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
 					       struct drm_plane_state *old_state)
 {
@@ -52,11 +94,11 @@ static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
 };
 
 static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
-	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
-	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state	= sun4i_backend_layer_destroy_state,
+	.atomic_duplicate_state	= sun4i_backend_layer_duplicate_state,
 	.destroy		= drm_plane_cleanup,
 	.disable_plane		= drm_atomic_helper_disable_plane,
-	.reset			= drm_atomic_helper_plane_reset,
+	.reset			= sun4i_backend_layer_reset,
 	.update_plane		= drm_atomic_helper_update_plane,
 };
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
index 4e84f438b346..d2c19348d1b0 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -22,12 +22,22 @@ struct sun4i_layer {
 	int			id;
 };
 
+struct sun4i_layer_state {
+	struct drm_plane_state	state;
+};
+
 static inline struct sun4i_layer *
 plane_to_sun4i_layer(struct drm_plane *plane)
 {
 	return container_of(plane, struct sun4i_layer, plane);
 }
 
+static inline struct sun4i_layer_state *
+state_to_sun4i_layer_state(struct drm_plane_state *state)
+{
+	return container_of(state, struct sun4i_layer_state, state);
+}
+
 struct drm_plane **sun4i_layers_init(struct drm_device *drm,
 				     struct sunxi_engine *engine);
 
-- 
git-series 0.9.1

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

* [PATCH 3/8] drm/sun4i: sun4i_layer: Add a custom plane state
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

We will need to store some additional data in the future to the state.
Create a custom plane state that will embed those data, in order to store
the pipe or whether or not that plane should use the frontend.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_layer.c | 48 ++++++++++++++++++++++++++++--
 drivers/gpu/drm/sun4i/sun4i_layer.h | 10 ++++++-
 2 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 7bddf12548d3..c3afcf888906 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -25,6 +25,48 @@ struct sun4i_plane_desc {
 	       uint32_t                nformats;
 };
 
+static void sun4i_backend_layer_reset(struct drm_plane *plane)
+{
+	struct sun4i_layer_state *state;
+
+	if (plane->state) {
+		state = state_to_sun4i_layer_state(plane->state);
+
+		__drm_atomic_helper_plane_destroy_state(&state->state);
+		kfree(state);
+		plane->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state) {
+		plane->state = &state->state;
+		plane->state->plane = plane;
+	}
+}
+
+static struct drm_plane_state *
+sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
+{
+	struct sun4i_layer_state *copy;
+
+	copy = kzalloc(sizeof(*copy), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
+
+	return &copy->state;
+}
+
+static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
+					      struct drm_plane_state *state)
+{
+	struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
+
+	__drm_atomic_helper_plane_destroy_state(state);
+	kfree(s_state);
+}
+
 static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
 					       struct drm_plane_state *old_state)
 {
@@ -52,11 +94,11 @@ static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
 };
 
 static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
-	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
-	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state	= sun4i_backend_layer_destroy_state,
+	.atomic_duplicate_state	= sun4i_backend_layer_duplicate_state,
 	.destroy		= drm_plane_cleanup,
 	.disable_plane		= drm_atomic_helper_disable_plane,
-	.reset			= drm_atomic_helper_plane_reset,
+	.reset			= sun4i_backend_layer_reset,
 	.update_plane		= drm_atomic_helper_update_plane,
 };
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
index 4e84f438b346..d2c19348d1b0 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -22,12 +22,22 @@ struct sun4i_layer {
 	int			id;
 };
 
+struct sun4i_layer_state {
+	struct drm_plane_state	state;
+};
+
 static inline struct sun4i_layer *
 plane_to_sun4i_layer(struct drm_plane *plane)
 {
 	return container_of(plane, struct sun4i_layer, plane);
 }
 
+static inline struct sun4i_layer_state *
+state_to_sun4i_layer_state(struct drm_plane_state *state)
+{
+	return container_of(state, struct sun4i_layer_state, state);
+}
+
 struct drm_plane **sun4i_layers_init(struct drm_device *drm,
 				     struct sunxi_engine *engine);
 
-- 
git-series 0.9.1

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

* [PATCH 3/8] drm/sun4i: sun4i_layer: Add a custom plane state
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

We will need to store some additional data in the future to the state.
Create a custom plane state that will embed those data, in order to store
the pipe or whether or not that plane should use the frontend.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_layer.c | 48 ++++++++++++++++++++++++++++--
 drivers/gpu/drm/sun4i/sun4i_layer.h | 10 ++++++-
 2 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 7bddf12548d3..c3afcf888906 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -25,6 +25,48 @@ struct sun4i_plane_desc {
 	       uint32_t                nformats;
 };
 
+static void sun4i_backend_layer_reset(struct drm_plane *plane)
+{
+	struct sun4i_layer_state *state;
+
+	if (plane->state) {
+		state = state_to_sun4i_layer_state(plane->state);
+
+		__drm_atomic_helper_plane_destroy_state(&state->state);
+		kfree(state);
+		plane->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state) {
+		plane->state = &state->state;
+		plane->state->plane = plane;
+	}
+}
+
+static struct drm_plane_state *
+sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
+{
+	struct sun4i_layer_state *copy;
+
+	copy = kzalloc(sizeof(*copy), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
+
+	return &copy->state;
+}
+
+static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
+					      struct drm_plane_state *state)
+{
+	struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
+
+	__drm_atomic_helper_plane_destroy_state(state);
+	kfree(s_state);
+}
+
 static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
 					       struct drm_plane_state *old_state)
 {
@@ -52,11 +94,11 @@ static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
 };
 
 static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
-	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
-	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state	= sun4i_backend_layer_destroy_state,
+	.atomic_duplicate_state	= sun4i_backend_layer_duplicate_state,
 	.destroy		= drm_plane_cleanup,
 	.disable_plane		= drm_atomic_helper_disable_plane,
-	.reset			= drm_atomic_helper_plane_reset,
+	.reset			= sun4i_backend_layer_reset,
 	.update_plane		= drm_atomic_helper_update_plane,
 };
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
index 4e84f438b346..d2c19348d1b0 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -22,12 +22,22 @@ struct sun4i_layer {
 	int			id;
 };
 
+struct sun4i_layer_state {
+	struct drm_plane_state	state;
+};
+
 static inline struct sun4i_layer *
 plane_to_sun4i_layer(struct drm_plane *plane)
 {
 	return container_of(plane, struct sun4i_layer, plane);
 }
 
+static inline struct sun4i_layer_state *
+state_to_sun4i_layer_state(struct drm_plane_state *state)
+{
+	return container_of(state, struct sun4i_layer_state, state);
+}
+
 struct drm_plane **sun4i_layers_init(struct drm_device *drm,
 				     struct sunxi_engine *engine);
 
-- 
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH 4/8] drm/sun4i: crtc: Add a custom crtc atomic_check
  2017-12-13 15:33   ` Maxime Ripard
  (?)
@ 2017-12-13 15:33     ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni, thomas

We have some restrictions on what the planes and CRTC can provide that are
tied to only one generation of display engines.

For example, on the first generation, we can only have one YUV plane or one
plane that uses the frontend output.

Let's allow our engines to provide an atomic_check callback to validate the
current configuration.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_crtc.c   | 14 ++++++++++++++
 drivers/gpu/drm/sun4i/sunxi_engine.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 5decae0069d0..2a565325714f 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -46,6 +46,19 @@ static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
 	return NULL;
 }
 
+static int sun4i_crtc_atomic_check(struct drm_crtc *crtc,
+				    struct drm_crtc_state *state)
+{
+	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
+	struct sunxi_engine *engine = scrtc->engine;
+	int ret = 0;
+
+	if (engine && engine->ops && engine->ops->atomic_check)
+		ret = engine->ops->atomic_check(engine, state);
+
+	return ret;
+}
+
 static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 				    struct drm_crtc_state *old_state)
 {
@@ -125,6 +138,7 @@ static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
 }
 
 static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
+	.atomic_check	= sun4i_crtc_atomic_check,
 	.atomic_begin	= sun4i_crtc_atomic_begin,
 	.atomic_flush	= sun4i_crtc_atomic_flush,
 	.atomic_enable	= sun4i_crtc_atomic_enable,
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index 4cb70ae65c79..42655230aeba 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -16,6 +16,8 @@ struct drm_device;
 struct sunxi_engine;
 
 struct sunxi_engine_ops {
+	int (*atomic_check)(struct sunxi_engine *engine,
+			    struct drm_crtc_state *state);
 	void (*commit)(struct sunxi_engine *engine);
 	struct drm_plane **(*layers_init)(struct drm_device *drm,
 					  struct sunxi_engine *engine);
-- 
git-series 0.9.1

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

* [PATCH 4/8] drm/sun4i: crtc: Add a custom crtc atomic_check
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

We have some restrictions on what the planes and CRTC can provide that are
tied to only one generation of display engines.

For example, on the first generation, we can only have one YUV plane or one
plane that uses the frontend output.

Let's allow our engines to provide an atomic_check callback to validate the
current configuration.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_crtc.c   | 14 ++++++++++++++
 drivers/gpu/drm/sun4i/sunxi_engine.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 5decae0069d0..2a565325714f 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -46,6 +46,19 @@ static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
 	return NULL;
 }
 
+static int sun4i_crtc_atomic_check(struct drm_crtc *crtc,
+				    struct drm_crtc_state *state)
+{
+	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
+	struct sunxi_engine *engine = scrtc->engine;
+	int ret = 0;
+
+	if (engine && engine->ops && engine->ops->atomic_check)
+		ret = engine->ops->atomic_check(engine, state);
+
+	return ret;
+}
+
 static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 				    struct drm_crtc_state *old_state)
 {
@@ -125,6 +138,7 @@ static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
 }
 
 static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
+	.atomic_check	= sun4i_crtc_atomic_check,
 	.atomic_begin	= sun4i_crtc_atomic_begin,
 	.atomic_flush	= sun4i_crtc_atomic_flush,
 	.atomic_enable	= sun4i_crtc_atomic_enable,
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index 4cb70ae65c79..42655230aeba 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -16,6 +16,8 @@ struct drm_device;
 struct sunxi_engine;
 
 struct sunxi_engine_ops {
+	int (*atomic_check)(struct sunxi_engine *engine,
+			    struct drm_crtc_state *state);
 	void (*commit)(struct sunxi_engine *engine);
 	struct drm_plane **(*layers_init)(struct drm_device *drm,
 					  struct sunxi_engine *engine);
-- 
git-series 0.9.1

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

* [PATCH 4/8] drm/sun4i: crtc: Add a custom crtc atomic_check
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

We have some restrictions on what the planes and CRTC can provide that are
tied to only one generation of display engines.

For example, on the first generation, we can only have one YUV plane or one
plane that uses the frontend output.

Let's allow our engines to provide an atomic_check callback to validate the
current configuration.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_crtc.c   | 14 ++++++++++++++
 drivers/gpu/drm/sun4i/sunxi_engine.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 5decae0069d0..2a565325714f 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -46,6 +46,19 @@ static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
 	return NULL;
 }
 
+static int sun4i_crtc_atomic_check(struct drm_crtc *crtc,
+				    struct drm_crtc_state *state)
+{
+	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
+	struct sunxi_engine *engine = scrtc->engine;
+	int ret = 0;
+
+	if (engine && engine->ops && engine->ops->atomic_check)
+		ret = engine->ops->atomic_check(engine, state);
+
+	return ret;
+}
+
 static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 				    struct drm_crtc_state *old_state)
 {
@@ -125,6 +138,7 @@ static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
 }
 
 static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
+	.atomic_check	= sun4i_crtc_atomic_check,
 	.atomic_begin	= sun4i_crtc_atomic_begin,
 	.atomic_flush	= sun4i_crtc_atomic_flush,
 	.atomic_enable	= sun4i_crtc_atomic_enable,
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index 4cb70ae65c79..42655230aeba 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -16,6 +16,8 @@ struct drm_device;
 struct sunxi_engine;
 
 struct sunxi_engine_ops {
+	int (*atomic_check)(struct sunxi_engine *engine,
+			    struct drm_crtc_state *state);
 	void (*commit)(struct sunxi_engine *engine);
 	struct drm_plane **(*layers_init)(struct drm_device *drm,
 					  struct sunxi_engine *engine);
-- 
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH 5/8] drm/sun4i: Add a driver for the display frontend
  2017-12-13 15:33   ` Maxime Ripard
  (?)
@ 2017-12-13 15:33     ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni, thomas

The display frontend is an hardware block that can be used to implement
some more advanced features like hardware scaling or colorspace
conversions. It can also be used to implement the output format of the VPU.

Let's create a minimal driver for it that will only enable the hardware
scaling features.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/Makefile         |   3 +-
 drivers/gpu/drm/sun4i/sun4i_backend.c  |   5 +-
 drivers/gpu/drm/sun4i/sun4i_backend.h  |   1 +-
 drivers/gpu/drm/sun4i/sun4i_drv.c      |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
 7 files changed, 500 insertions(+), 5 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 0c2f8c7facae..b660d82011f4 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 sun4i-backend-y			+= sun4i_backend.o sun4i_layer.o
+sun4i-frontend-y		+= sun4i_frontend.o
 
 sun4i-drm-y			+= sun4i_drv.o
 sun4i-drm-y			+= sun4i_framebuffer.o
@@ -21,6 +22,6 @@ obj-$(CONFIG_DRM_SUN4I)		+= sun4i-tcon.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
 
-obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o
+obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o sun4i-frontend.o
 obj-$(CONFIG_DRM_SUN4I_HDMI)	+= sun4i-drm-hdmi.o
 obj-$(CONFIG_DRM_SUN8I_MIXER)	+= sun8i-mixer.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index f971d3fb5ee4..e83e1fe43823 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -367,6 +367,11 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 	if (backend->engine.id < 0)
 		return backend->engine.id;
 
+	backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
+	if (IS_ERR(backend->frontend)) {
+		dev_err(dev, "Couldn't find matching frontend, frontend features disabled\n");
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	regs = devm_ioremap_resource(dev, res);
 	if (IS_ERR(regs))
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index ac3cc029f5cd..ba1410fd5410 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -145,6 +145,7 @@
 
 struct sun4i_backend {
 	struct sunxi_engine	engine;
+	struct sun4i_frontend	*frontend;
 
 	struct reset_control	*reset;
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 75c76cdd82bc..17bf9bfd98ba 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -98,6 +98,7 @@ static int sun4i_drv_bind(struct device *dev)
 		goto free_drm;
 	}
 	drm->dev_private = drv;
+	INIT_LIST_HEAD(&drv->frontend_list);
 	INIT_LIST_HEAD(&drv->engine_list);
 	INIT_LIST_HEAD(&drv->tcon_list);
 
@@ -239,9 +240,11 @@ static int sun4i_drv_add_endpoints(struct device *dev,
 	int count = 0;
 
 	/*
-	 * We don't support the frontend for now, so we will never
-	 * have a device bound. Just skip over it, but we still want
-	 * the rest our pipeline to be added.
+	 * The frontend has been disabled in all of our old device
+	 * trees. If we find a node that is the frontend and is
+	 * disabled, we should just follow through and parse its
+	 * child, but without adding it to the component list.
+	 * Otherwise, we obviously want to add it to the list.
 	 */
 	if (!sun4i_drv_node_is_frontend(node) &&
 	    !of_device_is_available(node))
@@ -254,7 +257,12 @@ static int sun4i_drv_add_endpoints(struct device *dev,
 	if (sun4i_drv_node_is_connector(node))
 		return 0;
 
-	if (!sun4i_drv_node_is_frontend(node)) {
+	/*
+	 * If the device is either just a regular device, or an
+	 * enabled frontend, we add it to our component list.
+	 */
+	if (!sun4i_drv_node_is_frontend(node) ||
+	    (sun4i_drv_node_is_frontend(node) && of_device_is_available(node))) {
 		/* Add current component */
 		DRM_DEBUG_DRIVER("Adding component %pOF\n", node);
 		drm_of_component_match_add(dev, match, compare_of, node);
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
index a960c89270cc..9c26a345f85c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.h
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
@@ -19,6 +19,7 @@
 
 struct sun4i_drv {
 	struct list_head	engine_list;
+	struct list_head	frontend_list;
 	struct list_head	tcon_list;
 
 	struct drm_fbdev_cma	*fbdev;
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
new file mode 100644
index 000000000000..1be0e86d1457
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+#include <drm/drmP.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include "sun4i_drv.h"
+#include "sun4i_frontend.h"
+
+static const u32 sun4i_frontend_vert_coef[32] = {
+	0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
+	0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
+	0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
+	0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
+	0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
+	0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
+	0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
+	0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
+};
+
+static const u32 sun4i_frontend_horz_coef[64] = {
+	0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
+	0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
+	0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
+	0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
+	0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
+	0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
+	0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
+	0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
+	0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
+	0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
+	0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
+	0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
+	0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
+	0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
+	0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
+	0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
+};
+
+static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
+{
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
+			     sun4i_frontend_horz_coef[2 * i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
+			     sun4i_frontend_horz_coef[2 * i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
+			     sun4i_frontend_horz_coef[2 * i + 1]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
+			     sun4i_frontend_horz_coef[2 * i + 1]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
+			     sun4i_frontend_vert_coef[i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
+			     sun4i_frontend_vert_coef[i]);
+	}
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, BIT(23), BIT(23));
+}
+
+int sun4i_frontend_init(struct sun4i_frontend *frontend)
+{
+	int ret;
+
+	if (atomic_read(&frontend->users))
+		return -EBUSY;
+
+	ret = reset_control_deassert(frontend->reset);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Couldn't deassert our reset line\n");
+		return ret;
+	}
+
+	clk_set_rate(frontend->mod_clk, 300000000);
+
+	clk_prepare_enable(frontend->bus_clk);
+	clk_prepare_enable(frontend->mod_clk);
+	clk_prepare_enable(frontend->ram_clk);
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
+			   SUN4I_FRONTEND_EN_EN,
+			   SUN4I_FRONTEND_EN_EN);
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
+			   SUN4I_FRONTEND_BYPASS_CSC_EN,
+			   SUN4I_FRONTEND_BYPASS_CSC_EN);
+
+	sun4i_frontend_scaler_init(frontend);
+
+	atomic_inc(&frontend->users);
+
+	return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_init);
+
+void sun4i_frontend_exit(struct sun4i_frontend *frontend)
+{
+	atomic_dec(&frontend->users);
+
+	clk_disable_unprepare(frontend->ram_clk);
+	clk_disable_unprepare(frontend->mod_clk);
+	clk_disable_unprepare(frontend->bus_clk);
+	reset_control_assert(frontend->reset);
+}
+EXPORT_SYMBOL(sun4i_frontend_exit);
+
+void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *gem;
+	dma_addr_t paddr;
+	int bpp;
+
+	/* Get the physical address of the buffer in memory */
+	gem = drm_fb_cma_get_gem_obj(fb, 0);
+
+	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
+
+	/* Set the line width */
+	DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
+		     fb->pitches[0]);
+
+	/* Compute the start of the displayed memory */
+	bpp = fb->format->cpp[0];
+	paddr = gem->paddr + fb->offsets[0];
+	paddr += (state->src_x >> 16) * bpp;
+	paddr += (state->src_y >> 16) * fb->pitches[0];
+
+	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
+}
+
+static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
+{
+	switch (fmt) {
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+		*val = 3;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
+{
+	switch (fmt) {
+	case DRM_FORMAT_ARGB8888:
+		*val = 2;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane, uint32_t out_fmt)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	u32 out_fmt_val;
+	u32 in_fmt_val;
+	int ret;
+
+	ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
+						     &in_fmt_val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid input format\n");
+		return ret;
+	}
+
+	ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid output format\n");
+		return ret;
+	}
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400);
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400);
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, 0x151);
+		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | */
+		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(5) | */
+		     /* SUN4I_FRONTEND_INPUT_FMT_PS(1)); */
+	regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, 0x82);
+		     /* SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1)); */
+
+	return 0;
+}
+
+void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
+				 struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+
+	/* Set height and width */
+	DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
+			 state->crtc_w, state->crtc_h);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
+		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
+					   state->src_w >> 16));
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
+		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
+					   state->src_w >> 16));
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
+		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
+		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
+
+	DRM_DEBUG_DRIVER("Frontend horizontal scaling factor %d.%d\n", 1, 0);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
+		     state->src_w / state->crtc_w);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
+		     state->src_w / state->crtc_w);
+
+	DRM_DEBUG_DRIVER("Frontend vertical scaling factor %d.%d\n", 1, 0);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
+		     state->src_h / state->crtc_h);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
+		     state->src_h / state->crtc_h);
+
+	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
+			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
+			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
+}
+EXPORT_SYMBOL(sun4i_frontend_update_coord);
+
+int sun4i_frontend_enable(struct sun4i_frontend *frontend)
+{
+	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
+			  SUN4I_FRONTEND_FRM_CTRL_FRM_START,
+			  SUN4I_FRONTEND_FRM_CTRL_FRM_START);
+
+	return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_enable);
+
+static struct regmap_config sun4i_frontend_regmap_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= 0x0a14,
+};
+
+static int sun4i_frontend_bind(struct device *dev, struct device *master,
+			 void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sun4i_frontend *frontend;
+	struct drm_device *drm = data;
+	struct sun4i_drv *drv = drm->dev_private;
+	struct resource *res;
+	void __iomem *regs;
+
+	frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
+	if (!frontend)
+		return -ENOMEM;
+	dev_set_drvdata(dev, frontend);
+	frontend->node = dev->of_node;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	frontend->regs = devm_regmap_init_mmio(dev, regs,
+					       &sun4i_frontend_regmap_config);
+	if (IS_ERR(frontend->regs)) {
+		dev_err(dev, "Couldn't create the frontend regmap\n");
+		return PTR_ERR(frontend->regs);
+	}
+
+	frontend->reset = devm_reset_control_get(dev, NULL);
+	if (IS_ERR(frontend->reset)) {
+		dev_err(dev, "Couldn't get our reset line\n");
+		return PTR_ERR(frontend->reset);
+	}
+
+	frontend->bus_clk = devm_clk_get(dev, "ahb");
+	if (IS_ERR(frontend->bus_clk)) {
+		dev_err(dev, "Couldn't get our bus clock\n");
+		return PTR_ERR(frontend->bus_clk);
+	}
+
+	frontend->mod_clk = devm_clk_get(dev, "mod");
+	if (IS_ERR(frontend->mod_clk)) {
+		dev_err(dev, "Couldn't get our mod clock\n");
+		return PTR_ERR(frontend->mod_clk);
+	}
+
+	frontend->ram_clk = devm_clk_get(dev, "ram");
+	if (IS_ERR(frontend->ram_clk)) {
+		dev_err(dev, "Couldn't get our ram clock\n");
+		return PTR_ERR(frontend->ram_clk);
+	}
+
+	list_add_tail(&frontend->list, &drv->frontend_list);
+
+	return 0;
+}
+
+static void sun4i_frontend_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(frontend->mod_clk);
+	clk_disable_unprepare(frontend->bus_clk);
+	reset_control_assert(frontend->reset);
+}
+
+static const struct component_ops sun4i_frontend_ops = {
+	.bind	= sun4i_frontend_bind,
+	.unbind	= sun4i_frontend_unbind,
+};
+
+static int sun4i_frontend_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &sun4i_frontend_ops);
+}
+
+static int sun4i_frontend_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &sun4i_frontend_ops);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_frontend_of_table[] = {
+	{ .compatible = "allwinner,sun5i-a13-display-frontend" },
+	{ .compatible = "allwinner,sun6i-a31-display-frontend" },
+	{ .compatible = "allwinner,sun8i-a33-display-frontend" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
+
+static struct platform_driver sun4i_frontend_driver = {
+	.probe		= sun4i_frontend_probe,
+	.remove		= sun4i_frontend_remove,
+	.driver		= {
+		.name		= "sun4i-frontend",
+		.of_match_table	= sun4i_frontend_of_table,
+	},
+};
+module_platform_driver(sun4i_frontend_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h
new file mode 100644
index 000000000000..2df9f6de0f3f
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifndef _SUN4I_FRONTEND_H_
+#define _SUN4I_FRONTEND_H_
+
+#include <linux/atomic.h>
+#include <linux/list.h>
+
+#define SUN4I_FRONTEND_EN_REG			0x000
+#define SUN4I_FRONTEND_EN_EN				BIT(0)
+
+#define SUN4I_FRONTEND_FRM_CTRL_REG		0x004
+#define SUN4I_FRONTEND_FRM_CTRL_FRM_START		BIT(16)
+#define SUN4I_FRONTEND_FRM_CTRL_COEF_RDY		BIT(1)
+#define SUN4I_FRONTEND_FRM_CTRL_REG_RDY			BIT(0)
+
+#define SUN4I_FRONTEND_BYPASS_REG		0x008
+#define SUN4I_FRONTEND_BYPASS_CSC_EN			BIT(1)
+
+#define SUN4I_FRONTEND_BUF_ADDR0_REG		0x020
+
+#define SUN4I_FRONTEND_LINESTRD0_REG		0x040
+
+#define SUN4I_FRONTEND_INPUT_FMT_REG		0x04c
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod)		((mod) << 8)
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt)		((fmt) << 4)
+#define SUN4I_FRONTEND_INPUT_FMT_PS(ps)			(ps)
+
+#define SUN4I_FRONTEND_OUTPUT_FMT_REG		0x05c
+#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt)		(fmt)
+
+#define SUN4I_FRONTEND_CH0_INSIZE_REG		0x100
+#define SUN4I_FRONTEND_INSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
+
+#define SUN4I_FRONTEND_CH0_OUTSIZE_REG		0x104
+#define SUN4I_FRONTEND_OUTSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
+
+#define SUN4I_FRONTEND_CH0_HORZFACT_REG		0x108
+#define SUN4I_FRONTEND_HORZFACT(i, f)			(((i) << 16) | (f))
+
+#define SUN4I_FRONTEND_CH0_VERTFACT_REG		0x10c
+#define SUN4I_FRONTEND_VERTFACT(i, f)			(((i) << 16) | (f))
+
+#define SUN4I_FRONTEND_CH0_HORZPHASE_REG	0x110
+#define SUN4I_FRONTEND_CH0_VERTPHASE0_REG	0x114
+#define SUN4I_FRONTEND_CH0_VERTPHASE1_REG	0x118
+
+#define SUN4I_FRONTEND_CH1_INSIZE_REG		0x200
+#define SUN4I_FRONTEND_CH1_OUTSIZE_REG		0x204
+#define SUN4I_FRONTEND_CH1_HORZFACT_REG		0x208
+#define SUN4I_FRONTEND_CH1_VERTFACT_REG		0x20c
+
+#define SUN4I_FRONTEND_CH1_HORZPHASE_REG	0x210
+#define SUN4I_FRONTEND_CH1_VERTPHASE0_REG	0x214
+#define SUN4I_FRONTEND_CH1_VERTPHASE1_REG	0x218
+
+#define SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i)	(0x400 + i * 4)
+#define SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i)	(0x480 + i * 4)
+#define SUN4I_FRONTEND_CH0_VERTCOEF_REG(i)	(0x500 + i * 4)
+#define SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i)	(0x600 + i * 4)
+#define SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i)	(0x680 + i * 4)
+#define SUN4I_FRONTEND_CH1_VERTCOEF_REG(i)	(0x700 + i * 4)
+
+struct clk;
+struct device_node;
+struct drm_plane;
+struct regmap;
+struct reset_control;
+
+struct sun4i_frontend {
+	struct list_head	list;
+	atomic_t		users;
+	struct device_node	*node;
+
+	struct clk		*bus_clk;
+	struct clk		*mod_clk;
+	struct clk		*ram_clk;
+	struct regmap		*regs;
+	struct reset_control	*reset;
+};
+
+int sun4i_frontend_init(struct sun4i_frontend *frontend);
+void sun4i_frontend_exit(struct sun4i_frontend *frontend);
+int sun4i_frontend_enable(struct sun4i_frontend *frontend);
+
+void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane);
+void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
+				 struct drm_plane *plane);
+int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane, uint32_t out_fmt);
+
+#endif /* _SUN4I_FRONTEND_H_ */
-- 
git-series 0.9.1

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

* [PATCH 5/8] drm/sun4i: Add a driver for the display frontend
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

The display frontend is an hardware block that can be used to implement
some more advanced features like hardware scaling or colorspace
conversions. It can also be used to implement the output format of the VPU.

Let's create a minimal driver for it that will only enable the hardware
scaling features.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/Makefile         |   3 +-
 drivers/gpu/drm/sun4i/sun4i_backend.c  |   5 +-
 drivers/gpu/drm/sun4i/sun4i_backend.h  |   1 +-
 drivers/gpu/drm/sun4i/sun4i_drv.c      |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
 7 files changed, 500 insertions(+), 5 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 0c2f8c7facae..b660d82011f4 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 sun4i-backend-y			+= sun4i_backend.o sun4i_layer.o
+sun4i-frontend-y		+= sun4i_frontend.o
 
 sun4i-drm-y			+= sun4i_drv.o
 sun4i-drm-y			+= sun4i_framebuffer.o
@@ -21,6 +22,6 @@ obj-$(CONFIG_DRM_SUN4I)		+= sun4i-tcon.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
 
-obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o
+obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o sun4i-frontend.o
 obj-$(CONFIG_DRM_SUN4I_HDMI)	+= sun4i-drm-hdmi.o
 obj-$(CONFIG_DRM_SUN8I_MIXER)	+= sun8i-mixer.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index f971d3fb5ee4..e83e1fe43823 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -367,6 +367,11 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 	if (backend->engine.id < 0)
 		return backend->engine.id;
 
+	backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
+	if (IS_ERR(backend->frontend)) {
+		dev_err(dev, "Couldn't find matching frontend, frontend features disabled\n");
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	regs = devm_ioremap_resource(dev, res);
 	if (IS_ERR(regs))
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index ac3cc029f5cd..ba1410fd5410 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -145,6 +145,7 @@
 
 struct sun4i_backend {
 	struct sunxi_engine	engine;
+	struct sun4i_frontend	*frontend;
 
 	struct reset_control	*reset;
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 75c76cdd82bc..17bf9bfd98ba 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -98,6 +98,7 @@ static int sun4i_drv_bind(struct device *dev)
 		goto free_drm;
 	}
 	drm->dev_private = drv;
+	INIT_LIST_HEAD(&drv->frontend_list);
 	INIT_LIST_HEAD(&drv->engine_list);
 	INIT_LIST_HEAD(&drv->tcon_list);
 
@@ -239,9 +240,11 @@ static int sun4i_drv_add_endpoints(struct device *dev,
 	int count = 0;
 
 	/*
-	 * We don't support the frontend for now, so we will never
-	 * have a device bound. Just skip over it, but we still want
-	 * the rest our pipeline to be added.
+	 * The frontend has been disabled in all of our old device
+	 * trees. If we find a node that is the frontend and is
+	 * disabled, we should just follow through and parse its
+	 * child, but without adding it to the component list.
+	 * Otherwise, we obviously want to add it to the list.
 	 */
 	if (!sun4i_drv_node_is_frontend(node) &&
 	    !of_device_is_available(node))
@@ -254,7 +257,12 @@ static int sun4i_drv_add_endpoints(struct device *dev,
 	if (sun4i_drv_node_is_connector(node))
 		return 0;
 
-	if (!sun4i_drv_node_is_frontend(node)) {
+	/*
+	 * If the device is either just a regular device, or an
+	 * enabled frontend, we add it to our component list.
+	 */
+	if (!sun4i_drv_node_is_frontend(node) ||
+	    (sun4i_drv_node_is_frontend(node) && of_device_is_available(node))) {
 		/* Add current component */
 		DRM_DEBUG_DRIVER("Adding component %pOF\n", node);
 		drm_of_component_match_add(dev, match, compare_of, node);
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
index a960c89270cc..9c26a345f85c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.h
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
@@ -19,6 +19,7 @@
 
 struct sun4i_drv {
 	struct list_head	engine_list;
+	struct list_head	frontend_list;
 	struct list_head	tcon_list;
 
 	struct drm_fbdev_cma	*fbdev;
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
new file mode 100644
index 000000000000..1be0e86d1457
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+#include <drm/drmP.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include "sun4i_drv.h"
+#include "sun4i_frontend.h"
+
+static const u32 sun4i_frontend_vert_coef[32] = {
+	0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
+	0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
+	0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
+	0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
+	0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
+	0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
+	0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
+	0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
+};
+
+static const u32 sun4i_frontend_horz_coef[64] = {
+	0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
+	0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
+	0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
+	0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
+	0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
+	0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
+	0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
+	0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
+	0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
+	0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
+	0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
+	0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
+	0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
+	0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
+	0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
+	0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
+};
+
+static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
+{
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
+			     sun4i_frontend_horz_coef[2 * i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
+			     sun4i_frontend_horz_coef[2 * i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
+			     sun4i_frontend_horz_coef[2 * i + 1]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
+			     sun4i_frontend_horz_coef[2 * i + 1]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
+			     sun4i_frontend_vert_coef[i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
+			     sun4i_frontend_vert_coef[i]);
+	}
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, BIT(23), BIT(23));
+}
+
+int sun4i_frontend_init(struct sun4i_frontend *frontend)
+{
+	int ret;
+
+	if (atomic_read(&frontend->users))
+		return -EBUSY;
+
+	ret = reset_control_deassert(frontend->reset);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Couldn't deassert our reset line\n");
+		return ret;
+	}
+
+	clk_set_rate(frontend->mod_clk, 300000000);
+
+	clk_prepare_enable(frontend->bus_clk);
+	clk_prepare_enable(frontend->mod_clk);
+	clk_prepare_enable(frontend->ram_clk);
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
+			   SUN4I_FRONTEND_EN_EN,
+			   SUN4I_FRONTEND_EN_EN);
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
+			   SUN4I_FRONTEND_BYPASS_CSC_EN,
+			   SUN4I_FRONTEND_BYPASS_CSC_EN);
+
+	sun4i_frontend_scaler_init(frontend);
+
+	atomic_inc(&frontend->users);
+
+	return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_init);
+
+void sun4i_frontend_exit(struct sun4i_frontend *frontend)
+{
+	atomic_dec(&frontend->users);
+
+	clk_disable_unprepare(frontend->ram_clk);
+	clk_disable_unprepare(frontend->mod_clk);
+	clk_disable_unprepare(frontend->bus_clk);
+	reset_control_assert(frontend->reset);
+}
+EXPORT_SYMBOL(sun4i_frontend_exit);
+
+void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *gem;
+	dma_addr_t paddr;
+	int bpp;
+
+	/* Get the physical address of the buffer in memory */
+	gem = drm_fb_cma_get_gem_obj(fb, 0);
+
+	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
+
+	/* Set the line width */
+	DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
+		     fb->pitches[0]);
+
+	/* Compute the start of the displayed memory */
+	bpp = fb->format->cpp[0];
+	paddr = gem->paddr + fb->offsets[0];
+	paddr += (state->src_x >> 16) * bpp;
+	paddr += (state->src_y >> 16) * fb->pitches[0];
+
+	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
+}
+
+static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
+{
+	switch (fmt) {
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+		*val = 3;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
+{
+	switch (fmt) {
+	case DRM_FORMAT_ARGB8888:
+		*val = 2;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane, uint32_t out_fmt)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	u32 out_fmt_val;
+	u32 in_fmt_val;
+	int ret;
+
+	ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
+						     &in_fmt_val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid input format\n");
+		return ret;
+	}
+
+	ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid output format\n");
+		return ret;
+	}
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400);
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400);
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, 0x151);
+		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | */
+		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(5) | */
+		     /* SUN4I_FRONTEND_INPUT_FMT_PS(1)); */
+	regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, 0x82);
+		     /* SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1)); */
+
+	return 0;
+}
+
+void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
+				 struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+
+	/* Set height and width */
+	DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
+			 state->crtc_w, state->crtc_h);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
+		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
+					   state->src_w >> 16));
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
+		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
+					   state->src_w >> 16));
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
+		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
+		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
+
+	DRM_DEBUG_DRIVER("Frontend horizontal scaling factor %d.%d\n", 1, 0);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
+		     state->src_w / state->crtc_w);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
+		     state->src_w / state->crtc_w);
+
+	DRM_DEBUG_DRIVER("Frontend vertical scaling factor %d.%d\n", 1, 0);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
+		     state->src_h / state->crtc_h);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
+		     state->src_h / state->crtc_h);
+
+	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
+			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
+			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
+}
+EXPORT_SYMBOL(sun4i_frontend_update_coord);
+
+int sun4i_frontend_enable(struct sun4i_frontend *frontend)
+{
+	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
+			  SUN4I_FRONTEND_FRM_CTRL_FRM_START,
+			  SUN4I_FRONTEND_FRM_CTRL_FRM_START);
+
+	return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_enable);
+
+static struct regmap_config sun4i_frontend_regmap_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= 0x0a14,
+};
+
+static int sun4i_frontend_bind(struct device *dev, struct device *master,
+			 void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sun4i_frontend *frontend;
+	struct drm_device *drm = data;
+	struct sun4i_drv *drv = drm->dev_private;
+	struct resource *res;
+	void __iomem *regs;
+
+	frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
+	if (!frontend)
+		return -ENOMEM;
+	dev_set_drvdata(dev, frontend);
+	frontend->node = dev->of_node;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	frontend->regs = devm_regmap_init_mmio(dev, regs,
+					       &sun4i_frontend_regmap_config);
+	if (IS_ERR(frontend->regs)) {
+		dev_err(dev, "Couldn't create the frontend regmap\n");
+		return PTR_ERR(frontend->regs);
+	}
+
+	frontend->reset = devm_reset_control_get(dev, NULL);
+	if (IS_ERR(frontend->reset)) {
+		dev_err(dev, "Couldn't get our reset line\n");
+		return PTR_ERR(frontend->reset);
+	}
+
+	frontend->bus_clk = devm_clk_get(dev, "ahb");
+	if (IS_ERR(frontend->bus_clk)) {
+		dev_err(dev, "Couldn't get our bus clock\n");
+		return PTR_ERR(frontend->bus_clk);
+	}
+
+	frontend->mod_clk = devm_clk_get(dev, "mod");
+	if (IS_ERR(frontend->mod_clk)) {
+		dev_err(dev, "Couldn't get our mod clock\n");
+		return PTR_ERR(frontend->mod_clk);
+	}
+
+	frontend->ram_clk = devm_clk_get(dev, "ram");
+	if (IS_ERR(frontend->ram_clk)) {
+		dev_err(dev, "Couldn't get our ram clock\n");
+		return PTR_ERR(frontend->ram_clk);
+	}
+
+	list_add_tail(&frontend->list, &drv->frontend_list);
+
+	return 0;
+}
+
+static void sun4i_frontend_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(frontend->mod_clk);
+	clk_disable_unprepare(frontend->bus_clk);
+	reset_control_assert(frontend->reset);
+}
+
+static const struct component_ops sun4i_frontend_ops = {
+	.bind	= sun4i_frontend_bind,
+	.unbind	= sun4i_frontend_unbind,
+};
+
+static int sun4i_frontend_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &sun4i_frontend_ops);
+}
+
+static int sun4i_frontend_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &sun4i_frontend_ops);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_frontend_of_table[] = {
+	{ .compatible = "allwinner,sun5i-a13-display-frontend" },
+	{ .compatible = "allwinner,sun6i-a31-display-frontend" },
+	{ .compatible = "allwinner,sun8i-a33-display-frontend" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
+
+static struct platform_driver sun4i_frontend_driver = {
+	.probe		= sun4i_frontend_probe,
+	.remove		= sun4i_frontend_remove,
+	.driver		= {
+		.name		= "sun4i-frontend",
+		.of_match_table	= sun4i_frontend_of_table,
+	},
+};
+module_platform_driver(sun4i_frontend_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h
new file mode 100644
index 000000000000..2df9f6de0f3f
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifndef _SUN4I_FRONTEND_H_
+#define _SUN4I_FRONTEND_H_
+
+#include <linux/atomic.h>
+#include <linux/list.h>
+
+#define SUN4I_FRONTEND_EN_REG			0x000
+#define SUN4I_FRONTEND_EN_EN				BIT(0)
+
+#define SUN4I_FRONTEND_FRM_CTRL_REG		0x004
+#define SUN4I_FRONTEND_FRM_CTRL_FRM_START		BIT(16)
+#define SUN4I_FRONTEND_FRM_CTRL_COEF_RDY		BIT(1)
+#define SUN4I_FRONTEND_FRM_CTRL_REG_RDY			BIT(0)
+
+#define SUN4I_FRONTEND_BYPASS_REG		0x008
+#define SUN4I_FRONTEND_BYPASS_CSC_EN			BIT(1)
+
+#define SUN4I_FRONTEND_BUF_ADDR0_REG		0x020
+
+#define SUN4I_FRONTEND_LINESTRD0_REG		0x040
+
+#define SUN4I_FRONTEND_INPUT_FMT_REG		0x04c
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod)		((mod) << 8)
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt)		((fmt) << 4)
+#define SUN4I_FRONTEND_INPUT_FMT_PS(ps)			(ps)
+
+#define SUN4I_FRONTEND_OUTPUT_FMT_REG		0x05c
+#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt)		(fmt)
+
+#define SUN4I_FRONTEND_CH0_INSIZE_REG		0x100
+#define SUN4I_FRONTEND_INSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
+
+#define SUN4I_FRONTEND_CH0_OUTSIZE_REG		0x104
+#define SUN4I_FRONTEND_OUTSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
+
+#define SUN4I_FRONTEND_CH0_HORZFACT_REG		0x108
+#define SUN4I_FRONTEND_HORZFACT(i, f)			(((i) << 16) | (f))
+
+#define SUN4I_FRONTEND_CH0_VERTFACT_REG		0x10c
+#define SUN4I_FRONTEND_VERTFACT(i, f)			(((i) << 16) | (f))
+
+#define SUN4I_FRONTEND_CH0_HORZPHASE_REG	0x110
+#define SUN4I_FRONTEND_CH0_VERTPHASE0_REG	0x114
+#define SUN4I_FRONTEND_CH0_VERTPHASE1_REG	0x118
+
+#define SUN4I_FRONTEND_CH1_INSIZE_REG		0x200
+#define SUN4I_FRONTEND_CH1_OUTSIZE_REG		0x204
+#define SUN4I_FRONTEND_CH1_HORZFACT_REG		0x208
+#define SUN4I_FRONTEND_CH1_VERTFACT_REG		0x20c
+
+#define SUN4I_FRONTEND_CH1_HORZPHASE_REG	0x210
+#define SUN4I_FRONTEND_CH1_VERTPHASE0_REG	0x214
+#define SUN4I_FRONTEND_CH1_VERTPHASE1_REG	0x218
+
+#define SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i)	(0x400 + i * 4)
+#define SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i)	(0x480 + i * 4)
+#define SUN4I_FRONTEND_CH0_VERTCOEF_REG(i)	(0x500 + i * 4)
+#define SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i)	(0x600 + i * 4)
+#define SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i)	(0x680 + i * 4)
+#define SUN4I_FRONTEND_CH1_VERTCOEF_REG(i)	(0x700 + i * 4)
+
+struct clk;
+struct device_node;
+struct drm_plane;
+struct regmap;
+struct reset_control;
+
+struct sun4i_frontend {
+	struct list_head	list;
+	atomic_t		users;
+	struct device_node	*node;
+
+	struct clk		*bus_clk;
+	struct clk		*mod_clk;
+	struct clk		*ram_clk;
+	struct regmap		*regs;
+	struct reset_control	*reset;
+};
+
+int sun4i_frontend_init(struct sun4i_frontend *frontend);
+void sun4i_frontend_exit(struct sun4i_frontend *frontend);
+int sun4i_frontend_enable(struct sun4i_frontend *frontend);
+
+void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane);
+void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
+				 struct drm_plane *plane);
+int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane, uint32_t out_fmt);
+
+#endif /* _SUN4I_FRONTEND_H_ */
-- 
git-series 0.9.1

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

* [PATCH 5/8] drm/sun4i: Add a driver for the display frontend
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

The display frontend is an hardware block that can be used to implement
some more advanced features like hardware scaling or colorspace
conversions. It can also be used to implement the output format of the VPU.

Let's create a minimal driver for it that will only enable the hardware
scaling features.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/Makefile         |   3 +-
 drivers/gpu/drm/sun4i/sun4i_backend.c  |   5 +-
 drivers/gpu/drm/sun4i/sun4i_backend.h  |   1 +-
 drivers/gpu/drm/sun4i/sun4i_drv.c      |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
 7 files changed, 500 insertions(+), 5 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 0c2f8c7facae..b660d82011f4 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 sun4i-backend-y			+= sun4i_backend.o sun4i_layer.o
+sun4i-frontend-y		+= sun4i_frontend.o
 
 sun4i-drm-y			+= sun4i_drv.o
 sun4i-drm-y			+= sun4i_framebuffer.o
@@ -21,6 +22,6 @@ obj-$(CONFIG_DRM_SUN4I)		+= sun4i-tcon.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
 
-obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o
+obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o sun4i-frontend.o
 obj-$(CONFIG_DRM_SUN4I_HDMI)	+= sun4i-drm-hdmi.o
 obj-$(CONFIG_DRM_SUN8I_MIXER)	+= sun8i-mixer.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index f971d3fb5ee4..e83e1fe43823 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -367,6 +367,11 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 	if (backend->engine.id < 0)
 		return backend->engine.id;
 
+	backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
+	if (IS_ERR(backend->frontend)) {
+		dev_err(dev, "Couldn't find matching frontend, frontend features disabled\n");
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	regs = devm_ioremap_resource(dev, res);
 	if (IS_ERR(regs))
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index ac3cc029f5cd..ba1410fd5410 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -145,6 +145,7 @@
 
 struct sun4i_backend {
 	struct sunxi_engine	engine;
+	struct sun4i_frontend	*frontend;
 
 	struct reset_control	*reset;
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 75c76cdd82bc..17bf9bfd98ba 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -98,6 +98,7 @@ static int sun4i_drv_bind(struct device *dev)
 		goto free_drm;
 	}
 	drm->dev_private = drv;
+	INIT_LIST_HEAD(&drv->frontend_list);
 	INIT_LIST_HEAD(&drv->engine_list);
 	INIT_LIST_HEAD(&drv->tcon_list);
 
@@ -239,9 +240,11 @@ static int sun4i_drv_add_endpoints(struct device *dev,
 	int count = 0;
 
 	/*
-	 * We don't support the frontend for now, so we will never
-	 * have a device bound. Just skip over it, but we still want
-	 * the rest our pipeline to be added.
+	 * The frontend has been disabled in all of our old device
+	 * trees. If we find a node that is the frontend and is
+	 * disabled, we should just follow through and parse its
+	 * child, but without adding it to the component list.
+	 * Otherwise, we obviously want to add it to the list.
 	 */
 	if (!sun4i_drv_node_is_frontend(node) &&
 	    !of_device_is_available(node))
@@ -254,7 +257,12 @@ static int sun4i_drv_add_endpoints(struct device *dev,
 	if (sun4i_drv_node_is_connector(node))
 		return 0;
 
-	if (!sun4i_drv_node_is_frontend(node)) {
+	/*
+	 * If the device is either just a regular device, or an
+	 * enabled frontend, we add it to our component list.
+	 */
+	if (!sun4i_drv_node_is_frontend(node) ||
+	    (sun4i_drv_node_is_frontend(node) && of_device_is_available(node))) {
 		/* Add current component */
 		DRM_DEBUG_DRIVER("Adding component %pOF\n", node);
 		drm_of_component_match_add(dev, match, compare_of, node);
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
index a960c89270cc..9c26a345f85c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.h
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
@@ -19,6 +19,7 @@
 
 struct sun4i_drv {
 	struct list_head	engine_list;
+	struct list_head	frontend_list;
 	struct list_head	tcon_list;
 
 	struct drm_fbdev_cma	*fbdev;
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
new file mode 100644
index 000000000000..1be0e86d1457
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+#include <drm/drmP.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include "sun4i_drv.h"
+#include "sun4i_frontend.h"
+
+static const u32 sun4i_frontend_vert_coef[32] = {
+	0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
+	0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
+	0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
+	0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
+	0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
+	0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
+	0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
+	0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
+};
+
+static const u32 sun4i_frontend_horz_coef[64] = {
+	0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
+	0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
+	0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
+	0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
+	0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
+	0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
+	0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
+	0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
+	0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
+	0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
+	0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
+	0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
+	0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
+	0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
+	0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
+	0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
+};
+
+static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
+{
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
+			     sun4i_frontend_horz_coef[2 * i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
+			     sun4i_frontend_horz_coef[2 * i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
+			     sun4i_frontend_horz_coef[2 * i + 1]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
+			     sun4i_frontend_horz_coef[2 * i + 1]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
+			     sun4i_frontend_vert_coef[i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
+			     sun4i_frontend_vert_coef[i]);
+	}
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, BIT(23), BIT(23));
+}
+
+int sun4i_frontend_init(struct sun4i_frontend *frontend)
+{
+	int ret;
+
+	if (atomic_read(&frontend->users))
+		return -EBUSY;
+
+	ret = reset_control_deassert(frontend->reset);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Couldn't deassert our reset line\n");
+		return ret;
+	}
+
+	clk_set_rate(frontend->mod_clk, 300000000);
+
+	clk_prepare_enable(frontend->bus_clk);
+	clk_prepare_enable(frontend->mod_clk);
+	clk_prepare_enable(frontend->ram_clk);
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
+			   SUN4I_FRONTEND_EN_EN,
+			   SUN4I_FRONTEND_EN_EN);
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
+			   SUN4I_FRONTEND_BYPASS_CSC_EN,
+			   SUN4I_FRONTEND_BYPASS_CSC_EN);
+
+	sun4i_frontend_scaler_init(frontend);
+
+	atomic_inc(&frontend->users);
+
+	return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_init);
+
+void sun4i_frontend_exit(struct sun4i_frontend *frontend)
+{
+	atomic_dec(&frontend->users);
+
+	clk_disable_unprepare(frontend->ram_clk);
+	clk_disable_unprepare(frontend->mod_clk);
+	clk_disable_unprepare(frontend->bus_clk);
+	reset_control_assert(frontend->reset);
+}
+EXPORT_SYMBOL(sun4i_frontend_exit);
+
+void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *gem;
+	dma_addr_t paddr;
+	int bpp;
+
+	/* Get the physical address of the buffer in memory */
+	gem = drm_fb_cma_get_gem_obj(fb, 0);
+
+	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
+
+	/* Set the line width */
+	DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
+		     fb->pitches[0]);
+
+	/* Compute the start of the displayed memory */
+	bpp = fb->format->cpp[0];
+	paddr = gem->paddr + fb->offsets[0];
+	paddr += (state->src_x >> 16) * bpp;
+	paddr += (state->src_y >> 16) * fb->pitches[0];
+
+	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
+}
+
+static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
+{
+	switch (fmt) {
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+		*val = 3;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
+{
+	switch (fmt) {
+	case DRM_FORMAT_ARGB8888:
+		*val = 2;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane, uint32_t out_fmt)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	u32 out_fmt_val;
+	u32 in_fmt_val;
+	int ret;
+
+	ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
+						     &in_fmt_val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid input format\n");
+		return ret;
+	}
+
+	ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid output format\n");
+		return ret;
+	}
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400);
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400);
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, 0x151);
+		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | */
+		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(5) | */
+		     /* SUN4I_FRONTEND_INPUT_FMT_PS(1)); */
+	regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, 0x82);
+		     /* SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1)); */
+
+	return 0;
+}
+
+void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
+				 struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+
+	/* Set height and width */
+	DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
+			 state->crtc_w, state->crtc_h);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
+		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
+					   state->src_w >> 16));
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
+		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
+					   state->src_w >> 16));
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
+		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
+		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
+
+	DRM_DEBUG_DRIVER("Frontend horizontal scaling factor %d.%d\n", 1, 0);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
+		     state->src_w / state->crtc_w);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
+		     state->src_w / state->crtc_w);
+
+	DRM_DEBUG_DRIVER("Frontend vertical scaling factor %d.%d\n", 1, 0);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
+		     state->src_h / state->crtc_h);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
+		     state->src_h / state->crtc_h);
+
+	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
+			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
+			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
+}
+EXPORT_SYMBOL(sun4i_frontend_update_coord);
+
+int sun4i_frontend_enable(struct sun4i_frontend *frontend)
+{
+	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
+			  SUN4I_FRONTEND_FRM_CTRL_FRM_START,
+			  SUN4I_FRONTEND_FRM_CTRL_FRM_START);
+
+	return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_enable);
+
+static struct regmap_config sun4i_frontend_regmap_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= 0x0a14,
+};
+
+static int sun4i_frontend_bind(struct device *dev, struct device *master,
+			 void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sun4i_frontend *frontend;
+	struct drm_device *drm = data;
+	struct sun4i_drv *drv = drm->dev_private;
+	struct resource *res;
+	void __iomem *regs;
+
+	frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
+	if (!frontend)
+		return -ENOMEM;
+	dev_set_drvdata(dev, frontend);
+	frontend->node = dev->of_node;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	frontend->regs = devm_regmap_init_mmio(dev, regs,
+					       &sun4i_frontend_regmap_config);
+	if (IS_ERR(frontend->regs)) {
+		dev_err(dev, "Couldn't create the frontend regmap\n");
+		return PTR_ERR(frontend->regs);
+	}
+
+	frontend->reset = devm_reset_control_get(dev, NULL);
+	if (IS_ERR(frontend->reset)) {
+		dev_err(dev, "Couldn't get our reset line\n");
+		return PTR_ERR(frontend->reset);
+	}
+
+	frontend->bus_clk = devm_clk_get(dev, "ahb");
+	if (IS_ERR(frontend->bus_clk)) {
+		dev_err(dev, "Couldn't get our bus clock\n");
+		return PTR_ERR(frontend->bus_clk);
+	}
+
+	frontend->mod_clk = devm_clk_get(dev, "mod");
+	if (IS_ERR(frontend->mod_clk)) {
+		dev_err(dev, "Couldn't get our mod clock\n");
+		return PTR_ERR(frontend->mod_clk);
+	}
+
+	frontend->ram_clk = devm_clk_get(dev, "ram");
+	if (IS_ERR(frontend->ram_clk)) {
+		dev_err(dev, "Couldn't get our ram clock\n");
+		return PTR_ERR(frontend->ram_clk);
+	}
+
+	list_add_tail(&frontend->list, &drv->frontend_list);
+
+	return 0;
+}
+
+static void sun4i_frontend_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(frontend->mod_clk);
+	clk_disable_unprepare(frontend->bus_clk);
+	reset_control_assert(frontend->reset);
+}
+
+static const struct component_ops sun4i_frontend_ops = {
+	.bind	= sun4i_frontend_bind,
+	.unbind	= sun4i_frontend_unbind,
+};
+
+static int sun4i_frontend_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &sun4i_frontend_ops);
+}
+
+static int sun4i_frontend_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &sun4i_frontend_ops);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_frontend_of_table[] = {
+	{ .compatible = "allwinner,sun5i-a13-display-frontend" },
+	{ .compatible = "allwinner,sun6i-a31-display-frontend" },
+	{ .compatible = "allwinner,sun8i-a33-display-frontend" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
+
+static struct platform_driver sun4i_frontend_driver = {
+	.probe		= sun4i_frontend_probe,
+	.remove		= sun4i_frontend_remove,
+	.driver		= {
+		.name		= "sun4i-frontend",
+		.of_match_table	= sun4i_frontend_of_table,
+	},
+};
+module_platform_driver(sun4i_frontend_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h
new file mode 100644
index 000000000000..2df9f6de0f3f
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifndef _SUN4I_FRONTEND_H_
+#define _SUN4I_FRONTEND_H_
+
+#include <linux/atomic.h>
+#include <linux/list.h>
+
+#define SUN4I_FRONTEND_EN_REG			0x000
+#define SUN4I_FRONTEND_EN_EN				BIT(0)
+
+#define SUN4I_FRONTEND_FRM_CTRL_REG		0x004
+#define SUN4I_FRONTEND_FRM_CTRL_FRM_START		BIT(16)
+#define SUN4I_FRONTEND_FRM_CTRL_COEF_RDY		BIT(1)
+#define SUN4I_FRONTEND_FRM_CTRL_REG_RDY			BIT(0)
+
+#define SUN4I_FRONTEND_BYPASS_REG		0x008
+#define SUN4I_FRONTEND_BYPASS_CSC_EN			BIT(1)
+
+#define SUN4I_FRONTEND_BUF_ADDR0_REG		0x020
+
+#define SUN4I_FRONTEND_LINESTRD0_REG		0x040
+
+#define SUN4I_FRONTEND_INPUT_FMT_REG		0x04c
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod)		((mod) << 8)
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt)		((fmt) << 4)
+#define SUN4I_FRONTEND_INPUT_FMT_PS(ps)			(ps)
+
+#define SUN4I_FRONTEND_OUTPUT_FMT_REG		0x05c
+#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt)		(fmt)
+
+#define SUN4I_FRONTEND_CH0_INSIZE_REG		0x100
+#define SUN4I_FRONTEND_INSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
+
+#define SUN4I_FRONTEND_CH0_OUTSIZE_REG		0x104
+#define SUN4I_FRONTEND_OUTSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
+
+#define SUN4I_FRONTEND_CH0_HORZFACT_REG		0x108
+#define SUN4I_FRONTEND_HORZFACT(i, f)			(((i) << 16) | (f))
+
+#define SUN4I_FRONTEND_CH0_VERTFACT_REG		0x10c
+#define SUN4I_FRONTEND_VERTFACT(i, f)			(((i) << 16) | (f))
+
+#define SUN4I_FRONTEND_CH0_HORZPHASE_REG	0x110
+#define SUN4I_FRONTEND_CH0_VERTPHASE0_REG	0x114
+#define SUN4I_FRONTEND_CH0_VERTPHASE1_REG	0x118
+
+#define SUN4I_FRONTEND_CH1_INSIZE_REG		0x200
+#define SUN4I_FRONTEND_CH1_OUTSIZE_REG		0x204
+#define SUN4I_FRONTEND_CH1_HORZFACT_REG		0x208
+#define SUN4I_FRONTEND_CH1_VERTFACT_REG		0x20c
+
+#define SUN4I_FRONTEND_CH1_HORZPHASE_REG	0x210
+#define SUN4I_FRONTEND_CH1_VERTPHASE0_REG	0x214
+#define SUN4I_FRONTEND_CH1_VERTPHASE1_REG	0x218
+
+#define SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i)	(0x400 + i * 4)
+#define SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i)	(0x480 + i * 4)
+#define SUN4I_FRONTEND_CH0_VERTCOEF_REG(i)	(0x500 + i * 4)
+#define SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i)	(0x600 + i * 4)
+#define SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i)	(0x680 + i * 4)
+#define SUN4I_FRONTEND_CH1_VERTCOEF_REG(i)	(0x700 + i * 4)
+
+struct clk;
+struct device_node;
+struct drm_plane;
+struct regmap;
+struct reset_control;
+
+struct sun4i_frontend {
+	struct list_head	list;
+	atomic_t		users;
+	struct device_node	*node;
+
+	struct clk		*bus_clk;
+	struct clk		*mod_clk;
+	struct clk		*ram_clk;
+	struct regmap		*regs;
+	struct reset_control	*reset;
+};
+
+int sun4i_frontend_init(struct sun4i_frontend *frontend);
+void sun4i_frontend_exit(struct sun4i_frontend *frontend);
+int sun4i_frontend_enable(struct sun4i_frontend *frontend);
+
+void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane);
+void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
+				 struct drm_plane *plane);
+int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane, uint32_t out_fmt);
+
+#endif /* _SUN4I_FRONTEND_H_ */
-- 
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
  2017-12-13 15:33   ` Maxime Ripard
@ 2017-12-13 15:33     ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni, thomas

Now that we have a driver, we can make use of it. This is done by
adding a flag to our custom plane state that will trigger whether we should
use the frontend on that particular plane or not.

The rest is just plumbing to set up the backend to not perform the DMA but
receive its data from the frontend.

Note that we're still not making any use of the frontend itself, as no one
is setting the flag yet.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 53 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h |  3 ++-
 drivers/gpu/drm/sun4i/sun4i_layer.c   | 27 ++++++++++++--
 drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
 4 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index e83e1fe43823..f1d19767c55d 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -26,6 +26,7 @@
 
 #include "sun4i_backend.h"
 #include "sun4i_drv.h"
+#include "sun4i_frontend.h"
 #include "sun4i_layer.h"
 #include "sunxi_engine.h"
 
@@ -203,6 +204,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
 	return 0;
 }
 
+int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
+					int layer, uint32_t fmt)
+{
+	u32 val;
+	int ret;
+
+	ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid format\n");
+		return ret;
+	}
+
+	regmap_update_bits(backend->engine.regs,
+			   SUN4I_BACKEND_ATTCTL_REG0(layer),
+			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
+			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
+
+	regmap_update_bits(backend->engine.regs,
+			   SUN4I_BACKEND_ATTCTL_REG1(layer),
+			   SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
+
+	return 0;
+}
+
 int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 				      int layer, struct drm_plane *plane)
 {
@@ -330,6 +355,34 @@ static int sun4i_backend_of_get_id(struct device_node *node)
 	return ret;
 }
 
+static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
+							  struct device_node *node)
+{
+	struct device_node *port, *ep, *remote;
+	struct sun4i_frontend *frontend;
+
+	port = of_graph_get_port_by_id(node, 0);
+	if (!port)
+		return ERR_PTR(-EINVAL);
+
+	for_each_available_child_of_node(port, ep) {
+		remote = of_graph_get_remote_port_parent(ep);
+		if (!remote)
+			continue;
+
+		/* does this node match any registered engines? */
+		list_for_each_entry(frontend, &drv->frontend_list, list) {
+			if (remote == frontend->node) {
+				of_node_put(remote);
+				of_node_put(port);
+				return frontend;
+			}
+		}
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
 static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
 	.commit				= sun4i_backend_commit,
 	.layers_init			= sun4i_layers_init,
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index ba1410fd5410..636a51521e77 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -72,6 +72,7 @@
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x)		((x) << 15)
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK	GENMASK(11, 10)
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x)			((x) << 10)
+#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN		BIT(1)
 
 #define SUN4I_BACKEND_ATTCTL_REG1(l)		(0x8a0 + (0x4 * (l)))
 #define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT		GENMASK(15, 14)
@@ -171,5 +172,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
 				       int layer, struct drm_plane *plane);
 int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 				      int layer, struct drm_plane *plane);
+int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
+					int layer, uint32_t in_fmt);
 
 #endif /* _SUN4I_BACKEND_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index c3afcf888906..3b58667a06dc 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -15,6 +15,7 @@
 #include <drm/drmP.h>
 
 #include "sun4i_backend.h"
+#include "sun4i_frontend.h"
 #include "sun4i_layer.h"
 #include "sunxi_engine.h"
 
@@ -70,21 +71,41 @@ static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
 static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
 					       struct drm_plane_state *old_state)
 {
+	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
 	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
 	struct sun4i_backend *backend = layer->backend;
+	struct sun4i_frontend *frontend = backend->frontend;
 
 	sun4i_backend_layer_enable(backend, layer->id, false);
+
+	if (layer_state->uses_frontend)
+		sun4i_frontend_exit(frontend);
 }
 
 static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
 					      struct drm_plane_state *old_state)
 {
+	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
 	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
 	struct sun4i_backend *backend = layer->backend;
+	struct sun4i_frontend *frontend = backend->frontend;
+
+	if (layer_state->uses_frontend) {
+		sun4i_frontend_init(frontend);
+		sun4i_frontend_update_coord(frontend, plane);
+		sun4i_frontend_update_buffer(frontend, plane);
+		sun4i_frontend_update_formats(frontend, plane,
+					      DRM_FORMAT_ARGB8888);
+		sun4i_backend_update_layer_frontend(backend, layer->id,
+						    DRM_FORMAT_ARGB8888);
+		sun4i_backend_update_layer_coord(backend, layer->id, plane);
+		sun4i_frontend_enable(frontend);
+	} else {
+		sun4i_backend_update_layer_coord(backend, layer->id, plane);
+		sun4i_backend_update_layer_formats(backend, layer->id, plane);
+		sun4i_backend_update_layer_buffer(backend, layer->id, plane);
+	}
 
-	sun4i_backend_update_layer_coord(backend, layer->id, plane);
-	sun4i_backend_update_layer_formats(backend, layer->id, plane);
-	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
 	sun4i_backend_layer_enable(backend, layer->id, true);
 }
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
index d2c19348d1b0..75b4868ba87c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -24,6 +24,7 @@ struct sun4i_layer {
 
 struct sun4i_layer_state {
 	struct drm_plane_state	state;
+	bool			uses_frontend;
 };
 
 static inline struct sun4i_layer *
-- 
git-series 0.9.1

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

* [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we have a driver, we can make use of it. This is done by
adding a flag to our custom plane state that will trigger whether we should
use the frontend on that particular plane or not.

The rest is just plumbing to set up the backend to not perform the DMA but
receive its data from the frontend.

Note that we're still not making any use of the frontend itself, as no one
is setting the flag yet.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 53 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h |  3 ++-
 drivers/gpu/drm/sun4i/sun4i_layer.c   | 27 ++++++++++++--
 drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
 4 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index e83e1fe43823..f1d19767c55d 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -26,6 +26,7 @@
 
 #include "sun4i_backend.h"
 #include "sun4i_drv.h"
+#include "sun4i_frontend.h"
 #include "sun4i_layer.h"
 #include "sunxi_engine.h"
 
@@ -203,6 +204,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
 	return 0;
 }
 
+int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
+					int layer, uint32_t fmt)
+{
+	u32 val;
+	int ret;
+
+	ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid format\n");
+		return ret;
+	}
+
+	regmap_update_bits(backend->engine.regs,
+			   SUN4I_BACKEND_ATTCTL_REG0(layer),
+			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
+			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
+
+	regmap_update_bits(backend->engine.regs,
+			   SUN4I_BACKEND_ATTCTL_REG1(layer),
+			   SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
+
+	return 0;
+}
+
 int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 				      int layer, struct drm_plane *plane)
 {
@@ -330,6 +355,34 @@ static int sun4i_backend_of_get_id(struct device_node *node)
 	return ret;
 }
 
+static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
+							  struct device_node *node)
+{
+	struct device_node *port, *ep, *remote;
+	struct sun4i_frontend *frontend;
+
+	port = of_graph_get_port_by_id(node, 0);
+	if (!port)
+		return ERR_PTR(-EINVAL);
+
+	for_each_available_child_of_node(port, ep) {
+		remote = of_graph_get_remote_port_parent(ep);
+		if (!remote)
+			continue;
+
+		/* does this node match any registered engines? */
+		list_for_each_entry(frontend, &drv->frontend_list, list) {
+			if (remote == frontend->node) {
+				of_node_put(remote);
+				of_node_put(port);
+				return frontend;
+			}
+		}
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
 static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
 	.commit				= sun4i_backend_commit,
 	.layers_init			= sun4i_layers_init,
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index ba1410fd5410..636a51521e77 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -72,6 +72,7 @@
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x)		((x) << 15)
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK	GENMASK(11, 10)
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x)			((x) << 10)
+#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN		BIT(1)
 
 #define SUN4I_BACKEND_ATTCTL_REG1(l)		(0x8a0 + (0x4 * (l)))
 #define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT		GENMASK(15, 14)
@@ -171,5 +172,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
 				       int layer, struct drm_plane *plane);
 int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 				      int layer, struct drm_plane *plane);
+int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
+					int layer, uint32_t in_fmt);
 
 #endif /* _SUN4I_BACKEND_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index c3afcf888906..3b58667a06dc 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -15,6 +15,7 @@
 #include <drm/drmP.h>
 
 #include "sun4i_backend.h"
+#include "sun4i_frontend.h"
 #include "sun4i_layer.h"
 #include "sunxi_engine.h"
 
@@ -70,21 +71,41 @@ static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
 static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
 					       struct drm_plane_state *old_state)
 {
+	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
 	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
 	struct sun4i_backend *backend = layer->backend;
+	struct sun4i_frontend *frontend = backend->frontend;
 
 	sun4i_backend_layer_enable(backend, layer->id, false);
+
+	if (layer_state->uses_frontend)
+		sun4i_frontend_exit(frontend);
 }
 
 static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
 					      struct drm_plane_state *old_state)
 {
+	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
 	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
 	struct sun4i_backend *backend = layer->backend;
+	struct sun4i_frontend *frontend = backend->frontend;
+
+	if (layer_state->uses_frontend) {
+		sun4i_frontend_init(frontend);
+		sun4i_frontend_update_coord(frontend, plane);
+		sun4i_frontend_update_buffer(frontend, plane);
+		sun4i_frontend_update_formats(frontend, plane,
+					      DRM_FORMAT_ARGB8888);
+		sun4i_backend_update_layer_frontend(backend, layer->id,
+						    DRM_FORMAT_ARGB8888);
+		sun4i_backend_update_layer_coord(backend, layer->id, plane);
+		sun4i_frontend_enable(frontend);
+	} else {
+		sun4i_backend_update_layer_coord(backend, layer->id, plane);
+		sun4i_backend_update_layer_formats(backend, layer->id, plane);
+		sun4i_backend_update_layer_buffer(backend, layer->id, plane);
+	}
 
-	sun4i_backend_update_layer_coord(backend, layer->id, plane);
-	sun4i_backend_update_layer_formats(backend, layer->id, plane);
-	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
 	sun4i_backend_layer_enable(backend, layer->id, true);
 }
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
index d2c19348d1b0..75b4868ba87c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -24,6 +24,7 @@ struct sun4i_layer {
 
 struct sun4i_layer_state {
 	struct drm_plane_state	state;
+	bool			uses_frontend;
 };
 
 static inline struct sun4i_layer *
-- 
git-series 0.9.1

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

* [PATCH 7/8] drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
  2017-12-13 15:33   ` Maxime Ripard
  (?)
@ 2017-12-13 15:33     ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni, thomas

Now that we have everything in place, we can start enabling the frontend.
This is more difficult than one would assume since there can only be one
plane using the frontend per-backend.

We therefore need to make sure that the userspace will not try to setup
multiple planes using it, since that would be impossible. In order to
prevent that, we can create an atomic_check callback that will check that
only one plane will effectively make use of the frontend in a given
configuration, and will toggle the switch in that plane state so that the
proper setup function can do their role.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 65 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h |  2 +-
 2 files changed, 67 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index f1d19767c55d..a7b87a12990e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -11,6 +11,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
@@ -271,6 +272,69 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	return 0;
 }
 
+static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
+{
+	u16 src_h = state->src_h >> 16;
+	u16 src_w = state->src_w >> 16;
+
+	DRM_DEBUG_DRIVER("Input size %dx%d, output size %dx%d\n",
+			 src_w, src_h, state->crtc_w, state->crtc_h);
+
+	if ((state->crtc_h != src_h) || (state->crtc_w != src_w))
+		return true;
+
+	return false;
+}
+
+static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
+{
+	struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);
+	struct sun4i_backend *backend = layer->backend;
+
+	if (IS_ERR(backend->frontend))
+		return false;
+
+	return sun4i_backend_plane_uses_scaler(state);
+}
+
+static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
+				      struct drm_crtc_state *crtc_state)
+{
+	struct drm_atomic_state *state = crtc_state->state;
+	struct drm_device *drm = state->dev;
+	struct drm_plane *plane;
+	unsigned int num_frontend_planes = 0;
+
+	DRM_DEBUG_DRIVER("Starting checking our planes\n");
+
+	if (!crtc_state->planes_changed)
+		return 0;
+
+	drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) {
+		struct drm_plane_state *plane_state =
+			drm_atomic_get_plane_state(state, plane);
+		struct sun4i_layer_state *layer_state =
+			state_to_sun4i_layer_state(plane_state);
+
+		if (sun4i_backend_plane_uses_frontend(plane_state)) {
+			DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
+					 plane->index);
+
+			layer_state->uses_frontend = true;
+			num_frontend_planes++;
+		} else {
+			layer_state->uses_frontend = false;
+		}
+	}
+
+	if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
+		DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int sun4i_backend_init_sat(struct device *dev) {
 	struct sun4i_backend *backend = dev_get_drvdata(dev);
 	int ret;
@@ -384,6 +448,7 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
 }
 
 static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
+	.atomic_check			= sun4i_backend_atomic_check,
 	.commit				= sun4i_backend_commit,
 	.layers_init			= sun4i_layers_init,
 	.apply_color_correction		= sun4i_backend_apply_color_correction,
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index 636a51521e77..3b5531440fa3 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -144,6 +144,8 @@
 #define SUN4I_BACKEND_HWCCOLORTAB_OFF		0x4c00
 #define SUN4I_BACKEND_PIPE_OFF(p)		(0x5000 + (0x400 * (p)))
 
+#define SUN4I_BACKEND_NUM_FRONTEND_LAYERS	1
+
 struct sun4i_backend {
 	struct sunxi_engine	engine;
 	struct sun4i_frontend	*frontend;
-- 
git-series 0.9.1

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

* [PATCH 7/8] drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we have everything in place, we can start enabling the frontend.
This is more difficult than one would assume since there can only be one
plane using the frontend per-backend.

We therefore need to make sure that the userspace will not try to setup
multiple planes using it, since that would be impossible. In order to
prevent that, we can create an atomic_check callback that will check that
only one plane will effectively make use of the frontend in a given
configuration, and will toggle the switch in that plane state so that the
proper setup function can do their role.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 65 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h |  2 +-
 2 files changed, 67 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index f1d19767c55d..a7b87a12990e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -11,6 +11,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
@@ -271,6 +272,69 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	return 0;
 }
 
+static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
+{
+	u16 src_h = state->src_h >> 16;
+	u16 src_w = state->src_w >> 16;
+
+	DRM_DEBUG_DRIVER("Input size %dx%d, output size %dx%d\n",
+			 src_w, src_h, state->crtc_w, state->crtc_h);
+
+	if ((state->crtc_h != src_h) || (state->crtc_w != src_w))
+		return true;
+
+	return false;
+}
+
+static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
+{
+	struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);
+	struct sun4i_backend *backend = layer->backend;
+
+	if (IS_ERR(backend->frontend))
+		return false;
+
+	return sun4i_backend_plane_uses_scaler(state);
+}
+
+static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
+				      struct drm_crtc_state *crtc_state)
+{
+	struct drm_atomic_state *state = crtc_state->state;
+	struct drm_device *drm = state->dev;
+	struct drm_plane *plane;
+	unsigned int num_frontend_planes = 0;
+
+	DRM_DEBUG_DRIVER("Starting checking our planes\n");
+
+	if (!crtc_state->planes_changed)
+		return 0;
+
+	drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) {
+		struct drm_plane_state *plane_state =
+			drm_atomic_get_plane_state(state, plane);
+		struct sun4i_layer_state *layer_state =
+			state_to_sun4i_layer_state(plane_state);
+
+		if (sun4i_backend_plane_uses_frontend(plane_state)) {
+			DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
+					 plane->index);
+
+			layer_state->uses_frontend = true;
+			num_frontend_planes++;
+		} else {
+			layer_state->uses_frontend = false;
+		}
+	}
+
+	if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
+		DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int sun4i_backend_init_sat(struct device *dev) {
 	struct sun4i_backend *backend = dev_get_drvdata(dev);
 	int ret;
@@ -384,6 +448,7 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
 }
 
 static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
+	.atomic_check			= sun4i_backend_atomic_check,
 	.commit				= sun4i_backend_commit,
 	.layers_init			= sun4i_layers_init,
 	.apply_color_correction		= sun4i_backend_apply_color_correction,
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index 636a51521e77..3b5531440fa3 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -144,6 +144,8 @@
 #define SUN4I_BACKEND_HWCCOLORTAB_OFF		0x4c00
 #define SUN4I_BACKEND_PIPE_OFF(p)		(0x5000 + (0x400 * (p)))
 
+#define SUN4I_BACKEND_NUM_FRONTEND_LAYERS	1
+
 struct sun4i_backend {
 	struct sunxi_engine	engine;
 	struct sun4i_frontend	*frontend;
-- 
git-series 0.9.1

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

* [PATCH 7/8] drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

Now that we have everything in place, we can start enabling the frontend.
This is more difficult than one would assume since there can only be one
plane using the frontend per-backend.

We therefore need to make sure that the userspace will not try to setup
multiple planes using it, since that would be impossible. In order to
prevent that, we can create an atomic_check callback that will check that
only one plane will effectively make use of the frontend in a given
configuration, and will toggle the switch in that plane state so that the
proper setup function can do their role.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 65 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h |  2 +-
 2 files changed, 67 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index f1d19767c55d..a7b87a12990e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -11,6 +11,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
@@ -271,6 +272,69 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	return 0;
 }
 
+static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
+{
+	u16 src_h = state->src_h >> 16;
+	u16 src_w = state->src_w >> 16;
+
+	DRM_DEBUG_DRIVER("Input size %dx%d, output size %dx%d\n",
+			 src_w, src_h, state->crtc_w, state->crtc_h);
+
+	if ((state->crtc_h != src_h) || (state->crtc_w != src_w))
+		return true;
+
+	return false;
+}
+
+static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
+{
+	struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);
+	struct sun4i_backend *backend = layer->backend;
+
+	if (IS_ERR(backend->frontend))
+		return false;
+
+	return sun4i_backend_plane_uses_scaler(state);
+}
+
+static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
+				      struct drm_crtc_state *crtc_state)
+{
+	struct drm_atomic_state *state = crtc_state->state;
+	struct drm_device *drm = state->dev;
+	struct drm_plane *plane;
+	unsigned int num_frontend_planes = 0;
+
+	DRM_DEBUG_DRIVER("Starting checking our planes\n");
+
+	if (!crtc_state->planes_changed)
+		return 0;
+
+	drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) {
+		struct drm_plane_state *plane_state =
+			drm_atomic_get_plane_state(state, plane);
+		struct sun4i_layer_state *layer_state =
+			state_to_sun4i_layer_state(plane_state);
+
+		if (sun4i_backend_plane_uses_frontend(plane_state)) {
+			DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
+					 plane->index);
+
+			layer_state->uses_frontend = true;
+			num_frontend_planes++;
+		} else {
+			layer_state->uses_frontend = false;
+		}
+	}
+
+	if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
+		DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int sun4i_backend_init_sat(struct device *dev) {
 	struct sun4i_backend *backend = dev_get_drvdata(dev);
 	int ret;
@@ -384,6 +448,7 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
 }
 
 static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
+	.atomic_check			= sun4i_backend_atomic_check,
 	.commit				= sun4i_backend_commit,
 	.layers_init			= sun4i_layers_init,
 	.apply_color_correction		= sun4i_backend_apply_color_correction,
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index 636a51521e77..3b5531440fa3 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -144,6 +144,8 @@
 #define SUN4I_BACKEND_HWCCOLORTAB_OFF		0x4c00
 #define SUN4I_BACKEND_PIPE_OFF(p)		(0x5000 + (0x400 * (p)))
 
+#define SUN4I_BACKEND_NUM_FRONTEND_LAYERS	1
+
 struct sun4i_backend {
 	struct sunxi_engine	engine;
 	struct sun4i_frontend	*frontend;
-- 
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH 8/8] ARM: dts: sun8i: a33 Enable our display frontend
  2017-12-13 15:33   ` Maxime Ripard
@ 2017-12-13 15:33     ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni, thomas

The display frontend can be used to do hardware scaling, colorspaces
conversion or to implement the buffer format output by the Cedar VPU.

Since we're starting to have some support for it in the DRM driver, let's
enable its DT node.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun8i-a33.dtsi | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index 50eb84fa246a..a21f2ed07a52 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -289,7 +289,6 @@
 			clock-names = "ahb", "mod",
 				      "ram";
 			resets = <&ccu RST_BUS_DE_FE>;
-			status = "disabled";
 
 			ports {
 				#address-cells = <1>;
-- 
git-series 0.9.1

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

* [PATCH 8/8] ARM: dts: sun8i: a33 Enable our display frontend
@ 2017-12-13 15:33     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-13 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

The display frontend can be used to do hardware scaling, colorspaces
conversion or to implement the buffer format output by the Cedar VPU.

Since we're starting to have some support for it in the DRM driver, let's
enable its DT node.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun8i-a33.dtsi | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index 50eb84fa246a..a21f2ed07a52 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -289,7 +289,6 @@
 			clock-names = "ahb", "mod",
 				      "ram";
 			resets = <&ccu RST_BUS_DE_FE>;
-			status = "disabled";
 
 			ports {
 				#address-cells = <1>;
-- 
git-series 0.9.1

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

* Re: [PATCH 1/8] drm/sun4i: backend: Move line stride setup to buffer setup function
  2017-12-13 15:33     ` Maxime Ripard
  (?)
@ 2017-12-13 16:03       ` Neil Armstrong
  -1 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:03 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> Setup the line stride in the buffer setup function, since it's tied to the
> buffer itself, and is not needed when we do not set the buffer in the
> backend.
> 
> This is for example the case when using the frontend and then routing its
> output to the backend.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index 847eecbe4d14..c99d1a7e815a 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -141,7 +141,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
>  				     int layer, struct drm_plane *plane)
>  {
>  	struct drm_plane_state *state = plane->state;
> -	struct drm_framebuffer *fb = state->fb;
>  
>  	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
>  
> @@ -153,12 +152,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
>  						   state->crtc_h));
>  	}
>  
> -	/* Set the line width */
> -	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
> -	regmap_write(backend->engine.regs,
> -		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
> -		     fb->pitches[0] * 8);
> -
>  	/* Set height and width */
>  	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>  			 state->crtc_w, state->crtc_h);
> @@ -218,6 +211,13 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  	u32 lo_paddr, hi_paddr;
>  	dma_addr_t paddr;
>  
> +	/* Set the line width */
> +	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
> +	regmap_write(backend->engine.regs,
> +		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
> +		     fb->pitches[0] * 8);
> +
> +
>  	/* Get the start of the displayed memory */
>  	paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
>  	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* [PATCH 1/8] drm/sun4i: backend: Move line stride setup to buffer setup function
@ 2017-12-13 16:03       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/12/2017 16:33, Maxime Ripard wrote:
> Setup the line stride in the buffer setup function, since it's tied to the
> buffer itself, and is not needed when we do not set the buffer in the
> backend.
> 
> This is for example the case when using the frontend and then routing its
> output to the backend.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index 847eecbe4d14..c99d1a7e815a 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -141,7 +141,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
>  				     int layer, struct drm_plane *plane)
>  {
>  	struct drm_plane_state *state = plane->state;
> -	struct drm_framebuffer *fb = state->fb;
>  
>  	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
>  
> @@ -153,12 +152,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
>  						   state->crtc_h));
>  	}
>  
> -	/* Set the line width */
> -	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
> -	regmap_write(backend->engine.regs,
> -		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
> -		     fb->pitches[0] * 8);
> -
>  	/* Set height and width */
>  	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>  			 state->crtc_w, state->crtc_h);
> @@ -218,6 +211,13 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  	u32 lo_paddr, hi_paddr;
>  	dma_addr_t paddr;
>  
> +	/* Set the line width */
> +	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
> +	regmap_write(backend->engine.regs,
> +		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
> +		     fb->pitches[0] * 8);
> +
> +
>  	/* Get the start of the displayed memory */
>  	paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
>  	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* Re: [PATCH 1/8] drm/sun4i: backend: Move line stride setup to buffer setup function
@ 2017-12-13 16:03       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:03 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: Thomas Petazzoni, dri-devel, linux-kernel, linux-arm-kernel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> Setup the line stride in the buffer setup function, since it's tied to the
> buffer itself, and is not needed when we do not set the buffer in the
> backend.
> 
> This is for example the case when using the frontend and then routing its
> output to the backend.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index 847eecbe4d14..c99d1a7e815a 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -141,7 +141,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
>  				     int layer, struct drm_plane *plane)
>  {
>  	struct drm_plane_state *state = plane->state;
> -	struct drm_framebuffer *fb = state->fb;
>  
>  	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
>  
> @@ -153,12 +152,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
>  						   state->crtc_h));
>  	}
>  
> -	/* Set the line width */
> -	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
> -	regmap_write(backend->engine.regs,
> -		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
> -		     fb->pitches[0] * 8);
> -
>  	/* Set height and width */
>  	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>  			 state->crtc_w, state->crtc_h);
> @@ -218,6 +211,13 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  	u32 lo_paddr, hi_paddr;
>  	dma_addr_t paddr;
>  
> +	/* Set the line width */
> +	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
> +	regmap_write(backend->engine.regs,
> +		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
> +		     fb->pitches[0] * 8);
> +
> +
>  	/* Get the start of the displayed memory */
>  	paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
>  	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 2/8] drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
  2017-12-13 15:33     ` Maxime Ripard
  (?)
@ 2017-12-13 16:03       ` Neil Armstrong
  -1 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:03 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> The function converting the DRM format to its equivalent in the backend
> registers was assuming that we were having a plane.
> 
> However, we might want to use that function when setting up a plane using
> the frontend, in which case we will not have a plane associated to the
> backend's layer. Yet, we still need to setup the format to the one output
> by the frontend.
> 
> Test for NULL plane pointers before referencing them, so that we can work
> around it.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index c99d1a7e815a..f971d3fb5ee4 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -93,7 +93,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
>  static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
>  					     u32 format, u32 *mode)
>  {
> -	if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
> +	if (plane && (plane->type == DRM_PLANE_TYPE_PRIMARY) &&
>  	    (format == DRM_FORMAT_ARGB8888))
>  		format = DRM_FORMAT_XRGB8888;
>  
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* [PATCH 2/8] drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
@ 2017-12-13 16:03       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/12/2017 16:33, Maxime Ripard wrote:
> The function converting the DRM format to its equivalent in the backend
> registers was assuming that we were having a plane.
> 
> However, we might want to use that function when setting up a plane using
> the frontend, in which case we will not have a plane associated to the
> backend's layer. Yet, we still need to setup the format to the one output
> by the frontend.
> 
> Test for NULL plane pointers before referencing them, so that we can work
> around it.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index c99d1a7e815a..f971d3fb5ee4 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -93,7 +93,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
>  static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
>  					     u32 format, u32 *mode)
>  {
> -	if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
> +	if (plane && (plane->type == DRM_PLANE_TYPE_PRIMARY) &&
>  	    (format == DRM_FORMAT_ARGB8888))
>  		format = DRM_FORMAT_XRGB8888;
>  
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* Re: [PATCH 2/8] drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
@ 2017-12-13 16:03       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:03 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: Thomas Petazzoni, dri-devel, linux-kernel, linux-arm-kernel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> The function converting the DRM format to its equivalent in the backend
> registers was assuming that we were having a plane.
> 
> However, we might want to use that function when setting up a plane using
> the frontend, in which case we will not have a plane associated to the
> backend's layer. Yet, we still need to setup the format to the one output
> by the frontend.
> 
> Test for NULL plane pointers before referencing them, so that we can work
> around it.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index c99d1a7e815a..f971d3fb5ee4 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -93,7 +93,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
>  static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
>  					     u32 format, u32 *mode)
>  {
> -	if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
> +	if (plane && (plane->type == DRM_PLANE_TYPE_PRIMARY) &&
>  	    (format == DRM_FORMAT_ARGB8888))
>  		format = DRM_FORMAT_XRGB8888;
>  
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 3/8] drm/sun4i: sun4i_layer: Add a custom plane state
  2017-12-13 15:33     ` Maxime Ripard
  (?)
@ 2017-12-13 16:05       ` Neil Armstrong
  -1 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:05 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> We will need to store some additional data in the future to the state.
> Create a custom plane state that will embed those data, in order to store
> the pipe or whether or not that plane should use the frontend.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_layer.c | 48 ++++++++++++++++++++++++++++--
>  drivers/gpu/drm/sun4i/sun4i_layer.h | 10 ++++++-
>  2 files changed, 55 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
> index 7bddf12548d3..c3afcf888906 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -25,6 +25,48 @@ struct sun4i_plane_desc {
>  	       uint32_t                nformats;
>  };
>  
> +static void sun4i_backend_layer_reset(struct drm_plane *plane)
> +{
> +	struct sun4i_layer_state *state;
> +
> +	if (plane->state) {
> +		state = state_to_sun4i_layer_state(plane->state);
> +
> +		__drm_atomic_helper_plane_destroy_state(&state->state);

Maybe a blank line here ?

> +		kfree(state);
> +		plane->state = NULL;
> +	}
> +
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (state) {
> +		plane->state = &state->state;
> +		plane->state->plane = plane;
> +	}
> +}
> +
> +static struct drm_plane_state *
> +sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
> +{
> +	struct sun4i_layer_state *copy;
> +
> +	copy = kzalloc(sizeof(*copy), GFP_KERNEL);
> +	if (!copy)
> +		return NULL;
> +
> +	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
> +
> +	return &copy->state;
> +}
> +
> +static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
> +					      struct drm_plane_state *state)
> +{
> +	struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
> +
> +	__drm_atomic_helper_plane_destroy_state(state);

You can add a blank line here

> +	kfree(s_state);
> +}
> +
>  static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
>  					       struct drm_plane_state *old_state)
>  {
> @@ -52,11 +94,11 @@ static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
>  };
>  
>  static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
> -	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
> -	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
> +	.atomic_destroy_state	= sun4i_backend_layer_destroy_state,
> +	.atomic_duplicate_state	= sun4i_backend_layer_duplicate_state,
>  	.destroy		= drm_plane_cleanup,
>  	.disable_plane		= drm_atomic_helper_disable_plane,
> -	.reset			= drm_atomic_helper_plane_reset,
> +	.reset			= sun4i_backend_layer_reset,
>  	.update_plane		= drm_atomic_helper_update_plane,
>  };
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
> index 4e84f438b346..d2c19348d1b0 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
> @@ -22,12 +22,22 @@ struct sun4i_layer {
>  	int			id;
>  };
>  
> +struct sun4i_layer_state {
> +	struct drm_plane_state	state;
> +};
> +
>  static inline struct sun4i_layer *
>  plane_to_sun4i_layer(struct drm_plane *plane)
>  {
>  	return container_of(plane, struct sun4i_layer, plane);
>  }
>  
> +static inline struct sun4i_layer_state *
> +state_to_sun4i_layer_state(struct drm_plane_state *state)
> +{
> +	return container_of(state, struct sun4i_layer_state, state);
> +}
> +
>  struct drm_plane **sun4i_layers_init(struct drm_device *drm,
>  				     struct sunxi_engine *engine);
>  
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* [PATCH 3/8] drm/sun4i: sun4i_layer: Add a custom plane state
@ 2017-12-13 16:05       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:05 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/12/2017 16:33, Maxime Ripard wrote:
> We will need to store some additional data in the future to the state.
> Create a custom plane state that will embed those data, in order to store
> the pipe or whether or not that plane should use the frontend.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_layer.c | 48 ++++++++++++++++++++++++++++--
>  drivers/gpu/drm/sun4i/sun4i_layer.h | 10 ++++++-
>  2 files changed, 55 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
> index 7bddf12548d3..c3afcf888906 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -25,6 +25,48 @@ struct sun4i_plane_desc {
>  	       uint32_t                nformats;
>  };
>  
> +static void sun4i_backend_layer_reset(struct drm_plane *plane)
> +{
> +	struct sun4i_layer_state *state;
> +
> +	if (plane->state) {
> +		state = state_to_sun4i_layer_state(plane->state);
> +
> +		__drm_atomic_helper_plane_destroy_state(&state->state);

Maybe a blank line here ?

> +		kfree(state);
> +		plane->state = NULL;
> +	}
> +
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (state) {
> +		plane->state = &state->state;
> +		plane->state->plane = plane;
> +	}
> +}
> +
> +static struct drm_plane_state *
> +sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
> +{
> +	struct sun4i_layer_state *copy;
> +
> +	copy = kzalloc(sizeof(*copy), GFP_KERNEL);
> +	if (!copy)
> +		return NULL;
> +
> +	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
> +
> +	return &copy->state;
> +}
> +
> +static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
> +					      struct drm_plane_state *state)
> +{
> +	struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
> +
> +	__drm_atomic_helper_plane_destroy_state(state);

You can add a blank line here

> +	kfree(s_state);
> +}
> +
>  static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
>  					       struct drm_plane_state *old_state)
>  {
> @@ -52,11 +94,11 @@ static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
>  };
>  
>  static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
> -	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
> -	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
> +	.atomic_destroy_state	= sun4i_backend_layer_destroy_state,
> +	.atomic_duplicate_state	= sun4i_backend_layer_duplicate_state,
>  	.destroy		= drm_plane_cleanup,
>  	.disable_plane		= drm_atomic_helper_disable_plane,
> -	.reset			= drm_atomic_helper_plane_reset,
> +	.reset			= sun4i_backend_layer_reset,
>  	.update_plane		= drm_atomic_helper_update_plane,
>  };
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
> index 4e84f438b346..d2c19348d1b0 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
> @@ -22,12 +22,22 @@ struct sun4i_layer {
>  	int			id;
>  };
>  
> +struct sun4i_layer_state {
> +	struct drm_plane_state	state;
> +};
> +
>  static inline struct sun4i_layer *
>  plane_to_sun4i_layer(struct drm_plane *plane)
>  {
>  	return container_of(plane, struct sun4i_layer, plane);
>  }
>  
> +static inline struct sun4i_layer_state *
> +state_to_sun4i_layer_state(struct drm_plane_state *state)
> +{
> +	return container_of(state, struct sun4i_layer_state, state);
> +}
> +
>  struct drm_plane **sun4i_layers_init(struct drm_device *drm,
>  				     struct sunxi_engine *engine);
>  
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* Re: [PATCH 3/8] drm/sun4i: sun4i_layer: Add a custom plane state
@ 2017-12-13 16:05       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:05 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: Thomas Petazzoni, dri-devel, linux-kernel, linux-arm-kernel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> We will need to store some additional data in the future to the state.
> Create a custom plane state that will embed those data, in order to store
> the pipe or whether or not that plane should use the frontend.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_layer.c | 48 ++++++++++++++++++++++++++++--
>  drivers/gpu/drm/sun4i/sun4i_layer.h | 10 ++++++-
>  2 files changed, 55 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
> index 7bddf12548d3..c3afcf888906 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -25,6 +25,48 @@ struct sun4i_plane_desc {
>  	       uint32_t                nformats;
>  };
>  
> +static void sun4i_backend_layer_reset(struct drm_plane *plane)
> +{
> +	struct sun4i_layer_state *state;
> +
> +	if (plane->state) {
> +		state = state_to_sun4i_layer_state(plane->state);
> +
> +		__drm_atomic_helper_plane_destroy_state(&state->state);

Maybe a blank line here ?

> +		kfree(state);
> +		plane->state = NULL;
> +	}
> +
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (state) {
> +		plane->state = &state->state;
> +		plane->state->plane = plane;
> +	}
> +}
> +
> +static struct drm_plane_state *
> +sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
> +{
> +	struct sun4i_layer_state *copy;
> +
> +	copy = kzalloc(sizeof(*copy), GFP_KERNEL);
> +	if (!copy)
> +		return NULL;
> +
> +	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
> +
> +	return &copy->state;
> +}
> +
> +static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
> +					      struct drm_plane_state *state)
> +{
> +	struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
> +
> +	__drm_atomic_helper_plane_destroy_state(state);

You can add a blank line here

> +	kfree(s_state);
> +}
> +
>  static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
>  					       struct drm_plane_state *old_state)
>  {
> @@ -52,11 +94,11 @@ static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
>  };
>  
>  static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
> -	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
> -	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
> +	.atomic_destroy_state	= sun4i_backend_layer_destroy_state,
> +	.atomic_duplicate_state	= sun4i_backend_layer_duplicate_state,
>  	.destroy		= drm_plane_cleanup,
>  	.disable_plane		= drm_atomic_helper_disable_plane,
> -	.reset			= drm_atomic_helper_plane_reset,
> +	.reset			= sun4i_backend_layer_reset,
>  	.update_plane		= drm_atomic_helper_update_plane,
>  };
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
> index 4e84f438b346..d2c19348d1b0 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
> @@ -22,12 +22,22 @@ struct sun4i_layer {
>  	int			id;
>  };
>  
> +struct sun4i_layer_state {
> +	struct drm_plane_state	state;
> +};
> +
>  static inline struct sun4i_layer *
>  plane_to_sun4i_layer(struct drm_plane *plane)
>  {
>  	return container_of(plane, struct sun4i_layer, plane);
>  }
>  
> +static inline struct sun4i_layer_state *
> +state_to_sun4i_layer_state(struct drm_plane_state *state)
> +{
> +	return container_of(state, struct sun4i_layer_state, state);
> +}
> +
>  struct drm_plane **sun4i_layers_init(struct drm_device *drm,
>  				     struct sunxi_engine *engine);
>  
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 4/8] drm/sun4i: crtc: Add a custom crtc atomic_check
  2017-12-13 15:33     ` Maxime Ripard
  (?)
@ 2017-12-13 16:06       ` Neil Armstrong
  -1 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:06 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> We have some restrictions on what the planes and CRTC can provide that are
> tied to only one generation of display engines.
> 
> For example, on the first generation, we can only have one YUV plane or one
> plane that uses the frontend output.
> 
> Let's allow our engines to provide an atomic_check callback to validate the
> current configuration.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_crtc.c   | 14 ++++++++++++++
>  drivers/gpu/drm/sun4i/sunxi_engine.h |  2 ++
>  2 files changed, 16 insertions(+)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> index 5decae0069d0..2a565325714f 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> @@ -46,6 +46,19 @@ static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
>  	return NULL;
>  }
>  
> +static int sun4i_crtc_atomic_check(struct drm_crtc *crtc,
> +				    struct drm_crtc_state *state)
> +{
> +	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
> +	struct sunxi_engine *engine = scrtc->engine;
> +	int ret = 0;
> +
> +	if (engine && engine->ops && engine->ops->atomic_check)
> +		ret = engine->ops->atomic_check(engine, state);
> +
> +	return ret;
> +}
> +
>  static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
>  				    struct drm_crtc_state *old_state)
>  {
> @@ -125,6 +138,7 @@ static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
>  }
>  
>  static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
> +	.atomic_check	= sun4i_crtc_atomic_check,
>  	.atomic_begin	= sun4i_crtc_atomic_begin,
>  	.atomic_flush	= sun4i_crtc_atomic_flush,
>  	.atomic_enable	= sun4i_crtc_atomic_enable,
> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
> index 4cb70ae65c79..42655230aeba 100644
> --- a/drivers/gpu/drm/sun4i/sunxi_engine.h
> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
> @@ -16,6 +16,8 @@ struct drm_device;
>  struct sunxi_engine;
>  
>  struct sunxi_engine_ops {
> +	int (*atomic_check)(struct sunxi_engine *engine,
> +			    struct drm_crtc_state *state);
>  	void (*commit)(struct sunxi_engine *engine);
>  	struct drm_plane **(*layers_init)(struct drm_device *drm,
>  					  struct sunxi_engine *engine);
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* [PATCH 4/8] drm/sun4i: crtc: Add a custom crtc atomic_check
@ 2017-12-13 16:06       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:06 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/12/2017 16:33, Maxime Ripard wrote:
> We have some restrictions on what the planes and CRTC can provide that are
> tied to only one generation of display engines.
> 
> For example, on the first generation, we can only have one YUV plane or one
> plane that uses the frontend output.
> 
> Let's allow our engines to provide an atomic_check callback to validate the
> current configuration.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_crtc.c   | 14 ++++++++++++++
>  drivers/gpu/drm/sun4i/sunxi_engine.h |  2 ++
>  2 files changed, 16 insertions(+)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> index 5decae0069d0..2a565325714f 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> @@ -46,6 +46,19 @@ static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
>  	return NULL;
>  }
>  
> +static int sun4i_crtc_atomic_check(struct drm_crtc *crtc,
> +				    struct drm_crtc_state *state)
> +{
> +	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
> +	struct sunxi_engine *engine = scrtc->engine;
> +	int ret = 0;
> +
> +	if (engine && engine->ops && engine->ops->atomic_check)
> +		ret = engine->ops->atomic_check(engine, state);
> +
> +	return ret;
> +}
> +
>  static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
>  				    struct drm_crtc_state *old_state)
>  {
> @@ -125,6 +138,7 @@ static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
>  }
>  
>  static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
> +	.atomic_check	= sun4i_crtc_atomic_check,
>  	.atomic_begin	= sun4i_crtc_atomic_begin,
>  	.atomic_flush	= sun4i_crtc_atomic_flush,
>  	.atomic_enable	= sun4i_crtc_atomic_enable,
> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
> index 4cb70ae65c79..42655230aeba 100644
> --- a/drivers/gpu/drm/sun4i/sunxi_engine.h
> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
> @@ -16,6 +16,8 @@ struct drm_device;
>  struct sunxi_engine;
>  
>  struct sunxi_engine_ops {
> +	int (*atomic_check)(struct sunxi_engine *engine,
> +			    struct drm_crtc_state *state);
>  	void (*commit)(struct sunxi_engine *engine);
>  	struct drm_plane **(*layers_init)(struct drm_device *drm,
>  					  struct sunxi_engine *engine);
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* Re: [PATCH 4/8] drm/sun4i: crtc: Add a custom crtc atomic_check
@ 2017-12-13 16:06       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:06 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: Thomas Petazzoni, dri-devel, linux-kernel, linux-arm-kernel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> We have some restrictions on what the planes and CRTC can provide that are
> tied to only one generation of display engines.
> 
> For example, on the first generation, we can only have one YUV plane or one
> plane that uses the frontend output.
> 
> Let's allow our engines to provide an atomic_check callback to validate the
> current configuration.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_crtc.c   | 14 ++++++++++++++
>  drivers/gpu/drm/sun4i/sunxi_engine.h |  2 ++
>  2 files changed, 16 insertions(+)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> index 5decae0069d0..2a565325714f 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> @@ -46,6 +46,19 @@ static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
>  	return NULL;
>  }
>  
> +static int sun4i_crtc_atomic_check(struct drm_crtc *crtc,
> +				    struct drm_crtc_state *state)
> +{
> +	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
> +	struct sunxi_engine *engine = scrtc->engine;
> +	int ret = 0;
> +
> +	if (engine && engine->ops && engine->ops->atomic_check)
> +		ret = engine->ops->atomic_check(engine, state);
> +
> +	return ret;
> +}
> +
>  static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
>  				    struct drm_crtc_state *old_state)
>  {
> @@ -125,6 +138,7 @@ static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
>  }
>  
>  static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
> +	.atomic_check	= sun4i_crtc_atomic_check,
>  	.atomic_begin	= sun4i_crtc_atomic_begin,
>  	.atomic_flush	= sun4i_crtc_atomic_flush,
>  	.atomic_enable	= sun4i_crtc_atomic_enable,
> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
> index 4cb70ae65c79..42655230aeba 100644
> --- a/drivers/gpu/drm/sun4i/sunxi_engine.h
> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
> @@ -16,6 +16,8 @@ struct drm_device;
>  struct sunxi_engine;
>  
>  struct sunxi_engine_ops {
> +	int (*atomic_check)(struct sunxi_engine *engine,
> +			    struct drm_crtc_state *state);
>  	void (*commit)(struct sunxi_engine *engine);
>  	struct drm_plane **(*layers_init)(struct drm_device *drm,
>  					  struct sunxi_engine *engine);
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 5/8] drm/sun4i: Add a driver for the display frontend
  2017-12-13 15:33     ` Maxime Ripard
  (?)
@ 2017-12-13 16:10       ` Neil Armstrong
  -1 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:10 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> The display frontend is an hardware block that can be used to implement
> some more advanced features like hardware scaling or colorspace
> conversions. It can also be used to implement the output format of the VPU.
> 
> Let's create a minimal driver for it that will only enable the hardware
> scaling features.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/Makefile         |   3 +-
>  drivers/gpu/drm/sun4i/sun4i_backend.c  |   5 +-
>  drivers/gpu/drm/sun4i/sun4i_backend.h  |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.c      |  16 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
>  7 files changed, 500 insertions(+), 5 deletions(-)
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h
> 
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index 0c2f8c7facae..b660d82011f4 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -1,5 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0
>  sun4i-backend-y			+= sun4i_backend.o sun4i_layer.o
> +sun4i-frontend-y		+= sun4i_frontend.o
>  
>  sun4i-drm-y			+= sun4i_drv.o
>  sun4i-drm-y			+= sun4i_framebuffer.o
> @@ -21,6 +22,6 @@ obj-$(CONFIG_DRM_SUN4I)		+= sun4i-tcon.o
>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
>  obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
>  
> -obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o
> +obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o sun4i-frontend.o
>  obj-$(CONFIG_DRM_SUN4I_HDMI)	+= sun4i-drm-hdmi.o
>  obj-$(CONFIG_DRM_SUN8I_MIXER)	+= sun8i-mixer.o
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index f971d3fb5ee4..e83e1fe43823 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -367,6 +367,11 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
>  	if (backend->engine.id < 0)
>  		return backend->engine.id;
>  
> +	backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
> +	if (IS_ERR(backend->frontend)) {
> +		dev_err(dev, "Couldn't find matching frontend, frontend features disabled\n");

Maybe a dev_warn ?

> +	}
> +
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	regs = devm_ioremap_resource(dev, res);
>  	if (IS_ERR(regs))
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index ac3cc029f5cd..ba1410fd5410 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -145,6 +145,7 @@
>  
>  struct sun4i_backend {
>  	struct sunxi_engine	engine;
> +	struct sun4i_frontend	*frontend;
>  
>  	struct reset_control	*reset;
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
> index 75c76cdd82bc..17bf9bfd98ba 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
> @@ -98,6 +98,7 @@ static int sun4i_drv_bind(struct device *dev)
>  		goto free_drm;
>  	}
>  	drm->dev_private = drv;
> +	INIT_LIST_HEAD(&drv->frontend_list);
>  	INIT_LIST_HEAD(&drv->engine_list);
>  	INIT_LIST_HEAD(&drv->tcon_list);
>  
> @@ -239,9 +240,11 @@ static int sun4i_drv_add_endpoints(struct device *dev,
>  	int count = 0;
>  
>  	/*
> -	 * We don't support the frontend for now, so we will never
> -	 * have a device bound. Just skip over it, but we still want
> -	 * the rest our pipeline to be added.
> +	 * The frontend has been disabled in all of our old device
> +	 * trees. If we find a node that is the frontend and is
> +	 * disabled, we should just follow through and parse its
> +	 * child, but without adding it to the component list.
> +	 * Otherwise, we obviously want to add it to the list.
>  	 */
>  	if (!sun4i_drv_node_is_frontend(node) &&
>  	    !of_device_is_available(node))
> @@ -254,7 +257,12 @@ static int sun4i_drv_add_endpoints(struct device *dev,
>  	if (sun4i_drv_node_is_connector(node))
>  		return 0;
>  
> -	if (!sun4i_drv_node_is_frontend(node)) {
> +	/*
> +	 * If the device is either just a regular device, or an
> +	 * enabled frontend, we add it to our component list.
> +	 */
> +	if (!sun4i_drv_node_is_frontend(node) ||
> +	    (sun4i_drv_node_is_frontend(node) && of_device_is_available(node))) {
>  		/* Add current component */
>  		DRM_DEBUG_DRIVER("Adding component %pOF\n", node);
>  		drm_of_component_match_add(dev, match, compare_of, node);
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
> index a960c89270cc..9c26a345f85c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
> @@ -19,6 +19,7 @@
>  
>  struct sun4i_drv {
>  	struct list_head	engine_list;
> +	struct list_head	frontend_list;
>  	struct list_head	tcon_list;
>  
>  	struct drm_fbdev_cma	*fbdev;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> new file mode 100644
> index 000000000000..1be0e86d1457
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> @@ -0,0 +1,377 @@

// SPDX-Licence-Identifier... new format ?

> +/*
> + * Copyright (C) 2017 Free Electrons
> + *
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +#include <drm/drmP.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#include "sun4i_drv.h"
> +#include "sun4i_frontend.h"
> +
> +static const u32 sun4i_frontend_vert_coef[32] = {
> +	0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
> +	0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
> +	0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
> +	0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
> +	0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
> +	0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
> +	0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
> +	0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
> +};
> +
> +static const u32 sun4i_frontend_horz_coef[64] = {
> +	0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
> +	0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
> +	0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
> +	0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
> +	0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
> +	0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
> +	0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
> +	0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
> +	0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
> +	0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
> +	0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
> +	0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
> +	0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
> +	0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
> +	0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
> +	0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
> +};
> +
> +static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
> +{
> +	int i;
> +
> +	for (i = 0; i < 32; i++) {
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i + 1]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i + 1]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
> +			     sun4i_frontend_vert_coef[i]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
> +			     sun4i_frontend_vert_coef[i]);
> +	}
> +
> +	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, BIT(23), BIT(23));
> +}
> +
> +int sun4i_frontend_init(struct sun4i_frontend *frontend)
> +{
> +	int ret;
> +
> +	if (atomic_read(&frontend->users))
> +		return -EBUSY;
> +
> +	ret = reset_control_deassert(frontend->reset);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Couldn't deassert our reset line\n");
> +		return ret;
> +	}
> +
> +	clk_set_rate(frontend->mod_clk, 300000000);
> +
> +	clk_prepare_enable(frontend->bus_clk);
> +	clk_prepare_enable(frontend->mod_clk);
> +	clk_prepare_enable(frontend->ram_clk);
> +
> +	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
> +			   SUN4I_FRONTEND_EN_EN,
> +			   SUN4I_FRONTEND_EN_EN);
> +
> +	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
> +			   SUN4I_FRONTEND_BYPASS_CSC_EN,
> +			   SUN4I_FRONTEND_BYPASS_CSC_EN);
> +
> +	sun4i_frontend_scaler_init(frontend);
> +
> +	atomic_inc(&frontend->users);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(sun4i_frontend_init);
> +
> +void sun4i_frontend_exit(struct sun4i_frontend *frontend)
> +{
> +	atomic_dec(&frontend->users);
> +
> +	clk_disable_unprepare(frontend->ram_clk);
> +	clk_disable_unprepare(frontend->mod_clk);
> +	clk_disable_unprepare(frontend->bus_clk);

Maybe a blank line ?

> +	reset_control_assert(frontend->reset);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_exit);
> +
> +void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +	struct drm_gem_cma_object *gem;
> +	dma_addr_t paddr;
> +	int bpp;
> +
> +	/* Get the physical address of the buffer in memory */
> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
> +
> +	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
> +
> +	/* Set the line width */
> +	DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
> +		     fb->pitches[0]);
> +
> +	/* Compute the start of the displayed memory */
> +	bpp = fb->format->cpp[0];
> +	paddr = gem->paddr + fb->offsets[0];
> +	paddr += (state->src_x >> 16) * bpp;
> +	paddr += (state->src_y >> 16) * fb->pitches[0];
> +
> +	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
> +}
> +
> +static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
> +{
> +	switch (fmt) {
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_XRGB8888:
> +		*val = 3;
> +		return 0;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
> +{
> +	switch (fmt) {
> +	case DRM_FORMAT_ARGB8888:
> +		*val = 2;
> +		return 0;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane, uint32_t out_fmt)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +	u32 out_fmt_val;
> +	u32 in_fmt_val;
> +	int ret;
> +
> +	ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
> +						     &in_fmt_val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid input format\n");
> +		return ret;
> +	}
> +
> +	ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid output format\n");
> +		return ret;
> +	}
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400);
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400);
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, 0x151);
> +		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | */
> +		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(5) | */
> +		     /* SUN4I_FRONTEND_INPUT_FMT_PS(1)); */

Why are these commented ?

> +	regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, 0x82);
> +		     /* SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1)); */

Same here

> +
> +	return 0;
> +}
> +
> +void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
> +				 struct drm_plane *plane)
> +{
> +	struct drm_plane_state *state = plane->state;
> +
> +	/* Set height and width */
> +	DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
> +			 state->crtc_w, state->crtc_h);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
> +		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
> +					   state->src_w >> 16));
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
> +		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
> +					   state->src_w >> 16));
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
> +		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
> +		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
> +
> +	DRM_DEBUG_DRIVER("Frontend horizontal scaling factor %d.%d\n", 1, 0);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
> +		     state->src_w / state->crtc_w);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
> +		     state->src_w / state->crtc_w);
> +
> +	DRM_DEBUG_DRIVER("Frontend vertical scaling factor %d.%d\n", 1, 0);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
> +		     state->src_h / state->crtc_h);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
> +		     state->src_h / state->crtc_h);
> +
> +	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
> +			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
> +			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_coord);
> +
> +int sun4i_frontend_enable(struct sun4i_frontend *frontend)
> +{
> +	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
> +			  SUN4I_FRONTEND_FRM_CTRL_FRM_START,
> +			  SUN4I_FRONTEND_FRM_CTRL_FRM_START);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(sun4i_frontend_enable);
> +
> +static struct regmap_config sun4i_frontend_regmap_config = {
> +	.reg_bits	= 32,
> +	.val_bits	= 32,
> +	.reg_stride	= 4,
> +	.max_register	= 0x0a14,
> +};
> +
> +static int sun4i_frontend_bind(struct device *dev, struct device *master,
> +			 void *data)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct sun4i_frontend *frontend;
> +	struct drm_device *drm = data;
> +	struct sun4i_drv *drv = drm->dev_private;
> +	struct resource *res;
> +	void __iomem *regs;
> +
> +	frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
> +	if (!frontend)
> +		return -ENOMEM;

Blank line ?

> +	dev_set_drvdata(dev, frontend);
> +	frontend->node = dev->of_node;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	regs = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(regs))
> +		return PTR_ERR(regs);
> +
> +	frontend->regs = devm_regmap_init_mmio(dev, regs,
> +					       &sun4i_frontend_regmap_config);
> +	if (IS_ERR(frontend->regs)) {
> +		dev_err(dev, "Couldn't create the frontend regmap\n");
> +		return PTR_ERR(frontend->regs);
> +	}
> +
> +	frontend->reset = devm_reset_control_get(dev, NULL);
> +	if (IS_ERR(frontend->reset)) {
> +		dev_err(dev, "Couldn't get our reset line\n");
> +		return PTR_ERR(frontend->reset);
> +	}
> +
> +	frontend->bus_clk = devm_clk_get(dev, "ahb");
> +	if (IS_ERR(frontend->bus_clk)) {
> +		dev_err(dev, "Couldn't get our bus clock\n");
> +		return PTR_ERR(frontend->bus_clk);
> +	}
> +
> +	frontend->mod_clk = devm_clk_get(dev, "mod");
> +	if (IS_ERR(frontend->mod_clk)) {
> +		dev_err(dev, "Couldn't get our mod clock\n");
> +		return PTR_ERR(frontend->mod_clk);
> +	}
> +
> +	frontend->ram_clk = devm_clk_get(dev, "ram");
> +	if (IS_ERR(frontend->ram_clk)) {
> +		dev_err(dev, "Couldn't get our ram clock\n");
> +		return PTR_ERR(frontend->ram_clk);
> +	}
> +
> +	list_add_tail(&frontend->list, &drv->frontend_list);
> +
> +	return 0;
> +}
> +
> +static void sun4i_frontend_unbind(struct device *dev, struct device *master,
> +			    void *data)
> +{
> +	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +
> +	clk_disable_unprepare(frontend->mod_clk);
> +	clk_disable_unprepare(frontend->bus_clk);

Blank line ?

> +	reset_control_assert(frontend->reset);
> +}
> +
> +static const struct component_ops sun4i_frontend_ops = {
> +	.bind	= sun4i_frontend_bind,
> +	.unbind	= sun4i_frontend_unbind,
> +};
> +
> +static int sun4i_frontend_probe(struct platform_device *pdev)
> +{
> +	return component_add(&pdev->dev, &sun4i_frontend_ops);
> +}
> +
> +static int sun4i_frontend_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &sun4i_frontend_ops);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sun4i_frontend_of_table[] = {
> +	{ .compatible = "allwinner,sun5i-a13-display-frontend" },
> +	{ .compatible = "allwinner,sun6i-a31-display-frontend" },
> +	{ .compatible = "allwinner,sun8i-a33-display-frontend" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
> +
> +static struct platform_driver sun4i_frontend_driver = {
> +	.probe		= sun4i_frontend_probe,
> +	.remove		= sun4i_frontend_remove,
> +	.driver		= {
> +		.name		= "sun4i-frontend",
> +		.of_match_table	= sun4i_frontend_of_table,
> +	},
> +};
> +module_platform_driver(sun4i_frontend_driver);
> +
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
> +MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> new file mode 100644
> index 000000000000..2df9f6de0f3f
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> @@ -0,0 +1,102 @@

// SPDX-Licence-Identifier... new format ?

> +/*
> + * Copyright (C) 2017 Free Electrons
> + *
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#ifndef _SUN4I_FRONTEND_H_
> +#define _SUN4I_FRONTEND_H_
> +
> +#include <linux/atomic.h>
> +#include <linux/list.h>
> +
> +#define SUN4I_FRONTEND_EN_REG			0x000
> +#define SUN4I_FRONTEND_EN_EN				BIT(0)
> +
> +#define SUN4I_FRONTEND_FRM_CTRL_REG		0x004
> +#define SUN4I_FRONTEND_FRM_CTRL_FRM_START		BIT(16)
> +#define SUN4I_FRONTEND_FRM_CTRL_COEF_RDY		BIT(1)
> +#define SUN4I_FRONTEND_FRM_CTRL_REG_RDY			BIT(0)
> +
> +#define SUN4I_FRONTEND_BYPASS_REG		0x008
> +#define SUN4I_FRONTEND_BYPASS_CSC_EN			BIT(1)
> +
> +#define SUN4I_FRONTEND_BUF_ADDR0_REG		0x020
> +
> +#define SUN4I_FRONTEND_LINESTRD0_REG		0x040
> +
> +#define SUN4I_FRONTEND_INPUT_FMT_REG		0x04c
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod)		((mod) << 8)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt)		((fmt) << 4)
> +#define SUN4I_FRONTEND_INPUT_FMT_PS(ps)			(ps)
> +
> +#define SUN4I_FRONTEND_OUTPUT_FMT_REG		0x05c
> +#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt)		(fmt)
> +
> +#define SUN4I_FRONTEND_CH0_INSIZE_REG		0x100
> +#define SUN4I_FRONTEND_INSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
> +
> +#define SUN4I_FRONTEND_CH0_OUTSIZE_REG		0x104
> +#define SUN4I_FRONTEND_OUTSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
> +
> +#define SUN4I_FRONTEND_CH0_HORZFACT_REG		0x108
> +#define SUN4I_FRONTEND_HORZFACT(i, f)			(((i) << 16) | (f))
> +
> +#define SUN4I_FRONTEND_CH0_VERTFACT_REG		0x10c
> +#define SUN4I_FRONTEND_VERTFACT(i, f)			(((i) << 16) | (f))
> +
> +#define SUN4I_FRONTEND_CH0_HORZPHASE_REG	0x110
> +#define SUN4I_FRONTEND_CH0_VERTPHASE0_REG	0x114
> +#define SUN4I_FRONTEND_CH0_VERTPHASE1_REG	0x118
> +
> +#define SUN4I_FRONTEND_CH1_INSIZE_REG		0x200
> +#define SUN4I_FRONTEND_CH1_OUTSIZE_REG		0x204
> +#define SUN4I_FRONTEND_CH1_HORZFACT_REG		0x208
> +#define SUN4I_FRONTEND_CH1_VERTFACT_REG		0x20c
> +
> +#define SUN4I_FRONTEND_CH1_HORZPHASE_REG	0x210
> +#define SUN4I_FRONTEND_CH1_VERTPHASE0_REG	0x214
> +#define SUN4I_FRONTEND_CH1_VERTPHASE1_REG	0x218
> +
> +#define SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i)	(0x400 + i * 4)
> +#define SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i)	(0x480 + i * 4)
> +#define SUN4I_FRONTEND_CH0_VERTCOEF_REG(i)	(0x500 + i * 4)
> +#define SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i)	(0x600 + i * 4)
> +#define SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i)	(0x680 + i * 4)
> +#define SUN4I_FRONTEND_CH1_VERTCOEF_REG(i)	(0x700 + i * 4)
> +
> +struct clk;
> +struct device_node;
> +struct drm_plane;
> +struct regmap;
> +struct reset_control;
> +
> +struct sun4i_frontend {
> +	struct list_head	list;
> +	atomic_t		users;
> +	struct device_node	*node;
> +
> +	struct clk		*bus_clk;
> +	struct clk		*mod_clk;
> +	struct clk		*ram_clk;
> +	struct regmap		*regs;
> +	struct reset_control	*reset;
> +};
> +
> +int sun4i_frontend_init(struct sun4i_frontend *frontend);
> +void sun4i_frontend_exit(struct sun4i_frontend *frontend);
> +int sun4i_frontend_enable(struct sun4i_frontend *frontend);
> +
> +void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane);
> +void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
> +				 struct drm_plane *plane);
> +int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane, uint32_t out_fmt);
> +
> +#endif /* _SUN4I_FRONTEND_H_ */
> 

Apart these nits,
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* [PATCH 5/8] drm/sun4i: Add a driver for the display frontend
@ 2017-12-13 16:10       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/12/2017 16:33, Maxime Ripard wrote:
> The display frontend is an hardware block that can be used to implement
> some more advanced features like hardware scaling or colorspace
> conversions. It can also be used to implement the output format of the VPU.
> 
> Let's create a minimal driver for it that will only enable the hardware
> scaling features.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/Makefile         |   3 +-
>  drivers/gpu/drm/sun4i/sun4i_backend.c  |   5 +-
>  drivers/gpu/drm/sun4i/sun4i_backend.h  |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.c      |  16 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
>  7 files changed, 500 insertions(+), 5 deletions(-)
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h
> 
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index 0c2f8c7facae..b660d82011f4 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -1,5 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0
>  sun4i-backend-y			+= sun4i_backend.o sun4i_layer.o
> +sun4i-frontend-y		+= sun4i_frontend.o
>  
>  sun4i-drm-y			+= sun4i_drv.o
>  sun4i-drm-y			+= sun4i_framebuffer.o
> @@ -21,6 +22,6 @@ obj-$(CONFIG_DRM_SUN4I)		+= sun4i-tcon.o
>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
>  obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
>  
> -obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o
> +obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o sun4i-frontend.o
>  obj-$(CONFIG_DRM_SUN4I_HDMI)	+= sun4i-drm-hdmi.o
>  obj-$(CONFIG_DRM_SUN8I_MIXER)	+= sun8i-mixer.o
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index f971d3fb5ee4..e83e1fe43823 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -367,6 +367,11 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
>  	if (backend->engine.id < 0)
>  		return backend->engine.id;
>  
> +	backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
> +	if (IS_ERR(backend->frontend)) {
> +		dev_err(dev, "Couldn't find matching frontend, frontend features disabled\n");

Maybe a dev_warn ?

> +	}
> +
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	regs = devm_ioremap_resource(dev, res);
>  	if (IS_ERR(regs))
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index ac3cc029f5cd..ba1410fd5410 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -145,6 +145,7 @@
>  
>  struct sun4i_backend {
>  	struct sunxi_engine	engine;
> +	struct sun4i_frontend	*frontend;
>  
>  	struct reset_control	*reset;
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
> index 75c76cdd82bc..17bf9bfd98ba 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
> @@ -98,6 +98,7 @@ static int sun4i_drv_bind(struct device *dev)
>  		goto free_drm;
>  	}
>  	drm->dev_private = drv;
> +	INIT_LIST_HEAD(&drv->frontend_list);
>  	INIT_LIST_HEAD(&drv->engine_list);
>  	INIT_LIST_HEAD(&drv->tcon_list);
>  
> @@ -239,9 +240,11 @@ static int sun4i_drv_add_endpoints(struct device *dev,
>  	int count = 0;
>  
>  	/*
> -	 * We don't support the frontend for now, so we will never
> -	 * have a device bound. Just skip over it, but we still want
> -	 * the rest our pipeline to be added.
> +	 * The frontend has been disabled in all of our old device
> +	 * trees. If we find a node that is the frontend and is
> +	 * disabled, we should just follow through and parse its
> +	 * child, but without adding it to the component list.
> +	 * Otherwise, we obviously want to add it to the list.
>  	 */
>  	if (!sun4i_drv_node_is_frontend(node) &&
>  	    !of_device_is_available(node))
> @@ -254,7 +257,12 @@ static int sun4i_drv_add_endpoints(struct device *dev,
>  	if (sun4i_drv_node_is_connector(node))
>  		return 0;
>  
> -	if (!sun4i_drv_node_is_frontend(node)) {
> +	/*
> +	 * If the device is either just a regular device, or an
> +	 * enabled frontend, we add it to our component list.
> +	 */
> +	if (!sun4i_drv_node_is_frontend(node) ||
> +	    (sun4i_drv_node_is_frontend(node) && of_device_is_available(node))) {
>  		/* Add current component */
>  		DRM_DEBUG_DRIVER("Adding component %pOF\n", node);
>  		drm_of_component_match_add(dev, match, compare_of, node);
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
> index a960c89270cc..9c26a345f85c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
> @@ -19,6 +19,7 @@
>  
>  struct sun4i_drv {
>  	struct list_head	engine_list;
> +	struct list_head	frontend_list;
>  	struct list_head	tcon_list;
>  
>  	struct drm_fbdev_cma	*fbdev;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> new file mode 100644
> index 000000000000..1be0e86d1457
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> @@ -0,0 +1,377 @@

// SPDX-Licence-Identifier... new format ?

> +/*
> + * Copyright (C) 2017 Free Electrons
> + *
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +#include <drm/drmP.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#include "sun4i_drv.h"
> +#include "sun4i_frontend.h"
> +
> +static const u32 sun4i_frontend_vert_coef[32] = {
> +	0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
> +	0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
> +	0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
> +	0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
> +	0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
> +	0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
> +	0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
> +	0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
> +};
> +
> +static const u32 sun4i_frontend_horz_coef[64] = {
> +	0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
> +	0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
> +	0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
> +	0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
> +	0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
> +	0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
> +	0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
> +	0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
> +	0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
> +	0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
> +	0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
> +	0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
> +	0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
> +	0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
> +	0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
> +	0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
> +};
> +
> +static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
> +{
> +	int i;
> +
> +	for (i = 0; i < 32; i++) {
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i + 1]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i + 1]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
> +			     sun4i_frontend_vert_coef[i]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
> +			     sun4i_frontend_vert_coef[i]);
> +	}
> +
> +	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, BIT(23), BIT(23));
> +}
> +
> +int sun4i_frontend_init(struct sun4i_frontend *frontend)
> +{
> +	int ret;
> +
> +	if (atomic_read(&frontend->users))
> +		return -EBUSY;
> +
> +	ret = reset_control_deassert(frontend->reset);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Couldn't deassert our reset line\n");
> +		return ret;
> +	}
> +
> +	clk_set_rate(frontend->mod_clk, 300000000);
> +
> +	clk_prepare_enable(frontend->bus_clk);
> +	clk_prepare_enable(frontend->mod_clk);
> +	clk_prepare_enable(frontend->ram_clk);
> +
> +	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
> +			   SUN4I_FRONTEND_EN_EN,
> +			   SUN4I_FRONTEND_EN_EN);
> +
> +	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
> +			   SUN4I_FRONTEND_BYPASS_CSC_EN,
> +			   SUN4I_FRONTEND_BYPASS_CSC_EN);
> +
> +	sun4i_frontend_scaler_init(frontend);
> +
> +	atomic_inc(&frontend->users);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(sun4i_frontend_init);
> +
> +void sun4i_frontend_exit(struct sun4i_frontend *frontend)
> +{
> +	atomic_dec(&frontend->users);
> +
> +	clk_disable_unprepare(frontend->ram_clk);
> +	clk_disable_unprepare(frontend->mod_clk);
> +	clk_disable_unprepare(frontend->bus_clk);

Maybe a blank line ?

> +	reset_control_assert(frontend->reset);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_exit);
> +
> +void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +	struct drm_gem_cma_object *gem;
> +	dma_addr_t paddr;
> +	int bpp;
> +
> +	/* Get the physical address of the buffer in memory */
> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
> +
> +	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
> +
> +	/* Set the line width */
> +	DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
> +		     fb->pitches[0]);
> +
> +	/* Compute the start of the displayed memory */
> +	bpp = fb->format->cpp[0];
> +	paddr = gem->paddr + fb->offsets[0];
> +	paddr += (state->src_x >> 16) * bpp;
> +	paddr += (state->src_y >> 16) * fb->pitches[0];
> +
> +	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
> +}
> +
> +static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
> +{
> +	switch (fmt) {
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_XRGB8888:
> +		*val = 3;
> +		return 0;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
> +{
> +	switch (fmt) {
> +	case DRM_FORMAT_ARGB8888:
> +		*val = 2;
> +		return 0;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane, uint32_t out_fmt)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +	u32 out_fmt_val;
> +	u32 in_fmt_val;
> +	int ret;
> +
> +	ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
> +						     &in_fmt_val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid input format\n");
> +		return ret;
> +	}
> +
> +	ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid output format\n");
> +		return ret;
> +	}
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400);
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400);
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, 0x151);
> +		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | */
> +		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(5) | */
> +		     /* SUN4I_FRONTEND_INPUT_FMT_PS(1)); */

Why are these commented ?

> +	regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, 0x82);
> +		     /* SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1)); */

Same here

> +
> +	return 0;
> +}
> +
> +void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
> +				 struct drm_plane *plane)
> +{
> +	struct drm_plane_state *state = plane->state;
> +
> +	/* Set height and width */
> +	DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
> +			 state->crtc_w, state->crtc_h);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
> +		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
> +					   state->src_w >> 16));
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
> +		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
> +					   state->src_w >> 16));
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
> +		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
> +		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
> +
> +	DRM_DEBUG_DRIVER("Frontend horizontal scaling factor %d.%d\n", 1, 0);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
> +		     state->src_w / state->crtc_w);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
> +		     state->src_w / state->crtc_w);
> +
> +	DRM_DEBUG_DRIVER("Frontend vertical scaling factor %d.%d\n", 1, 0);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
> +		     state->src_h / state->crtc_h);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
> +		     state->src_h / state->crtc_h);
> +
> +	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
> +			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
> +			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_coord);
> +
> +int sun4i_frontend_enable(struct sun4i_frontend *frontend)
> +{
> +	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
> +			  SUN4I_FRONTEND_FRM_CTRL_FRM_START,
> +			  SUN4I_FRONTEND_FRM_CTRL_FRM_START);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(sun4i_frontend_enable);
> +
> +static struct regmap_config sun4i_frontend_regmap_config = {
> +	.reg_bits	= 32,
> +	.val_bits	= 32,
> +	.reg_stride	= 4,
> +	.max_register	= 0x0a14,
> +};
> +
> +static int sun4i_frontend_bind(struct device *dev, struct device *master,
> +			 void *data)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct sun4i_frontend *frontend;
> +	struct drm_device *drm = data;
> +	struct sun4i_drv *drv = drm->dev_private;
> +	struct resource *res;
> +	void __iomem *regs;
> +
> +	frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
> +	if (!frontend)
> +		return -ENOMEM;

Blank line ?

> +	dev_set_drvdata(dev, frontend);
> +	frontend->node = dev->of_node;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	regs = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(regs))
> +		return PTR_ERR(regs);
> +
> +	frontend->regs = devm_regmap_init_mmio(dev, regs,
> +					       &sun4i_frontend_regmap_config);
> +	if (IS_ERR(frontend->regs)) {
> +		dev_err(dev, "Couldn't create the frontend regmap\n");
> +		return PTR_ERR(frontend->regs);
> +	}
> +
> +	frontend->reset = devm_reset_control_get(dev, NULL);
> +	if (IS_ERR(frontend->reset)) {
> +		dev_err(dev, "Couldn't get our reset line\n");
> +		return PTR_ERR(frontend->reset);
> +	}
> +
> +	frontend->bus_clk = devm_clk_get(dev, "ahb");
> +	if (IS_ERR(frontend->bus_clk)) {
> +		dev_err(dev, "Couldn't get our bus clock\n");
> +		return PTR_ERR(frontend->bus_clk);
> +	}
> +
> +	frontend->mod_clk = devm_clk_get(dev, "mod");
> +	if (IS_ERR(frontend->mod_clk)) {
> +		dev_err(dev, "Couldn't get our mod clock\n");
> +		return PTR_ERR(frontend->mod_clk);
> +	}
> +
> +	frontend->ram_clk = devm_clk_get(dev, "ram");
> +	if (IS_ERR(frontend->ram_clk)) {
> +		dev_err(dev, "Couldn't get our ram clock\n");
> +		return PTR_ERR(frontend->ram_clk);
> +	}
> +
> +	list_add_tail(&frontend->list, &drv->frontend_list);
> +
> +	return 0;
> +}
> +
> +static void sun4i_frontend_unbind(struct device *dev, struct device *master,
> +			    void *data)
> +{
> +	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +
> +	clk_disable_unprepare(frontend->mod_clk);
> +	clk_disable_unprepare(frontend->bus_clk);

Blank line ?

> +	reset_control_assert(frontend->reset);
> +}
> +
> +static const struct component_ops sun4i_frontend_ops = {
> +	.bind	= sun4i_frontend_bind,
> +	.unbind	= sun4i_frontend_unbind,
> +};
> +
> +static int sun4i_frontend_probe(struct platform_device *pdev)
> +{
> +	return component_add(&pdev->dev, &sun4i_frontend_ops);
> +}
> +
> +static int sun4i_frontend_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &sun4i_frontend_ops);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sun4i_frontend_of_table[] = {
> +	{ .compatible = "allwinner,sun5i-a13-display-frontend" },
> +	{ .compatible = "allwinner,sun6i-a31-display-frontend" },
> +	{ .compatible = "allwinner,sun8i-a33-display-frontend" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
> +
> +static struct platform_driver sun4i_frontend_driver = {
> +	.probe		= sun4i_frontend_probe,
> +	.remove		= sun4i_frontend_remove,
> +	.driver		= {
> +		.name		= "sun4i-frontend",
> +		.of_match_table	= sun4i_frontend_of_table,
> +	},
> +};
> +module_platform_driver(sun4i_frontend_driver);
> +
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
> +MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> new file mode 100644
> index 000000000000..2df9f6de0f3f
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> @@ -0,0 +1,102 @@

// SPDX-Licence-Identifier... new format ?

> +/*
> + * Copyright (C) 2017 Free Electrons
> + *
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#ifndef _SUN4I_FRONTEND_H_
> +#define _SUN4I_FRONTEND_H_
> +
> +#include <linux/atomic.h>
> +#include <linux/list.h>
> +
> +#define SUN4I_FRONTEND_EN_REG			0x000
> +#define SUN4I_FRONTEND_EN_EN				BIT(0)
> +
> +#define SUN4I_FRONTEND_FRM_CTRL_REG		0x004
> +#define SUN4I_FRONTEND_FRM_CTRL_FRM_START		BIT(16)
> +#define SUN4I_FRONTEND_FRM_CTRL_COEF_RDY		BIT(1)
> +#define SUN4I_FRONTEND_FRM_CTRL_REG_RDY			BIT(0)
> +
> +#define SUN4I_FRONTEND_BYPASS_REG		0x008
> +#define SUN4I_FRONTEND_BYPASS_CSC_EN			BIT(1)
> +
> +#define SUN4I_FRONTEND_BUF_ADDR0_REG		0x020
> +
> +#define SUN4I_FRONTEND_LINESTRD0_REG		0x040
> +
> +#define SUN4I_FRONTEND_INPUT_FMT_REG		0x04c
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod)		((mod) << 8)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt)		((fmt) << 4)
> +#define SUN4I_FRONTEND_INPUT_FMT_PS(ps)			(ps)
> +
> +#define SUN4I_FRONTEND_OUTPUT_FMT_REG		0x05c
> +#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt)		(fmt)
> +
> +#define SUN4I_FRONTEND_CH0_INSIZE_REG		0x100
> +#define SUN4I_FRONTEND_INSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
> +
> +#define SUN4I_FRONTEND_CH0_OUTSIZE_REG		0x104
> +#define SUN4I_FRONTEND_OUTSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
> +
> +#define SUN4I_FRONTEND_CH0_HORZFACT_REG		0x108
> +#define SUN4I_FRONTEND_HORZFACT(i, f)			(((i) << 16) | (f))
> +
> +#define SUN4I_FRONTEND_CH0_VERTFACT_REG		0x10c
> +#define SUN4I_FRONTEND_VERTFACT(i, f)			(((i) << 16) | (f))
> +
> +#define SUN4I_FRONTEND_CH0_HORZPHASE_REG	0x110
> +#define SUN4I_FRONTEND_CH0_VERTPHASE0_REG	0x114
> +#define SUN4I_FRONTEND_CH0_VERTPHASE1_REG	0x118
> +
> +#define SUN4I_FRONTEND_CH1_INSIZE_REG		0x200
> +#define SUN4I_FRONTEND_CH1_OUTSIZE_REG		0x204
> +#define SUN4I_FRONTEND_CH1_HORZFACT_REG		0x208
> +#define SUN4I_FRONTEND_CH1_VERTFACT_REG		0x20c
> +
> +#define SUN4I_FRONTEND_CH1_HORZPHASE_REG	0x210
> +#define SUN4I_FRONTEND_CH1_VERTPHASE0_REG	0x214
> +#define SUN4I_FRONTEND_CH1_VERTPHASE1_REG	0x218
> +
> +#define SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i)	(0x400 + i * 4)
> +#define SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i)	(0x480 + i * 4)
> +#define SUN4I_FRONTEND_CH0_VERTCOEF_REG(i)	(0x500 + i * 4)
> +#define SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i)	(0x600 + i * 4)
> +#define SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i)	(0x680 + i * 4)
> +#define SUN4I_FRONTEND_CH1_VERTCOEF_REG(i)	(0x700 + i * 4)
> +
> +struct clk;
> +struct device_node;
> +struct drm_plane;
> +struct regmap;
> +struct reset_control;
> +
> +struct sun4i_frontend {
> +	struct list_head	list;
> +	atomic_t		users;
> +	struct device_node	*node;
> +
> +	struct clk		*bus_clk;
> +	struct clk		*mod_clk;
> +	struct clk		*ram_clk;
> +	struct regmap		*regs;
> +	struct reset_control	*reset;
> +};
> +
> +int sun4i_frontend_init(struct sun4i_frontend *frontend);
> +void sun4i_frontend_exit(struct sun4i_frontend *frontend);
> +int sun4i_frontend_enable(struct sun4i_frontend *frontend);
> +
> +void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane);
> +void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
> +				 struct drm_plane *plane);
> +int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane, uint32_t out_fmt);
> +
> +#endif /* _SUN4I_FRONTEND_H_ */
> 

Apart these nits,
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* Re: [PATCH 5/8] drm/sun4i: Add a driver for the display frontend
@ 2017-12-13 16:10       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:10 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: Thomas Petazzoni, dri-devel, linux-kernel, linux-arm-kernel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> The display frontend is an hardware block that can be used to implement
> some more advanced features like hardware scaling or colorspace
> conversions. It can also be used to implement the output format of the VPU.
> 
> Let's create a minimal driver for it that will only enable the hardware
> scaling features.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/Makefile         |   3 +-
>  drivers/gpu/drm/sun4i/sun4i_backend.c  |   5 +-
>  drivers/gpu/drm/sun4i/sun4i_backend.h  |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.c      |  16 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
>  7 files changed, 500 insertions(+), 5 deletions(-)
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h
> 
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index 0c2f8c7facae..b660d82011f4 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -1,5 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0
>  sun4i-backend-y			+= sun4i_backend.o sun4i_layer.o
> +sun4i-frontend-y		+= sun4i_frontend.o
>  
>  sun4i-drm-y			+= sun4i_drv.o
>  sun4i-drm-y			+= sun4i_framebuffer.o
> @@ -21,6 +22,6 @@ obj-$(CONFIG_DRM_SUN4I)		+= sun4i-tcon.o
>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
>  obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
>  
> -obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o
> +obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o sun4i-frontend.o
>  obj-$(CONFIG_DRM_SUN4I_HDMI)	+= sun4i-drm-hdmi.o
>  obj-$(CONFIG_DRM_SUN8I_MIXER)	+= sun8i-mixer.o
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index f971d3fb5ee4..e83e1fe43823 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -367,6 +367,11 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
>  	if (backend->engine.id < 0)
>  		return backend->engine.id;
>  
> +	backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
> +	if (IS_ERR(backend->frontend)) {
> +		dev_err(dev, "Couldn't find matching frontend, frontend features disabled\n");

Maybe a dev_warn ?

> +	}
> +
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	regs = devm_ioremap_resource(dev, res);
>  	if (IS_ERR(regs))
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index ac3cc029f5cd..ba1410fd5410 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -145,6 +145,7 @@
>  
>  struct sun4i_backend {
>  	struct sunxi_engine	engine;
> +	struct sun4i_frontend	*frontend;
>  
>  	struct reset_control	*reset;
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
> index 75c76cdd82bc..17bf9bfd98ba 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
> @@ -98,6 +98,7 @@ static int sun4i_drv_bind(struct device *dev)
>  		goto free_drm;
>  	}
>  	drm->dev_private = drv;
> +	INIT_LIST_HEAD(&drv->frontend_list);
>  	INIT_LIST_HEAD(&drv->engine_list);
>  	INIT_LIST_HEAD(&drv->tcon_list);
>  
> @@ -239,9 +240,11 @@ static int sun4i_drv_add_endpoints(struct device *dev,
>  	int count = 0;
>  
>  	/*
> -	 * We don't support the frontend for now, so we will never
> -	 * have a device bound. Just skip over it, but we still want
> -	 * the rest our pipeline to be added.
> +	 * The frontend has been disabled in all of our old device
> +	 * trees. If we find a node that is the frontend and is
> +	 * disabled, we should just follow through and parse its
> +	 * child, but without adding it to the component list.
> +	 * Otherwise, we obviously want to add it to the list.
>  	 */
>  	if (!sun4i_drv_node_is_frontend(node) &&
>  	    !of_device_is_available(node))
> @@ -254,7 +257,12 @@ static int sun4i_drv_add_endpoints(struct device *dev,
>  	if (sun4i_drv_node_is_connector(node))
>  		return 0;
>  
> -	if (!sun4i_drv_node_is_frontend(node)) {
> +	/*
> +	 * If the device is either just a regular device, or an
> +	 * enabled frontend, we add it to our component list.
> +	 */
> +	if (!sun4i_drv_node_is_frontend(node) ||
> +	    (sun4i_drv_node_is_frontend(node) && of_device_is_available(node))) {
>  		/* Add current component */
>  		DRM_DEBUG_DRIVER("Adding component %pOF\n", node);
>  		drm_of_component_match_add(dev, match, compare_of, node);
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
> index a960c89270cc..9c26a345f85c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
> @@ -19,6 +19,7 @@
>  
>  struct sun4i_drv {
>  	struct list_head	engine_list;
> +	struct list_head	frontend_list;
>  	struct list_head	tcon_list;
>  
>  	struct drm_fbdev_cma	*fbdev;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> new file mode 100644
> index 000000000000..1be0e86d1457
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> @@ -0,0 +1,377 @@

// SPDX-Licence-Identifier... new format ?

> +/*
> + * Copyright (C) 2017 Free Electrons
> + *
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +#include <drm/drmP.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#include "sun4i_drv.h"
> +#include "sun4i_frontend.h"
> +
> +static const u32 sun4i_frontend_vert_coef[32] = {
> +	0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
> +	0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
> +	0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
> +	0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
> +	0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
> +	0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
> +	0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
> +	0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
> +};
> +
> +static const u32 sun4i_frontend_horz_coef[64] = {
> +	0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
> +	0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
> +	0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
> +	0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
> +	0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
> +	0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
> +	0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
> +	0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
> +	0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
> +	0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
> +	0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
> +	0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
> +	0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
> +	0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
> +	0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
> +	0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
> +};
> +
> +static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
> +{
> +	int i;
> +
> +	for (i = 0; i < 32; i++) {
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i + 1]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
> +			     sun4i_frontend_horz_coef[2 * i + 1]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
> +			     sun4i_frontend_vert_coef[i]);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
> +			     sun4i_frontend_vert_coef[i]);
> +	}
> +
> +	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, BIT(23), BIT(23));
> +}
> +
> +int sun4i_frontend_init(struct sun4i_frontend *frontend)
> +{
> +	int ret;
> +
> +	if (atomic_read(&frontend->users))
> +		return -EBUSY;
> +
> +	ret = reset_control_deassert(frontend->reset);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Couldn't deassert our reset line\n");
> +		return ret;
> +	}
> +
> +	clk_set_rate(frontend->mod_clk, 300000000);
> +
> +	clk_prepare_enable(frontend->bus_clk);
> +	clk_prepare_enable(frontend->mod_clk);
> +	clk_prepare_enable(frontend->ram_clk);
> +
> +	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
> +			   SUN4I_FRONTEND_EN_EN,
> +			   SUN4I_FRONTEND_EN_EN);
> +
> +	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
> +			   SUN4I_FRONTEND_BYPASS_CSC_EN,
> +			   SUN4I_FRONTEND_BYPASS_CSC_EN);
> +
> +	sun4i_frontend_scaler_init(frontend);
> +
> +	atomic_inc(&frontend->users);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(sun4i_frontend_init);
> +
> +void sun4i_frontend_exit(struct sun4i_frontend *frontend)
> +{
> +	atomic_dec(&frontend->users);
> +
> +	clk_disable_unprepare(frontend->ram_clk);
> +	clk_disable_unprepare(frontend->mod_clk);
> +	clk_disable_unprepare(frontend->bus_clk);

Maybe a blank line ?

> +	reset_control_assert(frontend->reset);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_exit);
> +
> +void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +	struct drm_gem_cma_object *gem;
> +	dma_addr_t paddr;
> +	int bpp;
> +
> +	/* Get the physical address of the buffer in memory */
> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
> +
> +	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
> +
> +	/* Set the line width */
> +	DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
> +		     fb->pitches[0]);
> +
> +	/* Compute the start of the displayed memory */
> +	bpp = fb->format->cpp[0];
> +	paddr = gem->paddr + fb->offsets[0];
> +	paddr += (state->src_x >> 16) * bpp;
> +	paddr += (state->src_y >> 16) * fb->pitches[0];
> +
> +	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
> +}
> +
> +static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
> +{
> +	switch (fmt) {
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_XRGB8888:
> +		*val = 3;
> +		return 0;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
> +{
> +	switch (fmt) {
> +	case DRM_FORMAT_ARGB8888:
> +		*val = 2;
> +		return 0;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane, uint32_t out_fmt)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +	u32 out_fmt_val;
> +	u32 in_fmt_val;
> +	int ret;
> +
> +	ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
> +						     &in_fmt_val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid input format\n");
> +		return ret;
> +	}
> +
> +	ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid output format\n");
> +		return ret;
> +	}
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400);
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400);
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, 0x151);
> +		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | */
> +		     /* SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(5) | */
> +		     /* SUN4I_FRONTEND_INPUT_FMT_PS(1)); */

Why are these commented ?

> +	regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, 0x82);
> +		     /* SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1)); */

Same here

> +
> +	return 0;
> +}
> +
> +void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
> +				 struct drm_plane *plane)
> +{
> +	struct drm_plane_state *state = plane->state;
> +
> +	/* Set height and width */
> +	DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
> +			 state->crtc_w, state->crtc_h);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
> +		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
> +					   state->src_w >> 16));
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
> +		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
> +					   state->src_w >> 16));
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
> +		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
> +		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
> +
> +	DRM_DEBUG_DRIVER("Frontend horizontal scaling factor %d.%d\n", 1, 0);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
> +		     state->src_w / state->crtc_w);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
> +		     state->src_w / state->crtc_w);
> +
> +	DRM_DEBUG_DRIVER("Frontend vertical scaling factor %d.%d\n", 1, 0);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
> +		     state->src_h / state->crtc_h);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
> +		     state->src_h / state->crtc_h);
> +
> +	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
> +			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
> +			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_coord);
> +
> +int sun4i_frontend_enable(struct sun4i_frontend *frontend)
> +{
> +	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
> +			  SUN4I_FRONTEND_FRM_CTRL_FRM_START,
> +			  SUN4I_FRONTEND_FRM_CTRL_FRM_START);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(sun4i_frontend_enable);
> +
> +static struct regmap_config sun4i_frontend_regmap_config = {
> +	.reg_bits	= 32,
> +	.val_bits	= 32,
> +	.reg_stride	= 4,
> +	.max_register	= 0x0a14,
> +};
> +
> +static int sun4i_frontend_bind(struct device *dev, struct device *master,
> +			 void *data)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct sun4i_frontend *frontend;
> +	struct drm_device *drm = data;
> +	struct sun4i_drv *drv = drm->dev_private;
> +	struct resource *res;
> +	void __iomem *regs;
> +
> +	frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
> +	if (!frontend)
> +		return -ENOMEM;

Blank line ?

> +	dev_set_drvdata(dev, frontend);
> +	frontend->node = dev->of_node;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	regs = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(regs))
> +		return PTR_ERR(regs);
> +
> +	frontend->regs = devm_regmap_init_mmio(dev, regs,
> +					       &sun4i_frontend_regmap_config);
> +	if (IS_ERR(frontend->regs)) {
> +		dev_err(dev, "Couldn't create the frontend regmap\n");
> +		return PTR_ERR(frontend->regs);
> +	}
> +
> +	frontend->reset = devm_reset_control_get(dev, NULL);
> +	if (IS_ERR(frontend->reset)) {
> +		dev_err(dev, "Couldn't get our reset line\n");
> +		return PTR_ERR(frontend->reset);
> +	}
> +
> +	frontend->bus_clk = devm_clk_get(dev, "ahb");
> +	if (IS_ERR(frontend->bus_clk)) {
> +		dev_err(dev, "Couldn't get our bus clock\n");
> +		return PTR_ERR(frontend->bus_clk);
> +	}
> +
> +	frontend->mod_clk = devm_clk_get(dev, "mod");
> +	if (IS_ERR(frontend->mod_clk)) {
> +		dev_err(dev, "Couldn't get our mod clock\n");
> +		return PTR_ERR(frontend->mod_clk);
> +	}
> +
> +	frontend->ram_clk = devm_clk_get(dev, "ram");
> +	if (IS_ERR(frontend->ram_clk)) {
> +		dev_err(dev, "Couldn't get our ram clock\n");
> +		return PTR_ERR(frontend->ram_clk);
> +	}
> +
> +	list_add_tail(&frontend->list, &drv->frontend_list);
> +
> +	return 0;
> +}
> +
> +static void sun4i_frontend_unbind(struct device *dev, struct device *master,
> +			    void *data)
> +{
> +	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +
> +	clk_disable_unprepare(frontend->mod_clk);
> +	clk_disable_unprepare(frontend->bus_clk);

Blank line ?

> +	reset_control_assert(frontend->reset);
> +}
> +
> +static const struct component_ops sun4i_frontend_ops = {
> +	.bind	= sun4i_frontend_bind,
> +	.unbind	= sun4i_frontend_unbind,
> +};
> +
> +static int sun4i_frontend_probe(struct platform_device *pdev)
> +{
> +	return component_add(&pdev->dev, &sun4i_frontend_ops);
> +}
> +
> +static int sun4i_frontend_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &sun4i_frontend_ops);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sun4i_frontend_of_table[] = {
> +	{ .compatible = "allwinner,sun5i-a13-display-frontend" },
> +	{ .compatible = "allwinner,sun6i-a31-display-frontend" },
> +	{ .compatible = "allwinner,sun8i-a33-display-frontend" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
> +
> +static struct platform_driver sun4i_frontend_driver = {
> +	.probe		= sun4i_frontend_probe,
> +	.remove		= sun4i_frontend_remove,
> +	.driver		= {
> +		.name		= "sun4i-frontend",
> +		.of_match_table	= sun4i_frontend_of_table,
> +	},
> +};
> +module_platform_driver(sun4i_frontend_driver);
> +
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
> +MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> new file mode 100644
> index 000000000000..2df9f6de0f3f
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> @@ -0,0 +1,102 @@

// SPDX-Licence-Identifier... new format ?

> +/*
> + * Copyright (C) 2017 Free Electrons
> + *
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#ifndef _SUN4I_FRONTEND_H_
> +#define _SUN4I_FRONTEND_H_
> +
> +#include <linux/atomic.h>
> +#include <linux/list.h>
> +
> +#define SUN4I_FRONTEND_EN_REG			0x000
> +#define SUN4I_FRONTEND_EN_EN				BIT(0)
> +
> +#define SUN4I_FRONTEND_FRM_CTRL_REG		0x004
> +#define SUN4I_FRONTEND_FRM_CTRL_FRM_START		BIT(16)
> +#define SUN4I_FRONTEND_FRM_CTRL_COEF_RDY		BIT(1)
> +#define SUN4I_FRONTEND_FRM_CTRL_REG_RDY			BIT(0)
> +
> +#define SUN4I_FRONTEND_BYPASS_REG		0x008
> +#define SUN4I_FRONTEND_BYPASS_CSC_EN			BIT(1)
> +
> +#define SUN4I_FRONTEND_BUF_ADDR0_REG		0x020
> +
> +#define SUN4I_FRONTEND_LINESTRD0_REG		0x040
> +
> +#define SUN4I_FRONTEND_INPUT_FMT_REG		0x04c
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod)		((mod) << 8)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt)		((fmt) << 4)
> +#define SUN4I_FRONTEND_INPUT_FMT_PS(ps)			(ps)
> +
> +#define SUN4I_FRONTEND_OUTPUT_FMT_REG		0x05c
> +#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt)		(fmt)
> +
> +#define SUN4I_FRONTEND_CH0_INSIZE_REG		0x100
> +#define SUN4I_FRONTEND_INSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
> +
> +#define SUN4I_FRONTEND_CH0_OUTSIZE_REG		0x104
> +#define SUN4I_FRONTEND_OUTSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
> +
> +#define SUN4I_FRONTEND_CH0_HORZFACT_REG		0x108
> +#define SUN4I_FRONTEND_HORZFACT(i, f)			(((i) << 16) | (f))
> +
> +#define SUN4I_FRONTEND_CH0_VERTFACT_REG		0x10c
> +#define SUN4I_FRONTEND_VERTFACT(i, f)			(((i) << 16) | (f))
> +
> +#define SUN4I_FRONTEND_CH0_HORZPHASE_REG	0x110
> +#define SUN4I_FRONTEND_CH0_VERTPHASE0_REG	0x114
> +#define SUN4I_FRONTEND_CH0_VERTPHASE1_REG	0x118
> +
> +#define SUN4I_FRONTEND_CH1_INSIZE_REG		0x200
> +#define SUN4I_FRONTEND_CH1_OUTSIZE_REG		0x204
> +#define SUN4I_FRONTEND_CH1_HORZFACT_REG		0x208
> +#define SUN4I_FRONTEND_CH1_VERTFACT_REG		0x20c
> +
> +#define SUN4I_FRONTEND_CH1_HORZPHASE_REG	0x210
> +#define SUN4I_FRONTEND_CH1_VERTPHASE0_REG	0x214
> +#define SUN4I_FRONTEND_CH1_VERTPHASE1_REG	0x218
> +
> +#define SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i)	(0x400 + i * 4)
> +#define SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i)	(0x480 + i * 4)
> +#define SUN4I_FRONTEND_CH0_VERTCOEF_REG(i)	(0x500 + i * 4)
> +#define SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i)	(0x600 + i * 4)
> +#define SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i)	(0x680 + i * 4)
> +#define SUN4I_FRONTEND_CH1_VERTCOEF_REG(i)	(0x700 + i * 4)
> +
> +struct clk;
> +struct device_node;
> +struct drm_plane;
> +struct regmap;
> +struct reset_control;
> +
> +struct sun4i_frontend {
> +	struct list_head	list;
> +	atomic_t		users;
> +	struct device_node	*node;
> +
> +	struct clk		*bus_clk;
> +	struct clk		*mod_clk;
> +	struct clk		*ram_clk;
> +	struct regmap		*regs;
> +	struct reset_control	*reset;
> +};
> +
> +int sun4i_frontend_init(struct sun4i_frontend *frontend);
> +void sun4i_frontend_exit(struct sun4i_frontend *frontend);
> +int sun4i_frontend_enable(struct sun4i_frontend *frontend);
> +
> +void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane);
> +void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
> +				 struct drm_plane *plane);
> +int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
> +				  struct drm_plane *plane, uint32_t out_fmt);
> +
> +#endif /* _SUN4I_FRONTEND_H_ */
> 

Apart these nits,
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
  2017-12-13 15:33     ` Maxime Ripard
  (?)
@ 2017-12-13 16:11       ` Neil Armstrong
  -1 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:11 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> Now that we have a driver, we can make use of it. This is done by
> adding a flag to our custom plane state that will trigger whether we should
> use the frontend on that particular plane or not.
> 
> The rest is just plumbing to set up the backend to not perform the DMA but
> receive its data from the frontend.
> 
> Note that we're still not making any use of the frontend itself, as no one
> is setting the flag yet.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 53 ++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h |  3 ++-
>  drivers/gpu/drm/sun4i/sun4i_layer.c   | 27 ++++++++++++--
>  drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
>  4 files changed, 81 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index e83e1fe43823..f1d19767c55d 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -26,6 +26,7 @@
>  
>  #include "sun4i_backend.h"
>  #include "sun4i_drv.h"
> +#include "sun4i_frontend.h"
>  #include "sun4i_layer.h"
>  #include "sunxi_engine.h"
>  
> @@ -203,6 +204,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>  	return 0;
>  }
>  
> +int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
> +					int layer, uint32_t fmt)
> +{
> +	u32 val;
> +	int ret;
> +
> +	ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid format\n");
> +		return ret;
> +	}
> +
> +	regmap_update_bits(backend->engine.regs,
> +			   SUN4I_BACKEND_ATTCTL_REG0(layer),
> +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
> +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
> +
> +	regmap_update_bits(backend->engine.regs,
> +			   SUN4I_BACKEND_ATTCTL_REG1(layer),
> +			   SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
> +
> +	return 0;
> +}
> +
>  int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  				      int layer, struct drm_plane *plane)
>  {
> @@ -330,6 +355,34 @@ static int sun4i_backend_of_get_id(struct device_node *node)
>  	return ret;
>  }
>  
> +static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
> +							  struct device_node *node)
> +{
> +	struct device_node *port, *ep, *remote;
> +	struct sun4i_frontend *frontend;
> +
> +	port = of_graph_get_port_by_id(node, 0);
> +	if (!port)
> +		return ERR_PTR(-EINVAL);
> +
> +	for_each_available_child_of_node(port, ep) {
> +		remote = of_graph_get_remote_port_parent(ep);
> +		if (!remote)
> +			continue;
> +
> +		/* does this node match any registered engines? */
> +		list_for_each_entry(frontend, &drv->frontend_list, list) {
> +			if (remote == frontend->node) {
> +				of_node_put(remote);
> +				of_node_put(port);
> +				return frontend;
> +			}
> +		}
> +	}
> +
> +	return ERR_PTR(-EINVAL);
> +}
> +
>  static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
>  	.commit				= sun4i_backend_commit,
>  	.layers_init			= sun4i_layers_init,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index ba1410fd5410..636a51521e77 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -72,6 +72,7 @@
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x)		((x) << 15)
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK	GENMASK(11, 10)
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x)			((x) << 10)
> +#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN		BIT(1)
>  
>  #define SUN4I_BACKEND_ATTCTL_REG1(l)		(0x8a0 + (0x4 * (l)))
>  #define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT		GENMASK(15, 14)
> @@ -171,5 +172,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>  				       int layer, struct drm_plane *plane);
>  int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  				      int layer, struct drm_plane *plane);
> +int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
> +					int layer, uint32_t in_fmt);
>  
>  #endif /* _SUN4I_BACKEND_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
> index c3afcf888906..3b58667a06dc 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -15,6 +15,7 @@
>  #include <drm/drmP.h>
>  
>  #include "sun4i_backend.h"
> +#include "sun4i_frontend.h"
>  #include "sun4i_layer.h"
>  #include "sunxi_engine.h"
>  
> @@ -70,21 +71,41 @@ static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
>  static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
>  					       struct drm_plane_state *old_state)
>  {
> +	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
>  	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
>  	struct sun4i_backend *backend = layer->backend;
> +	struct sun4i_frontend *frontend = backend->frontend;
>  
>  	sun4i_backend_layer_enable(backend, layer->id, false);
> +
> +	if (layer_state->uses_frontend)
> +		sun4i_frontend_exit(frontend);
>  }
>  
>  static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
>  					      struct drm_plane_state *old_state)
>  {
> +	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
>  	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
>  	struct sun4i_backend *backend = layer->backend;
> +	struct sun4i_frontend *frontend = backend->frontend;
> +
> +	if (layer_state->uses_frontend) {
> +		sun4i_frontend_init(frontend);
> +		sun4i_frontend_update_coord(frontend, plane);
> +		sun4i_frontend_update_buffer(frontend, plane);
> +		sun4i_frontend_update_formats(frontend, plane,
> +					      DRM_FORMAT_ARGB8888);
> +		sun4i_backend_update_layer_frontend(backend, layer->id,
> +						    DRM_FORMAT_ARGB8888);
> +		sun4i_backend_update_layer_coord(backend, layer->id, plane);
> +		sun4i_frontend_enable(frontend);
> +	} else {
> +		sun4i_backend_update_layer_coord(backend, layer->id, plane);
> +		sun4i_backend_update_layer_formats(backend, layer->id, plane);
> +		sun4i_backend_update_layer_buffer(backend, layer->id, plane);
> +	}
>  
> -	sun4i_backend_update_layer_coord(backend, layer->id, plane);
> -	sun4i_backend_update_layer_formats(backend, layer->id, plane);
> -	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
>  	sun4i_backend_layer_enable(backend, layer->id, true);
>  }
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
> index d2c19348d1b0..75b4868ba87c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
> @@ -24,6 +24,7 @@ struct sun4i_layer {
>  
>  struct sun4i_layer_state {
>  	struct drm_plane_state	state;
> +	bool			uses_frontend;
>  };
>  
>  static inline struct sun4i_layer *
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
@ 2017-12-13 16:11       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/12/2017 16:33, Maxime Ripard wrote:
> Now that we have a driver, we can make use of it. This is done by
> adding a flag to our custom plane state that will trigger whether we should
> use the frontend on that particular plane or not.
> 
> The rest is just plumbing to set up the backend to not perform the DMA but
> receive its data from the frontend.
> 
> Note that we're still not making any use of the frontend itself, as no one
> is setting the flag yet.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 53 ++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h |  3 ++-
>  drivers/gpu/drm/sun4i/sun4i_layer.c   | 27 ++++++++++++--
>  drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
>  4 files changed, 81 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index e83e1fe43823..f1d19767c55d 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -26,6 +26,7 @@
>  
>  #include "sun4i_backend.h"
>  #include "sun4i_drv.h"
> +#include "sun4i_frontend.h"
>  #include "sun4i_layer.h"
>  #include "sunxi_engine.h"
>  
> @@ -203,6 +204,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>  	return 0;
>  }
>  
> +int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
> +					int layer, uint32_t fmt)
> +{
> +	u32 val;
> +	int ret;
> +
> +	ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid format\n");
> +		return ret;
> +	}
> +
> +	regmap_update_bits(backend->engine.regs,
> +			   SUN4I_BACKEND_ATTCTL_REG0(layer),
> +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
> +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
> +
> +	regmap_update_bits(backend->engine.regs,
> +			   SUN4I_BACKEND_ATTCTL_REG1(layer),
> +			   SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
> +
> +	return 0;
> +}
> +
>  int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  				      int layer, struct drm_plane *plane)
>  {
> @@ -330,6 +355,34 @@ static int sun4i_backend_of_get_id(struct device_node *node)
>  	return ret;
>  }
>  
> +static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
> +							  struct device_node *node)
> +{
> +	struct device_node *port, *ep, *remote;
> +	struct sun4i_frontend *frontend;
> +
> +	port = of_graph_get_port_by_id(node, 0);
> +	if (!port)
> +		return ERR_PTR(-EINVAL);
> +
> +	for_each_available_child_of_node(port, ep) {
> +		remote = of_graph_get_remote_port_parent(ep);
> +		if (!remote)
> +			continue;
> +
> +		/* does this node match any registered engines? */
> +		list_for_each_entry(frontend, &drv->frontend_list, list) {
> +			if (remote == frontend->node) {
> +				of_node_put(remote);
> +				of_node_put(port);
> +				return frontend;
> +			}
> +		}
> +	}
> +
> +	return ERR_PTR(-EINVAL);
> +}
> +
>  static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
>  	.commit				= sun4i_backend_commit,
>  	.layers_init			= sun4i_layers_init,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index ba1410fd5410..636a51521e77 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -72,6 +72,7 @@
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x)		((x) << 15)
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK	GENMASK(11, 10)
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x)			((x) << 10)
> +#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN		BIT(1)
>  
>  #define SUN4I_BACKEND_ATTCTL_REG1(l)		(0x8a0 + (0x4 * (l)))
>  #define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT		GENMASK(15, 14)
> @@ -171,5 +172,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>  				       int layer, struct drm_plane *plane);
>  int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  				      int layer, struct drm_plane *plane);
> +int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
> +					int layer, uint32_t in_fmt);
>  
>  #endif /* _SUN4I_BACKEND_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
> index c3afcf888906..3b58667a06dc 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -15,6 +15,7 @@
>  #include <drm/drmP.h>
>  
>  #include "sun4i_backend.h"
> +#include "sun4i_frontend.h"
>  #include "sun4i_layer.h"
>  #include "sunxi_engine.h"
>  
> @@ -70,21 +71,41 @@ static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
>  static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
>  					       struct drm_plane_state *old_state)
>  {
> +	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
>  	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
>  	struct sun4i_backend *backend = layer->backend;
> +	struct sun4i_frontend *frontend = backend->frontend;
>  
>  	sun4i_backend_layer_enable(backend, layer->id, false);
> +
> +	if (layer_state->uses_frontend)
> +		sun4i_frontend_exit(frontend);
>  }
>  
>  static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
>  					      struct drm_plane_state *old_state)
>  {
> +	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
>  	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
>  	struct sun4i_backend *backend = layer->backend;
> +	struct sun4i_frontend *frontend = backend->frontend;
> +
> +	if (layer_state->uses_frontend) {
> +		sun4i_frontend_init(frontend);
> +		sun4i_frontend_update_coord(frontend, plane);
> +		sun4i_frontend_update_buffer(frontend, plane);
> +		sun4i_frontend_update_formats(frontend, plane,
> +					      DRM_FORMAT_ARGB8888);
> +		sun4i_backend_update_layer_frontend(backend, layer->id,
> +						    DRM_FORMAT_ARGB8888);
> +		sun4i_backend_update_layer_coord(backend, layer->id, plane);
> +		sun4i_frontend_enable(frontend);
> +	} else {
> +		sun4i_backend_update_layer_coord(backend, layer->id, plane);
> +		sun4i_backend_update_layer_formats(backend, layer->id, plane);
> +		sun4i_backend_update_layer_buffer(backend, layer->id, plane);
> +	}
>  
> -	sun4i_backend_update_layer_coord(backend, layer->id, plane);
> -	sun4i_backend_update_layer_formats(backend, layer->id, plane);
> -	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
>  	sun4i_backend_layer_enable(backend, layer->id, true);
>  }
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
> index d2c19348d1b0..75b4868ba87c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
> @@ -24,6 +24,7 @@ struct sun4i_layer {
>  
>  struct sun4i_layer_state {
>  	struct drm_plane_state	state;
> +	bool			uses_frontend;
>  };
>  
>  static inline struct sun4i_layer *
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* Re: [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
@ 2017-12-13 16:11       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:11 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: Thomas Petazzoni, dri-devel, linux-kernel, linux-arm-kernel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> Now that we have a driver, we can make use of it. This is done by
> adding a flag to our custom plane state that will trigger whether we should
> use the frontend on that particular plane or not.
> 
> The rest is just plumbing to set up the backend to not perform the DMA but
> receive its data from the frontend.
> 
> Note that we're still not making any use of the frontend itself, as no one
> is setting the flag yet.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 53 ++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h |  3 ++-
>  drivers/gpu/drm/sun4i/sun4i_layer.c   | 27 ++++++++++++--
>  drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
>  4 files changed, 81 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index e83e1fe43823..f1d19767c55d 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -26,6 +26,7 @@
>  
>  #include "sun4i_backend.h"
>  #include "sun4i_drv.h"
> +#include "sun4i_frontend.h"
>  #include "sun4i_layer.h"
>  #include "sunxi_engine.h"
>  
> @@ -203,6 +204,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>  	return 0;
>  }
>  
> +int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
> +					int layer, uint32_t fmt)
> +{
> +	u32 val;
> +	int ret;
> +
> +	ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid format\n");
> +		return ret;
> +	}
> +
> +	regmap_update_bits(backend->engine.regs,
> +			   SUN4I_BACKEND_ATTCTL_REG0(layer),
> +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
> +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
> +
> +	regmap_update_bits(backend->engine.regs,
> +			   SUN4I_BACKEND_ATTCTL_REG1(layer),
> +			   SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
> +
> +	return 0;
> +}
> +
>  int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  				      int layer, struct drm_plane *plane)
>  {
> @@ -330,6 +355,34 @@ static int sun4i_backend_of_get_id(struct device_node *node)
>  	return ret;
>  }
>  
> +static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
> +							  struct device_node *node)
> +{
> +	struct device_node *port, *ep, *remote;
> +	struct sun4i_frontend *frontend;
> +
> +	port = of_graph_get_port_by_id(node, 0);
> +	if (!port)
> +		return ERR_PTR(-EINVAL);
> +
> +	for_each_available_child_of_node(port, ep) {
> +		remote = of_graph_get_remote_port_parent(ep);
> +		if (!remote)
> +			continue;
> +
> +		/* does this node match any registered engines? */
> +		list_for_each_entry(frontend, &drv->frontend_list, list) {
> +			if (remote == frontend->node) {
> +				of_node_put(remote);
> +				of_node_put(port);
> +				return frontend;
> +			}
> +		}
> +	}
> +
> +	return ERR_PTR(-EINVAL);
> +}
> +
>  static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
>  	.commit				= sun4i_backend_commit,
>  	.layers_init			= sun4i_layers_init,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index ba1410fd5410..636a51521e77 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -72,6 +72,7 @@
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x)		((x) << 15)
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK	GENMASK(11, 10)
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x)			((x) << 10)
> +#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN		BIT(1)
>  
>  #define SUN4I_BACKEND_ATTCTL_REG1(l)		(0x8a0 + (0x4 * (l)))
>  #define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT		GENMASK(15, 14)
> @@ -171,5 +172,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>  				       int layer, struct drm_plane *plane);
>  int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  				      int layer, struct drm_plane *plane);
> +int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
> +					int layer, uint32_t in_fmt);
>  
>  #endif /* _SUN4I_BACKEND_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
> index c3afcf888906..3b58667a06dc 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -15,6 +15,7 @@
>  #include <drm/drmP.h>
>  
>  #include "sun4i_backend.h"
> +#include "sun4i_frontend.h"
>  #include "sun4i_layer.h"
>  #include "sunxi_engine.h"
>  
> @@ -70,21 +71,41 @@ static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
>  static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
>  					       struct drm_plane_state *old_state)
>  {
> +	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
>  	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
>  	struct sun4i_backend *backend = layer->backend;
> +	struct sun4i_frontend *frontend = backend->frontend;
>  
>  	sun4i_backend_layer_enable(backend, layer->id, false);
> +
> +	if (layer_state->uses_frontend)
> +		sun4i_frontend_exit(frontend);
>  }
>  
>  static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
>  					      struct drm_plane_state *old_state)
>  {
> +	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
>  	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
>  	struct sun4i_backend *backend = layer->backend;
> +	struct sun4i_frontend *frontend = backend->frontend;
> +
> +	if (layer_state->uses_frontend) {
> +		sun4i_frontend_init(frontend);
> +		sun4i_frontend_update_coord(frontend, plane);
> +		sun4i_frontend_update_buffer(frontend, plane);
> +		sun4i_frontend_update_formats(frontend, plane,
> +					      DRM_FORMAT_ARGB8888);
> +		sun4i_backend_update_layer_frontend(backend, layer->id,
> +						    DRM_FORMAT_ARGB8888);
> +		sun4i_backend_update_layer_coord(backend, layer->id, plane);
> +		sun4i_frontend_enable(frontend);
> +	} else {
> +		sun4i_backend_update_layer_coord(backend, layer->id, plane);
> +		sun4i_backend_update_layer_formats(backend, layer->id, plane);
> +		sun4i_backend_update_layer_buffer(backend, layer->id, plane);
> +	}
>  
> -	sun4i_backend_update_layer_coord(backend, layer->id, plane);
> -	sun4i_backend_update_layer_formats(backend, layer->id, plane);
> -	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
>  	sun4i_backend_layer_enable(backend, layer->id, true);
>  }
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
> index d2c19348d1b0..75b4868ba87c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
> @@ -24,6 +24,7 @@ struct sun4i_layer {
>  
>  struct sun4i_layer_state {
>  	struct drm_plane_state	state;
> +	bool			uses_frontend;
>  };
>  
>  static inline struct sun4i_layer *
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 7/8] drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
  2017-12-13 15:33     ` Maxime Ripard
  (?)
@ 2017-12-13 16:12       ` Neil Armstrong
  -1 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:12 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: linux-arm-kernel, Thomas Petazzoni, linux-kernel, dri-devel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> Now that we have everything in place, we can start enabling the frontend.
> This is more difficult than one would assume since there can only be one
> plane using the frontend per-backend.
> 
> We therefore need to make sure that the userspace will not try to setup
> multiple planes using it, since that would be impossible. In order to
> prevent that, we can create an atomic_check callback that will check that
> only one plane will effectively make use of the frontend in a given
> configuration, and will toggle the switch in that plane state so that the
> proper setup function can do their role.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 65 ++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h |  2 +-
>  2 files changed, 67 insertions(+)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index f1d19767c55d..a7b87a12990e 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -11,6 +11,7 @@
>   */
>  
>  #include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_crtc_helper.h>
> @@ -271,6 +272,69 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  	return 0;
>  }
>  
> +static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
> +{
> +	u16 src_h = state->src_h >> 16;
> +	u16 src_w = state->src_w >> 16;
> +
> +	DRM_DEBUG_DRIVER("Input size %dx%d, output size %dx%d\n",
> +			 src_w, src_h, state->crtc_w, state->crtc_h);
> +
> +	if ((state->crtc_h != src_h) || (state->crtc_w != src_w))
> +		return true;
> +
> +	return false;
> +}
> +
> +static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
> +{
> +	struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);
> +	struct sun4i_backend *backend = layer->backend;
> +
> +	if (IS_ERR(backend->frontend))
> +		return false;
> +
> +	return sun4i_backend_plane_uses_scaler(state);
> +}
> +
> +static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
> +				      struct drm_crtc_state *crtc_state)
> +{
> +	struct drm_atomic_state *state = crtc_state->state;
> +	struct drm_device *drm = state->dev;
> +	struct drm_plane *plane;
> +	unsigned int num_frontend_planes = 0;
> +
> +	DRM_DEBUG_DRIVER("Starting checking our planes\n");
> +
> +	if (!crtc_state->planes_changed)
> +		return 0;
> +
> +	drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) {
> +		struct drm_plane_state *plane_state =
> +			drm_atomic_get_plane_state(state, plane);
> +		struct sun4i_layer_state *layer_state =
> +			state_to_sun4i_layer_state(plane_state);
> +
> +		if (sun4i_backend_plane_uses_frontend(plane_state)) {
> +			DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
> +					 plane->index);
> +
> +			layer_state->uses_frontend = true;
> +			num_frontend_planes++;
> +		} else {
> +			layer_state->uses_frontend = false;
> +		}
> +	}
> +
> +	if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
> +		DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  static int sun4i_backend_init_sat(struct device *dev) {
>  	struct sun4i_backend *backend = dev_get_drvdata(dev);
>  	int ret;
> @@ -384,6 +448,7 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
>  }
>  
>  static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
> +	.atomic_check			= sun4i_backend_atomic_check,
>  	.commit				= sun4i_backend_commit,
>  	.layers_init			= sun4i_layers_init,
>  	.apply_color_correction		= sun4i_backend_apply_color_correction,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index 636a51521e77..3b5531440fa3 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -144,6 +144,8 @@
>  #define SUN4I_BACKEND_HWCCOLORTAB_OFF		0x4c00
>  #define SUN4I_BACKEND_PIPE_OFF(p)		(0x5000 + (0x400 * (p)))
>  
> +#define SUN4I_BACKEND_NUM_FRONTEND_LAYERS	1
> +
>  struct sun4i_backend {
>  	struct sunxi_engine	engine;
>  	struct sun4i_frontend	*frontend;
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* [PATCH 7/8] drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
@ 2017-12-13 16:12       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:12 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/12/2017 16:33, Maxime Ripard wrote:
> Now that we have everything in place, we can start enabling the frontend.
> This is more difficult than one would assume since there can only be one
> plane using the frontend per-backend.
> 
> We therefore need to make sure that the userspace will not try to setup
> multiple planes using it, since that would be impossible. In order to
> prevent that, we can create an atomic_check callback that will check that
> only one plane will effectively make use of the frontend in a given
> configuration, and will toggle the switch in that plane state so that the
> proper setup function can do their role.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 65 ++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h |  2 +-
>  2 files changed, 67 insertions(+)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index f1d19767c55d..a7b87a12990e 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -11,6 +11,7 @@
>   */
>  
>  #include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_crtc_helper.h>
> @@ -271,6 +272,69 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  	return 0;
>  }
>  
> +static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
> +{
> +	u16 src_h = state->src_h >> 16;
> +	u16 src_w = state->src_w >> 16;
> +
> +	DRM_DEBUG_DRIVER("Input size %dx%d, output size %dx%d\n",
> +			 src_w, src_h, state->crtc_w, state->crtc_h);
> +
> +	if ((state->crtc_h != src_h) || (state->crtc_w != src_w))
> +		return true;
> +
> +	return false;
> +}
> +
> +static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
> +{
> +	struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);
> +	struct sun4i_backend *backend = layer->backend;
> +
> +	if (IS_ERR(backend->frontend))
> +		return false;
> +
> +	return sun4i_backend_plane_uses_scaler(state);
> +}
> +
> +static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
> +				      struct drm_crtc_state *crtc_state)
> +{
> +	struct drm_atomic_state *state = crtc_state->state;
> +	struct drm_device *drm = state->dev;
> +	struct drm_plane *plane;
> +	unsigned int num_frontend_planes = 0;
> +
> +	DRM_DEBUG_DRIVER("Starting checking our planes\n");
> +
> +	if (!crtc_state->planes_changed)
> +		return 0;
> +
> +	drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) {
> +		struct drm_plane_state *plane_state =
> +			drm_atomic_get_plane_state(state, plane);
> +		struct sun4i_layer_state *layer_state =
> +			state_to_sun4i_layer_state(plane_state);
> +
> +		if (sun4i_backend_plane_uses_frontend(plane_state)) {
> +			DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
> +					 plane->index);
> +
> +			layer_state->uses_frontend = true;
> +			num_frontend_planes++;
> +		} else {
> +			layer_state->uses_frontend = false;
> +		}
> +	}
> +
> +	if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
> +		DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  static int sun4i_backend_init_sat(struct device *dev) {
>  	struct sun4i_backend *backend = dev_get_drvdata(dev);
>  	int ret;
> @@ -384,6 +448,7 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
>  }
>  
>  static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
> +	.atomic_check			= sun4i_backend_atomic_check,
>  	.commit				= sun4i_backend_commit,
>  	.layers_init			= sun4i_layers_init,
>  	.apply_color_correction		= sun4i_backend_apply_color_correction,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index 636a51521e77..3b5531440fa3 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -144,6 +144,8 @@
>  #define SUN4I_BACKEND_HWCCOLORTAB_OFF		0x4c00
>  #define SUN4I_BACKEND_PIPE_OFF(p)		(0x5000 + (0x400 * (p)))
>  
> +#define SUN4I_BACKEND_NUM_FRONTEND_LAYERS	1
> +
>  struct sun4i_backend {
>  	struct sunxi_engine	engine;
>  	struct sun4i_frontend	*frontend;
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

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

* Re: [PATCH 7/8] drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
@ 2017-12-13 16:12       ` Neil Armstrong
  0 siblings, 0 replies; 62+ messages in thread
From: Neil Armstrong @ 2017-12-13 16:12 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: Thomas Petazzoni, dri-devel, linux-kernel, linux-arm-kernel, thomas

On 13/12/2017 16:33, Maxime Ripard wrote:
> Now that we have everything in place, we can start enabling the frontend.
> This is more difficult than one would assume since there can only be one
> plane using the frontend per-backend.
> 
> We therefore need to make sure that the userspace will not try to setup
> multiple planes using it, since that would be impossible. In order to
> prevent that, we can create an atomic_check callback that will check that
> only one plane will effectively make use of the frontend in a given
> configuration, and will toggle the switch in that plane state so that the
> proper setup function can do their role.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 65 ++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h |  2 +-
>  2 files changed, 67 insertions(+)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index f1d19767c55d..a7b87a12990e 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -11,6 +11,7 @@
>   */
>  
>  #include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_crtc_helper.h>
> @@ -271,6 +272,69 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  	return 0;
>  }
>  
> +static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
> +{
> +	u16 src_h = state->src_h >> 16;
> +	u16 src_w = state->src_w >> 16;
> +
> +	DRM_DEBUG_DRIVER("Input size %dx%d, output size %dx%d\n",
> +			 src_w, src_h, state->crtc_w, state->crtc_h);
> +
> +	if ((state->crtc_h != src_h) || (state->crtc_w != src_w))
> +		return true;
> +
> +	return false;
> +}
> +
> +static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
> +{
> +	struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);
> +	struct sun4i_backend *backend = layer->backend;
> +
> +	if (IS_ERR(backend->frontend))
> +		return false;
> +
> +	return sun4i_backend_plane_uses_scaler(state);
> +}
> +
> +static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
> +				      struct drm_crtc_state *crtc_state)
> +{
> +	struct drm_atomic_state *state = crtc_state->state;
> +	struct drm_device *drm = state->dev;
> +	struct drm_plane *plane;
> +	unsigned int num_frontend_planes = 0;
> +
> +	DRM_DEBUG_DRIVER("Starting checking our planes\n");
> +
> +	if (!crtc_state->planes_changed)
> +		return 0;
> +
> +	drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) {
> +		struct drm_plane_state *plane_state =
> +			drm_atomic_get_plane_state(state, plane);
> +		struct sun4i_layer_state *layer_state =
> +			state_to_sun4i_layer_state(plane_state);
> +
> +		if (sun4i_backend_plane_uses_frontend(plane_state)) {
> +			DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
> +					 plane->index);
> +
> +			layer_state->uses_frontend = true;
> +			num_frontend_planes++;
> +		} else {
> +			layer_state->uses_frontend = false;
> +		}
> +	}
> +
> +	if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
> +		DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  static int sun4i_backend_init_sat(struct device *dev) {
>  	struct sun4i_backend *backend = dev_get_drvdata(dev);
>  	int ret;
> @@ -384,6 +448,7 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
>  }
>  
>  static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
> +	.atomic_check			= sun4i_backend_atomic_check,
>  	.commit				= sun4i_backend_commit,
>  	.layers_init			= sun4i_layers_init,
>  	.apply_color_correction		= sun4i_backend_apply_color_correction,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index 636a51521e77..3b5531440fa3 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -144,6 +144,8 @@
>  #define SUN4I_BACKEND_HWCCOLORTAB_OFF		0x4c00
>  #define SUN4I_BACKEND_PIPE_OFF(p)		(0x5000 + (0x400 * (p)))
>  
> +#define SUN4I_BACKEND_NUM_FRONTEND_LAYERS	1
> +
>  struct sun4i_backend {
>  	struct sunxi_engine	engine;
>  	struct sun4i_frontend	*frontend;
> 

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 0/8] drm/sun4i: Support the Display Engine frontend
  2017-12-13 15:33   ` Maxime Ripard
@ 2017-12-13 16:16     ` Thomas van Kleef
  -1 siblings, 0 replies; 62+ messages in thread
From: Thomas van Kleef @ 2017-12-13 16:16 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni

Hi,

On 13-12-17 16:33, Maxime Ripard wrote:
> Hi,
> 
> This is a first serie to enable the display engine frontend.
> 
> This hardware block is found in the first generation Display Engine from
> Allwinner. Its role is to implement more advanced features that the
> associated backend, even though the backend alone can be used (and was used
> so far) for basic composition.
> 
> Among those features, we will find hardware scaling, that is supported in
> this serie, colorspace conversions, or more exotic formats support such as
> the one output by the VPU.
So, if I have read the code correctly. The frontend will be used whenever the
input size differs from the output size.
> 
> Let me know what you think,
> Maxime
> 
> Maxime Ripard (8):
>   drm/sun4i: backend: Move line stride setup to buffer setup function
>   drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
>   drm/sun4i: sun4i_layer: Add a custom plane state
>   drm/sun4i: crtc: Add a custom crtc atomic_check
>   drm/sun4i: Add a driver for the display frontend
>   drm/sun4i: sun4i_layer: Wire in the frontend
>   drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
>   ARM: dts: sun8i: a33 Enable our display frontend
> 
>  arch/arm/boot/dts/sun8i-a33.dtsi       |   1 +-
>  drivers/gpu/drm/sun4i/Makefile         |   3 +-
>  drivers/gpu/drm/sun4i/sun4i_backend.c  | 139 +++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h  |   6 +-
>  drivers/gpu/drm/sun4i/sun4i_crtc.c     |  14 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.c      |  16 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
>  drivers/gpu/drm/sun4i/sun4i_layer.c    |  75 ++++-
>  drivers/gpu/drm/sun4i/sun4i_layer.h    |  11 +-
>  drivers/gpu/drm/sun4i/sunxi_engine.h   |   2 +-
>  12 files changed, 727 insertions(+), 20 deletions(-)
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h
> 
> base-commit: 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323
> 

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

* [PATCH 0/8] drm/sun4i: Support the Display Engine frontend
@ 2017-12-13 16:16     ` Thomas van Kleef
  0 siblings, 0 replies; 62+ messages in thread
From: Thomas van Kleef @ 2017-12-13 16:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 13-12-17 16:33, Maxime Ripard wrote:
> Hi,
> 
> This is a first serie to enable the display engine frontend.
> 
> This hardware block is found in the first generation Display Engine from
> Allwinner. Its role is to implement more advanced features that the
> associated backend, even though the backend alone can be used (and was used
> so far) for basic composition.
> 
> Among those features, we will find hardware scaling, that is supported in
> this serie, colorspace conversions, or more exotic formats support such as
> the one output by the VPU.
So, if I have read the code correctly. The frontend will be used whenever the
input size differs from the output size.
> 
> Let me know what you think,
> Maxime
> 
> Maxime Ripard (8):
>   drm/sun4i: backend: Move line stride setup to buffer setup function
>   drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format
>   drm/sun4i: sun4i_layer: Add a custom plane state
>   drm/sun4i: crtc: Add a custom crtc atomic_check
>   drm/sun4i: Add a driver for the display frontend
>   drm/sun4i: sun4i_layer: Wire in the frontend
>   drm/sun4i: sun4i_layer: Add a custom atomic_check for the frontend
>   ARM: dts: sun8i: a33 Enable our display frontend
> 
>  arch/arm/boot/dts/sun8i-a33.dtsi       |   1 +-
>  drivers/gpu/drm/sun4i/Makefile         |   3 +-
>  drivers/gpu/drm/sun4i/sun4i_backend.c  | 139 +++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h  |   6 +-
>  drivers/gpu/drm/sun4i/sun4i_crtc.c     |  14 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.c      |  16 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_frontend.c | 377 ++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_frontend.h | 102 +++++++-
>  drivers/gpu/drm/sun4i/sun4i_layer.c    |  75 ++++-
>  drivers/gpu/drm/sun4i/sun4i_layer.h    |  11 +-
>  drivers/gpu/drm/sun4i/sunxi_engine.h   |   2 +-
>  12 files changed, 727 insertions(+), 20 deletions(-)
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h
> 
> base-commit: 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323
> 

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

* Re: [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
  2017-12-13 15:33     ` Maxime Ripard
@ 2017-12-13 16:23       ` Thomas van Kleef
  -1 siblings, 0 replies; 62+ messages in thread
From: Thomas van Kleef @ 2017-12-13 16:23 UTC (permalink / raw)
  To: Maxime Ripard, Daniel Vetter, David Airlie, Chen-Yu Tsai
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni



On 13-12-17 16:33, Maxime Ripard wrote:
> Now that we have a driver, we can make use of it. This is done by
> adding a flag to our custom plane state that will trigger whether we should
> use the frontend on that particular plane or not.
> 
> The rest is just plumbing to set up the backend to not perform the DMA but
> receive its data from the frontend.
> 
> Note that we're still not making any use of the frontend itself, as no one
> is setting the flag yet.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 53 ++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h |  3 ++-
>  drivers/gpu/drm/sun4i/sun4i_layer.c   | 27 ++++++++++++--
>  drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
>  4 files changed, 81 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index e83e1fe43823..f1d19767c55d 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -26,6 +26,7 @@
>  
>  #include "sun4i_backend.h"
>  #include "sun4i_drv.h"
> +#include "sun4i_frontend.h"
>  #include "sun4i_layer.h"
>  #include "sunxi_engine.h"
>  
> @@ -203,6 +204,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>  	return 0;
>  }
>  
> +int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
> +					int layer, uint32_t fmt)
> +{
> +	u32 val;
> +	int ret;
> +
> +	ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid format\n");
> +		return ret;
> +	}
> +
> +	regmap_update_bits(backend->engine.regs,
> +			   SUN4I_BACKEND_ATTCTL_REG0(layer),
> +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
> +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
> +
> +	regmap_update_bits(backend->engine.regs,
> +			   SUN4I_BACKEND_ATTCTL_REG1(layer),
> +			   SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
> +
> +	return 0;
> +}
> +
>  int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  				      int layer, struct drm_plane *plane)
>  {
> @@ -330,6 +355,34 @@ static int sun4i_backend_of_get_id(struct device_node *node)
>  	return ret;
>  }
>  
> +static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
> +							  struct device_node *node)
> +{
> +	struct device_node *port, *ep, *remote;
> +	struct sun4i_frontend *frontend;
> +
> +	port = of_graph_get_port_by_id(node, 0);
> +	if (!port)
> +		return ERR_PTR(-EINVAL);
> +
> +	for_each_available_child_of_node(port, ep) {
> +		remote = of_graph_get_remote_port_parent(ep);
> +		if (!remote)
> +			continue;
> +
> +		/* does this node match any registered engines? */
> +		list_for_each_entry(frontend, &drv->frontend_list, list) {
> +			if (remote == frontend->node) {
> +				of_node_put(remote);
> +				of_node_put(port);
> +				return frontend;
> +			}
> +		}
> +	}
> +
> +	return ERR_PTR(-EINVAL);
> +}
> +
>  static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
>  	.commit				= sun4i_backend_commit,
>  	.layers_init			= sun4i_layers_init,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index ba1410fd5410..636a51521e77 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -72,6 +72,7 @@
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x)		((x) << 15)
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK	GENMASK(11, 10)
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x)			((x) << 10)
> +#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN		BIT(1)
>  
>  #define SUN4I_BACKEND_ATTCTL_REG1(l)		(0x8a0 + (0x4 * (l)))
>  #define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT		GENMASK(15, 14)
> @@ -171,5 +172,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>  				       int layer, struct drm_plane *plane);
>  int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  				      int layer, struct drm_plane *plane);
> +int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
> +					int layer, uint32_t in_fmt);
>  
>  #endif /* _SUN4I_BACKEND_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
> index c3afcf888906..3b58667a06dc 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -15,6 +15,7 @@
>  #include <drm/drmP.h>
>  
>  #include "sun4i_backend.h"
> +#include "sun4i_frontend.h"
>  #include "sun4i_layer.h"
>  #include "sunxi_engine.h"
>  
> @@ -70,21 +71,41 @@ static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
>  static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
>  					       struct drm_plane_state *old_state)
>  {
> +	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
>  	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
>  	struct sun4i_backend *backend = layer->backend;
> +	struct sun4i_frontend *frontend = backend->frontend;
>  
>  	sun4i_backend_layer_enable(backend, layer->id, false);
> +
> +	if (layer_state->uses_frontend)
> +		sun4i_frontend_exit(frontend);
>  }
>  
>  static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
>  					      struct drm_plane_state *old_state)
>  {
> +	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
>  	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
>  	struct sun4i_backend *backend = layer->backend;
> +	struct sun4i_frontend *frontend = backend->frontend;
> +
> +	if (layer_state->uses_frontend) {
> +		sun4i_frontend_init(frontend);
> +		sun4i_frontend_update_coord(frontend, plane);
> +		sun4i_frontend_update_buffer(frontend, plane);
> +		sun4i_frontend_update_formats(frontend, plane,
> +					      DRM_FORMAT_ARGB8888);
> +		sun4i_backend_update_layer_frontend(backend, layer->id,
> +						    DRM_FORMAT_ARGB8888);
> +		sun4i_backend_update_layer_coord(backend, layer->id, plane);
> +		sun4i_frontend_enable(frontend);
> +	} else {
> +		sun4i_backend_update_layer_coord(backend, layer->id, plane);
> +		sun4i_backend_update_layer_formats(backend, layer->id, plane);
> +		sun4i_backend_update_layer_buffer(backend, layer->id, plane);
> +	}
>  
> -	sun4i_backend_update_layer_coord(backend, layer->id, plane);
> -	sun4i_backend_update_layer_formats(backend, layer->id, plane);
> -	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
>  	sun4i_backend_layer_enable(backend, layer->id, true);
>  }
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
> index d2c19348d1b0..75b4868ba87c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
> @@ -24,6 +24,7 @@ struct sun4i_layer {
>  
>  struct sun4i_layer_state {
>  	struct drm_plane_state	state;
> +	bool			uses_frontend;
>  };
>  
>  static inline struct sun4i_layer *
> 

I wondered if the following is still valid?
In file sun4i_layer.c, func sun4i_layers_init

------------------
         /*
         * The hardware is a bit unusual here.
         *
         * Even though it supports 4 layers, it does the composition
         * in two separate steps.
         *
         * The first one is assigning a layer to one of its two
         * pipes. If more that 1 layer is assigned to the same pipe,
         * and if pixels overlaps, the pipe will take the pixel from
         * the layer with the highest priority.
         *
         * The second step is the actual alpha blending, that takes
         * the two pipes as input, and uses the eventual alpha
         * component to do the transparency between the two.
         *
         * This two steps scenario makes us unable to guarantee a
         * robust alpha blending between the 4 layers in all
         * situations. So we just expose two layers, one per pipe. On
         * SoCs that support it, sprites could fill the need for more
         * layers.
         */
        for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
                const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
                struct sun4i_layer *layer;

                layer = sun4i_layer_init_one(drm, backend, plane);
                if (IS_ERR(layer)) {
                        dev_err(drm->dev, "Couldn't initialize %s plane\n",
                                i ? "overlay" : "primary");
                        return ERR_CAST(layer);
                };

                DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
                                 i ? "overlay" : "primary", plane->pipe);
                regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
                                   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
                                   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));

                layer->id = i;
                planes[i] = &layer->plane;
        };
-----------------
I have been using the 3rd layer (layer2) as the input for the frontend. This essentially
overlays the other 2 layers. Is it still the case that we can only have 2 layers here?
Or could be present 1 additional layer when it is attached to the frontend?
Perhaps this is not relevant for this patchset.

Regards,

Thomas van Kleef
Vitsch Electronics
http://Vitsch.nl/
http://VitschVPN.nl/
tel: +31-(0)40-7113051
KvK nr: 17174380
BTW nr: NL142748201B01

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

* [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
@ 2017-12-13 16:23       ` Thomas van Kleef
  0 siblings, 0 replies; 62+ messages in thread
From: Thomas van Kleef @ 2017-12-13 16:23 UTC (permalink / raw)
  To: linux-arm-kernel



On 13-12-17 16:33, Maxime Ripard wrote:
> Now that we have a driver, we can make use of it. This is done by
> adding a flag to our custom plane state that will trigger whether we should
> use the frontend on that particular plane or not.
> 
> The rest is just plumbing to set up the backend to not perform the DMA but
> receive its data from the frontend.
> 
> Note that we're still not making any use of the frontend itself, as no one
> is setting the flag yet.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c | 53 ++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h |  3 ++-
>  drivers/gpu/drm/sun4i/sun4i_layer.c   | 27 ++++++++++++--
>  drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
>  4 files changed, 81 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index e83e1fe43823..f1d19767c55d 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -26,6 +26,7 @@
>  
>  #include "sun4i_backend.h"
>  #include "sun4i_drv.h"
> +#include "sun4i_frontend.h"
>  #include "sun4i_layer.h"
>  #include "sunxi_engine.h"
>  
> @@ -203,6 +204,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>  	return 0;
>  }
>  
> +int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
> +					int layer, uint32_t fmt)
> +{
> +	u32 val;
> +	int ret;
> +
> +	ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid format\n");
> +		return ret;
> +	}
> +
> +	regmap_update_bits(backend->engine.regs,
> +			   SUN4I_BACKEND_ATTCTL_REG0(layer),
> +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
> +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
> +
> +	regmap_update_bits(backend->engine.regs,
> +			   SUN4I_BACKEND_ATTCTL_REG1(layer),
> +			   SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
> +
> +	return 0;
> +}
> +
>  int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  				      int layer, struct drm_plane *plane)
>  {
> @@ -330,6 +355,34 @@ static int sun4i_backend_of_get_id(struct device_node *node)
>  	return ret;
>  }
>  
> +static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
> +							  struct device_node *node)
> +{
> +	struct device_node *port, *ep, *remote;
> +	struct sun4i_frontend *frontend;
> +
> +	port = of_graph_get_port_by_id(node, 0);
> +	if (!port)
> +		return ERR_PTR(-EINVAL);
> +
> +	for_each_available_child_of_node(port, ep) {
> +		remote = of_graph_get_remote_port_parent(ep);
> +		if (!remote)
> +			continue;
> +
> +		/* does this node match any registered engines? */
> +		list_for_each_entry(frontend, &drv->frontend_list, list) {
> +			if (remote == frontend->node) {
> +				of_node_put(remote);
> +				of_node_put(port);
> +				return frontend;
> +			}
> +		}
> +	}
> +
> +	return ERR_PTR(-EINVAL);
> +}
> +
>  static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
>  	.commit				= sun4i_backend_commit,
>  	.layers_init			= sun4i_layers_init,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index ba1410fd5410..636a51521e77 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -72,6 +72,7 @@
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x)		((x) << 15)
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK	GENMASK(11, 10)
>  #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x)			((x) << 10)
> +#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN		BIT(1)
>  
>  #define SUN4I_BACKEND_ATTCTL_REG1(l)		(0x8a0 + (0x4 * (l)))
>  #define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT		GENMASK(15, 14)
> @@ -171,5 +172,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>  				       int layer, struct drm_plane *plane);
>  int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>  				      int layer, struct drm_plane *plane);
> +int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
> +					int layer, uint32_t in_fmt);
>  
>  #endif /* _SUN4I_BACKEND_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
> index c3afcf888906..3b58667a06dc 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -15,6 +15,7 @@
>  #include <drm/drmP.h>
>  
>  #include "sun4i_backend.h"
> +#include "sun4i_frontend.h"
>  #include "sun4i_layer.h"
>  #include "sunxi_engine.h"
>  
> @@ -70,21 +71,41 @@ static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
>  static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
>  					       struct drm_plane_state *old_state)
>  {
> +	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
>  	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
>  	struct sun4i_backend *backend = layer->backend;
> +	struct sun4i_frontend *frontend = backend->frontend;
>  
>  	sun4i_backend_layer_enable(backend, layer->id, false);
> +
> +	if (layer_state->uses_frontend)
> +		sun4i_frontend_exit(frontend);
>  }
>  
>  static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
>  					      struct drm_plane_state *old_state)
>  {
> +	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
>  	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
>  	struct sun4i_backend *backend = layer->backend;
> +	struct sun4i_frontend *frontend = backend->frontend;
> +
> +	if (layer_state->uses_frontend) {
> +		sun4i_frontend_init(frontend);
> +		sun4i_frontend_update_coord(frontend, plane);
> +		sun4i_frontend_update_buffer(frontend, plane);
> +		sun4i_frontend_update_formats(frontend, plane,
> +					      DRM_FORMAT_ARGB8888);
> +		sun4i_backend_update_layer_frontend(backend, layer->id,
> +						    DRM_FORMAT_ARGB8888);
> +		sun4i_backend_update_layer_coord(backend, layer->id, plane);
> +		sun4i_frontend_enable(frontend);
> +	} else {
> +		sun4i_backend_update_layer_coord(backend, layer->id, plane);
> +		sun4i_backend_update_layer_formats(backend, layer->id, plane);
> +		sun4i_backend_update_layer_buffer(backend, layer->id, plane);
> +	}
>  
> -	sun4i_backend_update_layer_coord(backend, layer->id, plane);
> -	sun4i_backend_update_layer_formats(backend, layer->id, plane);
> -	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
>  	sun4i_backend_layer_enable(backend, layer->id, true);
>  }
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
> index d2c19348d1b0..75b4868ba87c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
> @@ -24,6 +24,7 @@ struct sun4i_layer {
>  
>  struct sun4i_layer_state {
>  	struct drm_plane_state	state;
> +	bool			uses_frontend;
>  };
>  
>  static inline struct sun4i_layer *
> 

I wondered if the following is still valid?
In file sun4i_layer.c, func sun4i_layers_init

------------------
         /*
         * The hardware is a bit unusual here.
         *
         * Even though it supports 4 layers, it does the composition
         * in two separate steps.
         *
         * The first one is assigning a layer to one of its two
         * pipes. If more that 1 layer is assigned to the same pipe,
         * and if pixels overlaps, the pipe will take the pixel from
         * the layer with the highest priority.
         *
         * The second step is the actual alpha blending, that takes
         * the two pipes as input, and uses the eventual alpha
         * component to do the transparency between the two.
         *
         * This two steps scenario makes us unable to guarantee a
         * robust alpha blending between the 4 layers in all
         * situations. So we just expose two layers, one per pipe. On
         * SoCs that support it, sprites could fill the need for more
         * layers.
         */
        for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
                const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
                struct sun4i_layer *layer;

                layer = sun4i_layer_init_one(drm, backend, plane);
                if (IS_ERR(layer)) {
                        dev_err(drm->dev, "Couldn't initialize %s plane\n",
                                i ? "overlay" : "primary");
                        return ERR_CAST(layer);
                };

                DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
                                 i ? "overlay" : "primary", plane->pipe);
                regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
                                   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
                                   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));

                layer->id = i;
                planes[i] = &layer->plane;
        };
-----------------
I have been using the 3rd layer (layer2) as the input for the frontend. This essentially
overlays the other 2 layers. Is it still the case that we can only have 2 layers here?
Or could be present 1 additional layer when it is attached to the frontend?
Perhaps this is not relevant for this patchset.

Regards,

Thomas van Kleef
Vitsch Electronics
http://Vitsch.nl/
http://VitschVPN.nl/
tel: +31-(0)40-7113051
KvK nr: 17174380
BTW nr: NL142748201B01

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

* Re: [PATCH 0/8] drm/sun4i: Support the Display Engine frontend
  2017-12-13 16:16     ` Thomas van Kleef
  (?)
@ 2017-12-14  8:35       ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-14  8:35 UTC (permalink / raw)
  To: Thomas van Kleef
  Cc: Daniel Vetter, David Airlie, Chen-Yu Tsai, dri-devel,
	linux-kernel, linux-arm-kernel, Thomas Petazzoni

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

Hi Thomas,

On Wed, Dec 13, 2017 at 05:16:22PM +0100, Thomas van Kleef wrote:
> Hi,
> 
> On 13-12-17 16:33, Maxime Ripard wrote:
> > Hi,
> > 
> > This is a first serie to enable the display engine frontend.
> > 
> > This hardware block is found in the first generation Display Engine from
> > Allwinner. Its role is to implement more advanced features that the
> > associated backend, even though the backend alone can be used (and was used
> > so far) for basic composition.
> > 
> > Among those features, we will find hardware scaling, that is supported in
> > this serie, colorspace conversions, or more exotic formats support such as
> > the one output by the VPU.
>
> So, if I have read the code correctly. The frontend will be used whenever the
> input size differs from the output size.

Yes :)

My current plan is to extend it as needed when we'll need to deal with
a format not supported by the backend (for the VPU), or anything the
backend cannot support.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

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

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

* [PATCH 0/8] drm/sun4i: Support the Display Engine frontend
@ 2017-12-14  8:35       ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-14  8:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

On Wed, Dec 13, 2017 at 05:16:22PM +0100, Thomas van Kleef wrote:
> Hi,
> 
> On 13-12-17 16:33, Maxime Ripard wrote:
> > Hi,
> > 
> > This is a first serie to enable the display engine frontend.
> > 
> > This hardware block is found in the first generation Display Engine from
> > Allwinner. Its role is to implement more advanced features that the
> > associated backend, even though the backend alone can be used (and was used
> > so far) for basic composition.
> > 
> > Among those features, we will find hardware scaling, that is supported in
> > this serie, colorspace conversions, or more exotic formats support such as
> > the one output by the VPU.
>
> So, if I have read the code correctly. The frontend will be used whenever the
> input size differs from the output size.

Yes :)

My current plan is to extend it as needed when we'll need to deal with
a format not supported by the backend (for the VPU), or anything the
backend cannot support.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171214/795427a7/attachment-0001.sig>

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

* Re: [PATCH 0/8] drm/sun4i: Support the Display Engine frontend
@ 2017-12-14  8:35       ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-14  8:35 UTC (permalink / raw)
  To: Thomas van Kleef
  Cc: Thomas Petazzoni, David Airlie, linux-kernel, dri-devel,
	Chen-Yu Tsai, Daniel Vetter, linux-arm-kernel


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

Hi Thomas,

On Wed, Dec 13, 2017 at 05:16:22PM +0100, Thomas van Kleef wrote:
> Hi,
> 
> On 13-12-17 16:33, Maxime Ripard wrote:
> > Hi,
> > 
> > This is a first serie to enable the display engine frontend.
> > 
> > This hardware block is found in the first generation Display Engine from
> > Allwinner. Its role is to implement more advanced features that the
> > associated backend, even though the backend alone can be used (and was used
> > so far) for basic composition.
> > 
> > Among those features, we will find hardware scaling, that is supported in
> > this serie, colorspace conversions, or more exotic formats support such as
> > the one output by the VPU.
>
> So, if I have read the code correctly. The frontend will be used whenever the
> input size differs from the output size.

Yes :)

My current plan is to extend it as needed when we'll need to deal with
a format not supported by the backend (for the VPU), or anything the
backend cannot support.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

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

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
  2017-12-13 16:23       ` Thomas van Kleef
  (?)
@ 2017-12-14 10:32         ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-14 10:32 UTC (permalink / raw)
  To: Thomas van Kleef
  Cc: Daniel Vetter, David Airlie, Chen-Yu Tsai, dri-devel,
	linux-kernel, linux-arm-kernel, Thomas Petazzoni

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

Hi,

On Wed, Dec 13, 2017 at 05:23:04PM +0100, Thomas van Kleef wrote:
> I wondered if the following is still valid?
> In file sun4i_layer.c, func sun4i_layers_init
> 
> ------------------
>          /*
>          * The hardware is a bit unusual here.
>          *
>          * Even though it supports 4 layers, it does the composition
>          * in two separate steps.
>          *
>          * The first one is assigning a layer to one of its two
>          * pipes. If more that 1 layer is assigned to the same pipe,
>          * and if pixels overlaps, the pipe will take the pixel from
>          * the layer with the highest priority.
>          *
>          * The second step is the actual alpha blending, that takes
>          * the two pipes as input, and uses the eventual alpha
>          * component to do the transparency between the two.
>          *
>          * This two steps scenario makes us unable to guarantee a
>          * robust alpha blending between the 4 layers in all
>          * situations. So we just expose two layers, one per pipe. On
>          * SoCs that support it, sprites could fill the need for more
>          * layers.
>          */
>         for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
>                 const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
>                 struct sun4i_layer *layer;
> 
>                 layer = sun4i_layer_init_one(drm, backend, plane);
>                 if (IS_ERR(layer)) {
>                         dev_err(drm->dev, "Couldn't initialize %s plane\n",
>                                 i ? "overlay" : "primary");
>                         return ERR_CAST(layer);
>                 };
> 
>                 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
>                                  i ? "overlay" : "primary", plane->pipe);
>                 regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
>                                    SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
>                                    SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
> 
>                 layer->id = i;
>                 planes[i] = &layer->plane;
>         };
> -----------------
>
> I have been using the 3rd layer (layer2) as the input for the
> frontend. This essentially overlays the other 2 layers. Is it still
> the case that we can only have 2 layers here?

Yes.

> Or could be present 1 additional layer when it is attached to the
> frontend?

The frontend will still consume a backend layer. In this current
serie, we still define only two layers for the reasons exposed above,
and whatever layer using hardware scaling will use the frontend.

I have a few patches that would remove that limitation, but we need a
few things in order to do that properly.

The first one would be to add a check on the alpha component of our
layers. We basically have two rules:
  - the lowest plane shouldn't use alpha at all, because of a bug in
    the display engine that would render the pixels completely
    transparents if the alpha is set to something less than 255 on the
    lowest plane.
  - we can only have a plane with alpha as the lowest plane of each
    pipe.

This effectively means that the only scenario that works would be that
there can be only one plane can use alpha at a time, that it shouldn't
be the lowest one, and that it must be assigned to the second pipe.

I worked on that a bit quite some time ago, and the only thing I was
missing was a proper way to check for that in atomic_check, but with
the work done in this serie it shouldn't be too hard.

Then, we can enable the four layers, which is not really difficult in
itself.

> Perhaps this is not relevant for this patchset.

Yep, that's quite orthogonal.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

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

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

* [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
@ 2017-12-14 10:32         ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-14 10:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Wed, Dec 13, 2017 at 05:23:04PM +0100, Thomas van Kleef wrote:
> I wondered if the following is still valid?
> In file sun4i_layer.c, func sun4i_layers_init
> 
> ------------------
>          /*
>          * The hardware is a bit unusual here.
>          *
>          * Even though it supports 4 layers, it does the composition
>          * in two separate steps.
>          *
>          * The first one is assigning a layer to one of its two
>          * pipes. If more that 1 layer is assigned to the same pipe,
>          * and if pixels overlaps, the pipe will take the pixel from
>          * the layer with the highest priority.
>          *
>          * The second step is the actual alpha blending, that takes
>          * the two pipes as input, and uses the eventual alpha
>          * component to do the transparency between the two.
>          *
>          * This two steps scenario makes us unable to guarantee a
>          * robust alpha blending between the 4 layers in all
>          * situations. So we just expose two layers, one per pipe. On
>          * SoCs that support it, sprites could fill the need for more
>          * layers.
>          */
>         for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
>                 const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
>                 struct sun4i_layer *layer;
> 
>                 layer = sun4i_layer_init_one(drm, backend, plane);
>                 if (IS_ERR(layer)) {
>                         dev_err(drm->dev, "Couldn't initialize %s plane\n",
>                                 i ? "overlay" : "primary");
>                         return ERR_CAST(layer);
>                 };
> 
>                 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
>                                  i ? "overlay" : "primary", plane->pipe);
>                 regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
>                                    SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
>                                    SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
> 
>                 layer->id = i;
>                 planes[i] = &layer->plane;
>         };
> -----------------
>
> I have been using the 3rd layer (layer2) as the input for the
> frontend. This essentially overlays the other 2 layers. Is it still
> the case that we can only have 2 layers here?

Yes.

> Or could be present 1 additional layer when it is attached to the
> frontend?

The frontend will still consume a backend layer. In this current
serie, we still define only two layers for the reasons exposed above,
and whatever layer using hardware scaling will use the frontend.

I have a few patches that would remove that limitation, but we need a
few things in order to do that properly.

The first one would be to add a check on the alpha component of our
layers. We basically have two rules:
  - the lowest plane shouldn't use alpha at all, because of a bug in
    the display engine that would render the pixels completely
    transparents if the alpha is set to something less than 255 on the
    lowest plane.
  - we can only have a plane with alpha as the lowest plane of each
    pipe.

This effectively means that the only scenario that works would be that
there can be only one plane can use alpha at a time, that it shouldn't
be the lowest one, and that it must be assigned to the second pipe.

I worked on that a bit quite some time ago, and the only thing I was
missing was a proper way to check for that in atomic_check, but with
the work done in this serie it shouldn't be too hard.

Then, we can enable the four layers, which is not really difficult in
itself.

> Perhaps this is not relevant for this patchset.

Yep, that's quite orthogonal.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171214/c2d79103/attachment.sig>

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

* Re: [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
@ 2017-12-14 10:32         ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2017-12-14 10:32 UTC (permalink / raw)
  To: Thomas van Kleef
  Cc: Thomas Petazzoni, David Airlie, linux-kernel, dri-devel,
	Chen-Yu Tsai, Daniel Vetter, linux-arm-kernel


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

Hi,

On Wed, Dec 13, 2017 at 05:23:04PM +0100, Thomas van Kleef wrote:
> I wondered if the following is still valid?
> In file sun4i_layer.c, func sun4i_layers_init
> 
> ------------------
>          /*
>          * The hardware is a bit unusual here.
>          *
>          * Even though it supports 4 layers, it does the composition
>          * in two separate steps.
>          *
>          * The first one is assigning a layer to one of its two
>          * pipes. If more that 1 layer is assigned to the same pipe,
>          * and if pixels overlaps, the pipe will take the pixel from
>          * the layer with the highest priority.
>          *
>          * The second step is the actual alpha blending, that takes
>          * the two pipes as input, and uses the eventual alpha
>          * component to do the transparency between the two.
>          *
>          * This two steps scenario makes us unable to guarantee a
>          * robust alpha blending between the 4 layers in all
>          * situations. So we just expose two layers, one per pipe. On
>          * SoCs that support it, sprites could fill the need for more
>          * layers.
>          */
>         for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
>                 const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
>                 struct sun4i_layer *layer;
> 
>                 layer = sun4i_layer_init_one(drm, backend, plane);
>                 if (IS_ERR(layer)) {
>                         dev_err(drm->dev, "Couldn't initialize %s plane\n",
>                                 i ? "overlay" : "primary");
>                         return ERR_CAST(layer);
>                 };
> 
>                 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
>                                  i ? "overlay" : "primary", plane->pipe);
>                 regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
>                                    SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
>                                    SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
> 
>                 layer->id = i;
>                 planes[i] = &layer->plane;
>         };
> -----------------
>
> I have been using the 3rd layer (layer2) as the input for the
> frontend. This essentially overlays the other 2 layers. Is it still
> the case that we can only have 2 layers here?

Yes.

> Or could be present 1 additional layer when it is attached to the
> frontend?

The frontend will still consume a backend layer. In this current
serie, we still define only two layers for the reasons exposed above,
and whatever layer using hardware scaling will use the frontend.

I have a few patches that would remove that limitation, but we need a
few things in order to do that properly.

The first one would be to add a check on the alpha component of our
layers. We basically have two rules:
  - the lowest plane shouldn't use alpha at all, because of a bug in
    the display engine that would render the pixels completely
    transparents if the alpha is set to something less than 255 on the
    lowest plane.
  - we can only have a plane with alpha as the lowest plane of each
    pipe.

This effectively means that the only scenario that works would be that
there can be only one plane can use alpha at a time, that it shouldn't
be the lowest one, and that it must be assigned to the second pipe.

I worked on that a bit quite some time ago, and the only thing I was
missing was a proper way to check for that in atomic_check, but with
the work done in this serie it shouldn't be too hard.

Then, we can enable the four layers, which is not really difficult in
itself.

> Perhaps this is not relevant for this patchset.

Yep, that's quite orthogonal.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

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

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 5/8] drm/sun4i: Add a driver for the display frontend
  2017-12-13 15:33     ` Maxime Ripard
  (?)
@ 2017-12-16  7:00       ` kbuild test robot
  -1 siblings, 0 replies; 62+ messages in thread
From: kbuild test robot @ 2017-12-16  7:00 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: kbuild-all, Daniel Vetter, David Airlie, Chen-Yu Tsai,
	Maxime Ripard, linux-arm-kernel, Thomas Petazzoni, linux-kernel,
	dri-devel, thomas

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

Hi Maxime,

I love your patch! Yet something to improve:

[auto build test ERROR on ]

url:    https://github.com/0day-ci/linux/commits/Maxime-Ripard/drm-sun4i-Support-the-Display-Engine-frontend/20171216-122702
base:    
config: arm-sunxi_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        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
        make.cross ARCH=arm 

Note: the linux-review/Maxime-Ripard/drm-sun4i-Support-the-Display-Engine-frontend/20171216-122702 HEAD c38c4ce4b14c4c68a9fde0cc35ead5b1c894776b builds fine.
      It only hurts bisectibility.

All error/warnings (new ones prefixed by >>):

   drivers/gpu/drm/sun4i/sun4i_backend.c: In function 'sun4i_backend_bind':
>> drivers/gpu/drm/sun4i/sun4i_backend.c:370:22: error: implicit declaration of function 'sun4i_backend_find_frontend'; did you mean 'sun4i_backend_bind'? [-Werror=implicit-function-declaration]
     backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
                         sun4i_backend_bind
>> drivers/gpu/drm/sun4i/sun4i_backend.c:370:20: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
     backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
                       ^
   cc1: some warnings being treated as errors

vim +370 drivers/gpu/drm/sun4i/sun4i_backend.c

   346	
   347	static int sun4i_backend_bind(struct device *dev, struct device *master,
   348				      void *data)
   349	{
   350		struct platform_device *pdev = to_platform_device(dev);
   351		struct drm_device *drm = data;
   352		struct sun4i_drv *drv = drm->dev_private;
   353		struct sun4i_backend *backend;
   354		const struct sun4i_backend_quirks *quirks;
   355		struct resource *res;
   356		void __iomem *regs;
   357		int i, ret;
   358	
   359		backend = devm_kzalloc(dev, sizeof(*backend), GFP_KERNEL);
   360		if (!backend)
   361			return -ENOMEM;
   362		dev_set_drvdata(dev, backend);
   363	
   364		backend->engine.node = dev->of_node;
   365		backend->engine.ops = &sun4i_backend_engine_ops;
   366		backend->engine.id = sun4i_backend_of_get_id(dev->of_node);
   367		if (backend->engine.id < 0)
   368			return backend->engine.id;
   369	
 > 370		backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
   371		if (IS_ERR(backend->frontend)) {
   372			dev_err(dev, "Couldn't find matching frontend, frontend features disabled\n");
   373		}
   374	
   375		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
   376		regs = devm_ioremap_resource(dev, res);
   377		if (IS_ERR(regs))
   378			return PTR_ERR(regs);
   379	
   380		backend->reset = devm_reset_control_get(dev, NULL);
   381		if (IS_ERR(backend->reset)) {
   382			dev_err(dev, "Couldn't get our reset line\n");
   383			return PTR_ERR(backend->reset);
   384		}
   385	
   386		ret = reset_control_deassert(backend->reset);
   387		if (ret) {
   388			dev_err(dev, "Couldn't deassert our reset line\n");
   389			return ret;
   390		}
   391	
   392		backend->bus_clk = devm_clk_get(dev, "ahb");
   393		if (IS_ERR(backend->bus_clk)) {
   394			dev_err(dev, "Couldn't get the backend bus clock\n");
   395			ret = PTR_ERR(backend->bus_clk);
   396			goto err_assert_reset;
   397		}
   398		clk_prepare_enable(backend->bus_clk);
   399	
   400		backend->mod_clk = devm_clk_get(dev, "mod");
   401		if (IS_ERR(backend->mod_clk)) {
   402			dev_err(dev, "Couldn't get the backend module clock\n");
   403			ret = PTR_ERR(backend->mod_clk);
   404			goto err_disable_bus_clk;
   405		}
   406		clk_prepare_enable(backend->mod_clk);
   407	
   408		backend->ram_clk = devm_clk_get(dev, "ram");
   409		if (IS_ERR(backend->ram_clk)) {
   410			dev_err(dev, "Couldn't get the backend RAM clock\n");
   411			ret = PTR_ERR(backend->ram_clk);
   412			goto err_disable_mod_clk;
   413		}
   414		clk_prepare_enable(backend->ram_clk);
   415	
   416		if (of_device_is_compatible(dev->of_node,
   417					    "allwinner,sun8i-a33-display-backend")) {
   418			ret = sun4i_backend_init_sat(dev);
   419			if (ret) {
   420				dev_err(dev, "Couldn't init SAT resources\n");
   421				goto err_disable_ram_clk;
   422			}
   423		}
   424	
   425		backend->engine.regs = devm_regmap_init_mmio(dev, regs,
   426							     &sun4i_backend_regmap_config);
   427		if (IS_ERR(backend->engine.regs)) {
   428			dev_err(dev, "Couldn't create the backend regmap\n");
   429			return PTR_ERR(backend->engine.regs);
   430		}
   431	
   432		list_add_tail(&backend->engine.list, &drv->engine_list);
   433	
   434		/*
   435		 * Many of the backend's layer configuration registers have
   436		 * undefined default values. This poses a risk as we use
   437		 * regmap_update_bits in some places, and don't overwrite
   438		 * the whole register.
   439		 *
   440		 * Clear the registers here to have something predictable.
   441		 */
   442		for (i = 0x800; i < 0x1000; i += 4)
   443			regmap_write(backend->engine.regs, i, 0);
   444	
   445		/* Disable registers autoloading */
   446		regmap_write(backend->engine.regs, SUN4I_BACKEND_REGBUFFCTL_REG,
   447			     SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS);
   448	
   449		/* Enable the backend */
   450		regmap_write(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
   451			     SUN4I_BACKEND_MODCTL_DEBE_EN |
   452			     SUN4I_BACKEND_MODCTL_START_CTL);
   453	
   454		/* Set output selection if needed */
   455		quirks = of_device_get_match_data(dev);
   456		if (quirks->needs_output_muxing) {
   457			/*
   458			 * We assume there is no dynamic muxing of backends
   459			 * and TCONs, so we select the backend with same ID.
   460			 *
   461			 * While dynamic selection might be interesting, since
   462			 * the CRTC is tied to the TCON, while the layers are
   463			 * tied to the backends, this means, we will need to
   464			 * switch between groups of layers. There might not be
   465			 * a way to represent this constraint in DRM.
   466			 */
   467			regmap_update_bits(backend->engine.regs,
   468					   SUN4I_BACKEND_MODCTL_REG,
   469					   SUN4I_BACKEND_MODCTL_OUT_SEL,
   470					   (backend->engine.id
   471					    ? SUN4I_BACKEND_MODCTL_OUT_LCD1
   472					    : SUN4I_BACKEND_MODCTL_OUT_LCD0));
   473		}
   474	
   475		return 0;
   476	
   477	err_disable_ram_clk:
   478		clk_disable_unprepare(backend->ram_clk);
   479	err_disable_mod_clk:
   480		clk_disable_unprepare(backend->mod_clk);
   481	err_disable_bus_clk:
   482		clk_disable_unprepare(backend->bus_clk);
   483	err_assert_reset:
   484		reset_control_assert(backend->reset);
   485		return ret;
   486	}
   487	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 23186 bytes --]

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

* [PATCH 5/8] drm/sun4i: Add a driver for the display frontend
@ 2017-12-16  7:00       ` kbuild test robot
  0 siblings, 0 replies; 62+ messages in thread
From: kbuild test robot @ 2017-12-16  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Maxime,

I love your patch! Yet something to improve:

[auto build test ERROR on ]

url:    https://github.com/0day-ci/linux/commits/Maxime-Ripard/drm-sun4i-Support-the-Display-Engine-frontend/20171216-122702
base:    
config: arm-sunxi_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        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
        make.cross ARCH=arm 

Note: the linux-review/Maxime-Ripard/drm-sun4i-Support-the-Display-Engine-frontend/20171216-122702 HEAD c38c4ce4b14c4c68a9fde0cc35ead5b1c894776b builds fine.
      It only hurts bisectibility.

All error/warnings (new ones prefixed by >>):

   drivers/gpu/drm/sun4i/sun4i_backend.c: In function 'sun4i_backend_bind':
>> drivers/gpu/drm/sun4i/sun4i_backend.c:370:22: error: implicit declaration of function 'sun4i_backend_find_frontend'; did you mean 'sun4i_backend_bind'? [-Werror=implicit-function-declaration]
     backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
                         sun4i_backend_bind
>> drivers/gpu/drm/sun4i/sun4i_backend.c:370:20: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
     backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
                       ^
   cc1: some warnings being treated as errors

vim +370 drivers/gpu/drm/sun4i/sun4i_backend.c

   346	
   347	static int sun4i_backend_bind(struct device *dev, struct device *master,
   348				      void *data)
   349	{
   350		struct platform_device *pdev = to_platform_device(dev);
   351		struct drm_device *drm = data;
   352		struct sun4i_drv *drv = drm->dev_private;
   353		struct sun4i_backend *backend;
   354		const struct sun4i_backend_quirks *quirks;
   355		struct resource *res;
   356		void __iomem *regs;
   357		int i, ret;
   358	
   359		backend = devm_kzalloc(dev, sizeof(*backend), GFP_KERNEL);
   360		if (!backend)
   361			return -ENOMEM;
   362		dev_set_drvdata(dev, backend);
   363	
   364		backend->engine.node = dev->of_node;
   365		backend->engine.ops = &sun4i_backend_engine_ops;
   366		backend->engine.id = sun4i_backend_of_get_id(dev->of_node);
   367		if (backend->engine.id < 0)
   368			return backend->engine.id;
   369	
 > 370		backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
   371		if (IS_ERR(backend->frontend)) {
   372			dev_err(dev, "Couldn't find matching frontend, frontend features disabled\n");
   373		}
   374	
   375		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
   376		regs = devm_ioremap_resource(dev, res);
   377		if (IS_ERR(regs))
   378			return PTR_ERR(regs);
   379	
   380		backend->reset = devm_reset_control_get(dev, NULL);
   381		if (IS_ERR(backend->reset)) {
   382			dev_err(dev, "Couldn't get our reset line\n");
   383			return PTR_ERR(backend->reset);
   384		}
   385	
   386		ret = reset_control_deassert(backend->reset);
   387		if (ret) {
   388			dev_err(dev, "Couldn't deassert our reset line\n");
   389			return ret;
   390		}
   391	
   392		backend->bus_clk = devm_clk_get(dev, "ahb");
   393		if (IS_ERR(backend->bus_clk)) {
   394			dev_err(dev, "Couldn't get the backend bus clock\n");
   395			ret = PTR_ERR(backend->bus_clk);
   396			goto err_assert_reset;
   397		}
   398		clk_prepare_enable(backend->bus_clk);
   399	
   400		backend->mod_clk = devm_clk_get(dev, "mod");
   401		if (IS_ERR(backend->mod_clk)) {
   402			dev_err(dev, "Couldn't get the backend module clock\n");
   403			ret = PTR_ERR(backend->mod_clk);
   404			goto err_disable_bus_clk;
   405		}
   406		clk_prepare_enable(backend->mod_clk);
   407	
   408		backend->ram_clk = devm_clk_get(dev, "ram");
   409		if (IS_ERR(backend->ram_clk)) {
   410			dev_err(dev, "Couldn't get the backend RAM clock\n");
   411			ret = PTR_ERR(backend->ram_clk);
   412			goto err_disable_mod_clk;
   413		}
   414		clk_prepare_enable(backend->ram_clk);
   415	
   416		if (of_device_is_compatible(dev->of_node,
   417					    "allwinner,sun8i-a33-display-backend")) {
   418			ret = sun4i_backend_init_sat(dev);
   419			if (ret) {
   420				dev_err(dev, "Couldn't init SAT resources\n");
   421				goto err_disable_ram_clk;
   422			}
   423		}
   424	
   425		backend->engine.regs = devm_regmap_init_mmio(dev, regs,
   426							     &sun4i_backend_regmap_config);
   427		if (IS_ERR(backend->engine.regs)) {
   428			dev_err(dev, "Couldn't create the backend regmap\n");
   429			return PTR_ERR(backend->engine.regs);
   430		}
   431	
   432		list_add_tail(&backend->engine.list, &drv->engine_list);
   433	
   434		/*
   435		 * Many of the backend's layer configuration registers have
   436		 * undefined default values. This poses a risk as we use
   437		 * regmap_update_bits in some places, and don't overwrite
   438		 * the whole register.
   439		 *
   440		 * Clear the registers here to have something predictable.
   441		 */
   442		for (i = 0x800; i < 0x1000; i += 4)
   443			regmap_write(backend->engine.regs, i, 0);
   444	
   445		/* Disable registers autoloading */
   446		regmap_write(backend->engine.regs, SUN4I_BACKEND_REGBUFFCTL_REG,
   447			     SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS);
   448	
   449		/* Enable the backend */
   450		regmap_write(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
   451			     SUN4I_BACKEND_MODCTL_DEBE_EN |
   452			     SUN4I_BACKEND_MODCTL_START_CTL);
   453	
   454		/* Set output selection if needed */
   455		quirks = of_device_get_match_data(dev);
   456		if (quirks->needs_output_muxing) {
   457			/*
   458			 * We assume there is no dynamic muxing of backends
   459			 * and TCONs, so we select the backend with same ID.
   460			 *
   461			 * While dynamic selection might be interesting, since
   462			 * the CRTC is tied to the TCON, while the layers are
   463			 * tied to the backends, this means, we will need to
   464			 * switch between groups of layers. There might not be
   465			 * a way to represent this constraint in DRM.
   466			 */
   467			regmap_update_bits(backend->engine.regs,
   468					   SUN4I_BACKEND_MODCTL_REG,
   469					   SUN4I_BACKEND_MODCTL_OUT_SEL,
   470					   (backend->engine.id
   471					    ? SUN4I_BACKEND_MODCTL_OUT_LCD1
   472					    : SUN4I_BACKEND_MODCTL_OUT_LCD0));
   473		}
   474	
   475		return 0;
   476	
   477	err_disable_ram_clk:
   478		clk_disable_unprepare(backend->ram_clk);
   479	err_disable_mod_clk:
   480		clk_disable_unprepare(backend->mod_clk);
   481	err_disable_bus_clk:
   482		clk_disable_unprepare(backend->bus_clk);
   483	err_assert_reset:
   484		reset_control_assert(backend->reset);
   485		return ret;
   486	}
   487	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 23186 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171216/09df427a/attachment-0001.gz>

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

* Re: [PATCH 5/8] drm/sun4i: Add a driver for the display frontend
@ 2017-12-16  7:00       ` kbuild test robot
  0 siblings, 0 replies; 62+ messages in thread
From: kbuild test robot @ 2017-12-16  7:00 UTC (permalink / raw)
  Cc: Thomas Petazzoni, David Airlie, linux-kernel, dri-devel,
	Chen-Yu Tsai, kbuild-all, Daniel Vetter, Maxime Ripard,
	linux-arm-kernel, thomas

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

Hi Maxime,

I love your patch! Yet something to improve:

[auto build test ERROR on ]

url:    https://github.com/0day-ci/linux/commits/Maxime-Ripard/drm-sun4i-Support-the-Display-Engine-frontend/20171216-122702
base:    
config: arm-sunxi_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        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
        make.cross ARCH=arm 

Note: the linux-review/Maxime-Ripard/drm-sun4i-Support-the-Display-Engine-frontend/20171216-122702 HEAD c38c4ce4b14c4c68a9fde0cc35ead5b1c894776b builds fine.
      It only hurts bisectibility.

All error/warnings (new ones prefixed by >>):

   drivers/gpu/drm/sun4i/sun4i_backend.c: In function 'sun4i_backend_bind':
>> drivers/gpu/drm/sun4i/sun4i_backend.c:370:22: error: implicit declaration of function 'sun4i_backend_find_frontend'; did you mean 'sun4i_backend_bind'? [-Werror=implicit-function-declaration]
     backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
                         sun4i_backend_bind
>> drivers/gpu/drm/sun4i/sun4i_backend.c:370:20: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
     backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
                       ^
   cc1: some warnings being treated as errors

vim +370 drivers/gpu/drm/sun4i/sun4i_backend.c

   346	
   347	static int sun4i_backend_bind(struct device *dev, struct device *master,
   348				      void *data)
   349	{
   350		struct platform_device *pdev = to_platform_device(dev);
   351		struct drm_device *drm = data;
   352		struct sun4i_drv *drv = drm->dev_private;
   353		struct sun4i_backend *backend;
   354		const struct sun4i_backend_quirks *quirks;
   355		struct resource *res;
   356		void __iomem *regs;
   357		int i, ret;
   358	
   359		backend = devm_kzalloc(dev, sizeof(*backend), GFP_KERNEL);
   360		if (!backend)
   361			return -ENOMEM;
   362		dev_set_drvdata(dev, backend);
   363	
   364		backend->engine.node = dev->of_node;
   365		backend->engine.ops = &sun4i_backend_engine_ops;
   366		backend->engine.id = sun4i_backend_of_get_id(dev->of_node);
   367		if (backend->engine.id < 0)
   368			return backend->engine.id;
   369	
 > 370		backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
   371		if (IS_ERR(backend->frontend)) {
   372			dev_err(dev, "Couldn't find matching frontend, frontend features disabled\n");
   373		}
   374	
   375		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
   376		regs = devm_ioremap_resource(dev, res);
   377		if (IS_ERR(regs))
   378			return PTR_ERR(regs);
   379	
   380		backend->reset = devm_reset_control_get(dev, NULL);
   381		if (IS_ERR(backend->reset)) {
   382			dev_err(dev, "Couldn't get our reset line\n");
   383			return PTR_ERR(backend->reset);
   384		}
   385	
   386		ret = reset_control_deassert(backend->reset);
   387		if (ret) {
   388			dev_err(dev, "Couldn't deassert our reset line\n");
   389			return ret;
   390		}
   391	
   392		backend->bus_clk = devm_clk_get(dev, "ahb");
   393		if (IS_ERR(backend->bus_clk)) {
   394			dev_err(dev, "Couldn't get the backend bus clock\n");
   395			ret = PTR_ERR(backend->bus_clk);
   396			goto err_assert_reset;
   397		}
   398		clk_prepare_enable(backend->bus_clk);
   399	
   400		backend->mod_clk = devm_clk_get(dev, "mod");
   401		if (IS_ERR(backend->mod_clk)) {
   402			dev_err(dev, "Couldn't get the backend module clock\n");
   403			ret = PTR_ERR(backend->mod_clk);
   404			goto err_disable_bus_clk;
   405		}
   406		clk_prepare_enable(backend->mod_clk);
   407	
   408		backend->ram_clk = devm_clk_get(dev, "ram");
   409		if (IS_ERR(backend->ram_clk)) {
   410			dev_err(dev, "Couldn't get the backend RAM clock\n");
   411			ret = PTR_ERR(backend->ram_clk);
   412			goto err_disable_mod_clk;
   413		}
   414		clk_prepare_enable(backend->ram_clk);
   415	
   416		if (of_device_is_compatible(dev->of_node,
   417					    "allwinner,sun8i-a33-display-backend")) {
   418			ret = sun4i_backend_init_sat(dev);
   419			if (ret) {
   420				dev_err(dev, "Couldn't init SAT resources\n");
   421				goto err_disable_ram_clk;
   422			}
   423		}
   424	
   425		backend->engine.regs = devm_regmap_init_mmio(dev, regs,
   426							     &sun4i_backend_regmap_config);
   427		if (IS_ERR(backend->engine.regs)) {
   428			dev_err(dev, "Couldn't create the backend regmap\n");
   429			return PTR_ERR(backend->engine.regs);
   430		}
   431	
   432		list_add_tail(&backend->engine.list, &drv->engine_list);
   433	
   434		/*
   435		 * Many of the backend's layer configuration registers have
   436		 * undefined default values. This poses a risk as we use
   437		 * regmap_update_bits in some places, and don't overwrite
   438		 * the whole register.
   439		 *
   440		 * Clear the registers here to have something predictable.
   441		 */
   442		for (i = 0x800; i < 0x1000; i += 4)
   443			regmap_write(backend->engine.regs, i, 0);
   444	
   445		/* Disable registers autoloading */
   446		regmap_write(backend->engine.regs, SUN4I_BACKEND_REGBUFFCTL_REG,
   447			     SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS);
   448	
   449		/* Enable the backend */
   450		regmap_write(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
   451			     SUN4I_BACKEND_MODCTL_DEBE_EN |
   452			     SUN4I_BACKEND_MODCTL_START_CTL);
   453	
   454		/* Set output selection if needed */
   455		quirks = of_device_get_match_data(dev);
   456		if (quirks->needs_output_muxing) {
   457			/*
   458			 * We assume there is no dynamic muxing of backends
   459			 * and TCONs, so we select the backend with same ID.
   460			 *
   461			 * While dynamic selection might be interesting, since
   462			 * the CRTC is tied to the TCON, while the layers are
   463			 * tied to the backends, this means, we will need to
   464			 * switch between groups of layers. There might not be
   465			 * a way to represent this constraint in DRM.
   466			 */
   467			regmap_update_bits(backend->engine.regs,
   468					   SUN4I_BACKEND_MODCTL_REG,
   469					   SUN4I_BACKEND_MODCTL_OUT_SEL,
   470					   (backend->engine.id
   471					    ? SUN4I_BACKEND_MODCTL_OUT_LCD1
   472					    : SUN4I_BACKEND_MODCTL_OUT_LCD0));
   473		}
   474	
   475		return 0;
   476	
   477	err_disable_ram_clk:
   478		clk_disable_unprepare(backend->ram_clk);
   479	err_disable_mod_clk:
   480		clk_disable_unprepare(backend->mod_clk);
   481	err_disable_bus_clk:
   482		clk_disable_unprepare(backend->bus_clk);
   483	err_assert_reset:
   484		reset_control_assert(backend->reset);
   485		return ret;
   486	}
   487	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 23186 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
  2017-12-13 15:33     ` Maxime Ripard
  (?)
@ 2017-12-16  9:17       ` kbuild test robot
  -1 siblings, 0 replies; 62+ messages in thread
From: kbuild test robot @ 2017-12-16  9:17 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: kbuild-all, Daniel Vetter, David Airlie, Chen-Yu Tsai,
	Maxime Ripard, linux-arm-kernel, Thomas Petazzoni, linux-kernel,
	dri-devel, thomas

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

Hi Maxime,

I love your patch! Yet something to improve:

[auto build test ERROR on ]

url:    https://github.com/0day-ci/linux/commits/Maxime-Ripard/drm-sun4i-Support-the-Display-Engine-frontend/20171216-122702
base:    
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        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
        make.cross ARCH=arm 

All errors (new ones prefixed by >>):

   WARNING: modpost: missing MODULE_LICENSE() in arch/arm/common/bL_switcher_dummy_if.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/auxdisplay/img-ascii-lcd.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/cpufreq/mediatek-cpufreq.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/gpio/gpio-ath79.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/gpio/gpio-iop.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/iio/accel/kxsd9-i2c.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/iio/adc/qcom-vadc-common.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/media/platform/mtk-vcodec/mtk-vcodec-common.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/media/platform/soc_camera/soc_scale_crop.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/media/platform/tegra-cec/tegra_cec.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/mmc/host/renesas_sdhi_core.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/mtd/nand/denali_pci.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/net/ethernet/cirrus/cs89x0.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/phy/qualcomm/phy-qcom-ufs.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/pinctrl/pxa/pinctrl-pxa2xx.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/power/reset/zx-reboot.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/soc/qcom/rmtfs_mem.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/staging/comedi/drivers/ni_atmio.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/video/fbdev/mmp/mmp_disp.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in sound/soc/codecs/snd-soc-pcm512x-spi.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in sound/soc/ux500/snd-soc-ux500-mach-mop500.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in sound/soc/ux500/snd-soc-ux500-plat-dma.o
   see include/linux/module.h for more information
>> ERROR: "sun4i_frontend_update_formats" [drivers/gpu/drm/sun4i/sun4i-backend.ko] undefined!
>> ERROR: "sun4i_frontend_update_buffer" [drivers/gpu/drm/sun4i/sun4i-backend.ko] undefined!

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 64661 bytes --]

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

* [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
@ 2017-12-16  9:17       ` kbuild test robot
  0 siblings, 0 replies; 62+ messages in thread
From: kbuild test robot @ 2017-12-16  9:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Maxime,

I love your patch! Yet something to improve:

[auto build test ERROR on ]

url:    https://github.com/0day-ci/linux/commits/Maxime-Ripard/drm-sun4i-Support-the-Display-Engine-frontend/20171216-122702
base:    
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        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
        make.cross ARCH=arm 

All errors (new ones prefixed by >>):

   WARNING: modpost: missing MODULE_LICENSE() in arch/arm/common/bL_switcher_dummy_if.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/auxdisplay/img-ascii-lcd.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/cpufreq/mediatek-cpufreq.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/gpio/gpio-ath79.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/gpio/gpio-iop.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/iio/accel/kxsd9-i2c.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/iio/adc/qcom-vadc-common.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/media/platform/mtk-vcodec/mtk-vcodec-common.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/media/platform/soc_camera/soc_scale_crop.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/media/platform/tegra-cec/tegra_cec.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/mmc/host/renesas_sdhi_core.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/mtd/nand/denali_pci.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/net/ethernet/cirrus/cs89x0.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/phy/qualcomm/phy-qcom-ufs.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/pinctrl/pxa/pinctrl-pxa2xx.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/power/reset/zx-reboot.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/soc/qcom/rmtfs_mem.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/staging/comedi/drivers/ni_atmio.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/video/fbdev/mmp/mmp_disp.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in sound/soc/codecs/snd-soc-pcm512x-spi.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in sound/soc/ux500/snd-soc-ux500-mach-mop500.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in sound/soc/ux500/snd-soc-ux500-plat-dma.o
   see include/linux/module.h for more information
>> ERROR: "sun4i_frontend_update_formats" [drivers/gpu/drm/sun4i/sun4i-backend.ko] undefined!
>> ERROR: "sun4i_frontend_update_buffer" [drivers/gpu/drm/sun4i/sun4i-backend.ko] undefined!

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 64661 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171216/9eb1088e/attachment-0001.gz>

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

* Re: [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend
@ 2017-12-16  9:17       ` kbuild test robot
  0 siblings, 0 replies; 62+ messages in thread
From: kbuild test robot @ 2017-12-16  9:17 UTC (permalink / raw)
  Cc: Thomas Petazzoni, David Airlie, linux-kernel, dri-devel,
	Chen-Yu Tsai, kbuild-all, Daniel Vetter, Maxime Ripard,
	linux-arm-kernel, thomas

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

Hi Maxime,

I love your patch! Yet something to improve:

[auto build test ERROR on ]

url:    https://github.com/0day-ci/linux/commits/Maxime-Ripard/drm-sun4i-Support-the-Display-Engine-frontend/20171216-122702
base:    
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        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
        make.cross ARCH=arm 

All errors (new ones prefixed by >>):

   WARNING: modpost: missing MODULE_LICENSE() in arch/arm/common/bL_switcher_dummy_if.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/auxdisplay/img-ascii-lcd.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/cpufreq/mediatek-cpufreq.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/gpio/gpio-ath79.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/gpio/gpio-iop.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/iio/accel/kxsd9-i2c.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/iio/adc/qcom-vadc-common.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/media/platform/mtk-vcodec/mtk-vcodec-common.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/media/platform/soc_camera/soc_scale_crop.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/media/platform/tegra-cec/tegra_cec.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/mmc/host/renesas_sdhi_core.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/mtd/nand/denali_pci.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/net/ethernet/cirrus/cs89x0.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/phy/qualcomm/phy-qcom-ufs.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/pinctrl/pxa/pinctrl-pxa2xx.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/power/reset/zx-reboot.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/soc/qcom/rmtfs_mem.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/staging/comedi/drivers/ni_atmio.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in drivers/video/fbdev/mmp/mmp_disp.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in sound/soc/codecs/snd-soc-pcm512x-spi.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in sound/soc/ux500/snd-soc-ux500-mach-mop500.o
   see include/linux/module.h for more information
   WARNING: modpost: missing MODULE_LICENSE() in sound/soc/ux500/snd-soc-ux500-plat-dma.o
   see include/linux/module.h for more information
>> ERROR: "sun4i_frontend_update_formats" [drivers/gpu/drm/sun4i/sun4i-backend.ko] undefined!
>> ERROR: "sun4i_frontend_update_buffer" [drivers/gpu/drm/sun4i/sun4i-backend.ko] undefined!

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 64661 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

end of thread, other threads:[~2017-12-16  9:17 UTC | newest]

Thread overview: 62+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <1513181781-0808628882.0a9bc10eb7@prakkezator.vehosting.nl>
2017-12-13 15:33 ` [PATCH 0/8] drm/sun4i: Support the Display Engine frontend Maxime Ripard
2017-12-13 15:33   ` Maxime Ripard
2017-12-13 15:33   ` Maxime Ripard
2017-12-13 15:33   ` [PATCH 1/8] drm/sun4i: backend: Move line stride setup to buffer setup function Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 16:03     ` Neil Armstrong
2017-12-13 16:03       ` Neil Armstrong
2017-12-13 16:03       ` Neil Armstrong
2017-12-13 15:33   ` [PATCH 2/8] drm/sun4i: backend: Allow a NULL plane pointer to retrieve the format Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 16:03     ` Neil Armstrong
2017-12-13 16:03       ` Neil Armstrong
2017-12-13 16:03       ` Neil Armstrong
2017-12-13 15:33   ` [PATCH 3/8] drm/sun4i: sun4i_layer: Add a custom plane state Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 16:05     ` Neil Armstrong
2017-12-13 16:05       ` Neil Armstrong
2017-12-13 16:05       ` Neil Armstrong
2017-12-13 15:33   ` [PATCH 4/8] drm/sun4i: crtc: Add a custom crtc atomic_check Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 16:06     ` Neil Armstrong
2017-12-13 16:06       ` Neil Armstrong
2017-12-13 16:06       ` Neil Armstrong
2017-12-13 15:33   ` [PATCH 5/8] drm/sun4i: Add a driver for the display frontend Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 16:10     ` Neil Armstrong
2017-12-13 16:10       ` Neil Armstrong
2017-12-13 16:10       ` Neil Armstrong
2017-12-16  7:00     ` kbuild test robot
2017-12-16  7:00       ` kbuild test robot
2017-12-16  7:00       ` kbuild test robot
2017-12-13 15:33   ` [PATCH 6/8] drm/sun4i: sun4i_layer: Wire in the frontend Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 16:11     ` Neil Armstrong
2017-12-13 16:11       ` Neil Armstrong
2017-12-13 16:11       ` Neil Armstrong
2017-12-13 16:23     ` Thomas van Kleef
2017-12-13 16:23       ` Thomas van Kleef
2017-12-14 10:32       ` Maxime Ripard
2017-12-14 10:32         ` Maxime Ripard
2017-12-14 10:32         ` Maxime Ripard
2017-12-16  9:17     ` kbuild test robot
2017-12-16  9:17       ` kbuild test robot
2017-12-16  9:17       ` kbuild test robot
2017-12-13 15:33   ` [PATCH 7/8] drm/sun4i: sun4i_layer: Add a custom atomic_check for " Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 16:12     ` Neil Armstrong
2017-12-13 16:12       ` Neil Armstrong
2017-12-13 16:12       ` Neil Armstrong
2017-12-13 15:33   ` [PATCH 8/8] ARM: dts: sun8i: a33 Enable our display frontend Maxime Ripard
2017-12-13 15:33     ` Maxime Ripard
2017-12-13 16:16   ` [PATCH 0/8] drm/sun4i: Support the Display Engine frontend Thomas van Kleef
2017-12-13 16:16     ` Thomas van Kleef
2017-12-14  8:35     ` Maxime Ripard
2017-12-14  8:35       ` Maxime Ripard
2017-12-14  8:35       ` Maxime Ripard

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.