All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/12] drm/sun4i: Support the Display Engine frontend
@ 2017-12-18 14:57 ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, 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

Changes from v1:
  - Fixed the unbind function to not disable the already disabled clocks,
    and to remove ourself from the frontend list
  - Changed the log level of the frontend disabled message
  - Added blank lines where suggested by Neil
  - Fixed an artifact that was happening when the plane using the frontend
    was disabled. This was happening because the frontend was disabled
    before the backend layer (that would be disabled at the next vblank).
    This led to a significant rework of the patches, so I didn't apply all
    the tags. I also had to take a few patches in.
  - Added engine ops documentation
  - Fixed a bug in our duplicate_state callback that wouldn't preserve the
    frontend state
  - Removed the hardcoded register values and used the real ones instead.
  - Fixed some compilation errors reported by the 0-day bot.

Maxime Ripard (12):
  drm/sun4i: backend: Move line stride setup to buffer setup function
  sun4i/drm: backend: Document the engine operations
  drm/sun4i: backend: Add a custom plane state
  drm/sun4i: engine: Add a custom crtc atomic_check
  drm/sun4i: engine: Add a VBLANK quirk callback
  drm/sun4i: engine: Create an atomic_begin callback
  drm/sun4i: Add a driver for the display frontend
  drm/sun4i: backend: Wire in the frontend
  drm/sun4i: backend: Add a custom atomic_check for the frontend
  drm/sun4i: backend: Use runtime_pm variant of atomic_commit_tail
  drm/sun4i: backend: Make sure we don't have a commit pending
  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     | 183 ++++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h     |  10 +-
 drivers/gpu/drm/sun4i/sun4i_crtc.c        |  21 +-
 drivers/gpu/drm/sun4i/sun4i_drv.c         |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h         |   1 +-
 drivers/gpu/drm/sun4i/sun4i_framebuffer.c |   6 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c    | 392 +++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h    |  96 ++++++-
 drivers/gpu/drm/sun4i/sun4i_layer.c       |  83 ++++-
 drivers/gpu/drm/sun4i/sun4i_layer.h       |  11 +-
 drivers/gpu/drm/sun4i/sun4i_tcon.c        |   4 +-
 drivers/gpu/drm/sun4i/sunxi_engine.h      |  93 ++++-
 14 files changed, 897 insertions(+), 23 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] 65+ messages in thread

* [PATCH v2 00/12] drm/sun4i: Support the Display Engine frontend
@ 2017-12-18 14:57 ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 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

Changes from v1:
  - Fixed the unbind function to not disable the already disabled clocks,
    and to remove ourself from the frontend list
  - Changed the log level of the frontend disabled message
  - Added blank lines where suggested by Neil
  - Fixed an artifact that was happening when the plane using the frontend
    was disabled. This was happening because the frontend was disabled
    before the backend layer (that would be disabled at the next vblank).
    This led to a significant rework of the patches, so I didn't apply all
    the tags. I also had to take a few patches in.
  - Added engine ops documentation
  - Fixed a bug in our duplicate_state callback that wouldn't preserve the
    frontend state
  - Removed the hardcoded register values and used the real ones instead.
  - Fixed some compilation errors reported by the 0-day bot.

Maxime Ripard (12):
  drm/sun4i: backend: Move line stride setup to buffer setup function
  sun4i/drm: backend: Document the engine operations
  drm/sun4i: backend: Add a custom plane state
  drm/sun4i: engine: Add a custom crtc atomic_check
  drm/sun4i: engine: Add a VBLANK quirk callback
  drm/sun4i: engine: Create an atomic_begin callback
  drm/sun4i: Add a driver for the display frontend
  drm/sun4i: backend: Wire in the frontend
  drm/sun4i: backend: Add a custom atomic_check for the frontend
  drm/sun4i: backend: Use runtime_pm variant of atomic_commit_tail
  drm/sun4i: backend: Make sure we don't have a commit pending
  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     | 183 ++++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h     |  10 +-
 drivers/gpu/drm/sun4i/sun4i_crtc.c        |  21 +-
 drivers/gpu/drm/sun4i/sun4i_drv.c         |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h         |   1 +-
 drivers/gpu/drm/sun4i/sun4i_framebuffer.c |   6 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c    | 392 +++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h    |  96 ++++++-
 drivers/gpu/drm/sun4i/sun4i_layer.c       |  83 ++++-
 drivers/gpu/drm/sun4i/sun4i_layer.h       |  11 +-
 drivers/gpu/drm/sun4i/sun4i_tcon.c        |   4 +-
 drivers/gpu/drm/sun4i/sunxi_engine.h      |  93 ++++-
 14 files changed, 897 insertions(+), 23 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] 65+ messages in thread

* [PATCH v2 00/12] drm/sun4i: Support the Display Engine frontend
@ 2017-12-18 14:57 ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, 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

Changes from v1:
  - Fixed the unbind function to not disable the already disabled clocks,
    and to remove ourself from the frontend list
  - Changed the log level of the frontend disabled message
  - Added blank lines where suggested by Neil
  - Fixed an artifact that was happening when the plane using the frontend
    was disabled. This was happening because the frontend was disabled
    before the backend layer (that would be disabled at the next vblank).
    This led to a significant rework of the patches, so I didn't apply all
    the tags. I also had to take a few patches in.
  - Added engine ops documentation
  - Fixed a bug in our duplicate_state callback that wouldn't preserve the
    frontend state
  - Removed the hardcoded register values and used the real ones instead.
  - Fixed some compilation errors reported by the 0-day bot.

Maxime Ripard (12):
  drm/sun4i: backend: Move line stride setup to buffer setup function
  sun4i/drm: backend: Document the engine operations
  drm/sun4i: backend: Add a custom plane state
  drm/sun4i: engine: Add a custom crtc atomic_check
  drm/sun4i: engine: Add a VBLANK quirk callback
  drm/sun4i: engine: Create an atomic_begin callback
  drm/sun4i: Add a driver for the display frontend
  drm/sun4i: backend: Wire in the frontend
  drm/sun4i: backend: Add a custom atomic_check for the frontend
  drm/sun4i: backend: Use runtime_pm variant of atomic_commit_tail
  drm/sun4i: backend: Make sure we don't have a commit pending
  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     | 183 ++++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h     |  10 +-
 drivers/gpu/drm/sun4i/sun4i_crtc.c        |  21 +-
 drivers/gpu/drm/sun4i/sun4i_drv.c         |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h         |   1 +-
 drivers/gpu/drm/sun4i/sun4i_framebuffer.c |   6 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c    | 392 +++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h    |  96 ++++++-
 drivers/gpu/drm/sun4i/sun4i_layer.c       |  83 ++++-
 drivers/gpu/drm/sun4i/sun4i_layer.h       |  11 +-
 drivers/gpu/drm/sun4i/sun4i_tcon.c        |   4 +-
 drivers/gpu/drm/sun4i/sunxi_engine.h      |  93 ++++-
 14 files changed, 897 insertions(+), 23 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] 65+ messages in thread

* [PATCH v2 01/12] drm/sun4i: backend: Move line stride setup to buffer setup function
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, 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.

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
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] 65+ messages in thread

* [PATCH v2 01/12] drm/sun4i: backend: Move line stride setup to buffer setup function
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 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.

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
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] 65+ messages in thread

* [PATCH v2 01/12] drm/sun4i: backend: Move line stride setup to buffer setup function
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, 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.

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
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] 65+ messages in thread

* [PATCH v2 02/12] sun4i/drm: backend: Document the engine operations
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, thomas

Our operations were missing some documentation to explain what was expected
from them.

Let's make that clearer.

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

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;
 
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index 4cb70ae65c79..36c8388b1646 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -15,13 +15,60 @@ struct drm_device;
 
 struct sunxi_engine;
 
+/**
+ * struct sunxi_engine_ops - helper operations for sunXi engines
+ *
+ * These hooks are used by the common part of the DRM driver to
+ * implement the proper behaviour.
+ */
 struct sunxi_engine_ops {
+	/**
+	 * @apply_color_correction:
+	 *
+	 * This callback will enable the color correction in the
+	 * backend. This is useful only for the composite output.
+	 *
+	 * This function is optional.
+	 */
+	void (*apply_color_correction)(struct sunxi_engine *engine);
+
+	/**
+	 * @commit:
+	 *
+	 * This callback will trigger the hardware switch to commit
+	 * the new configuration that has been setup during the next
+	 * vblank period.
+	 *
+	 * This function is optional.
+	 */
 	void (*commit)(struct sunxi_engine *engine);
+
+	/**
+	 * @disable_color_correction:
+	 *
+	 * This callback will stop the color correction in the
+	 * backend. This is useful only for the composite output.
+	 *
+	 * This function is optional.
+	 */
+	void (*disable_color_correction)(struct sunxi_engine *engine);
+
+	/**
+	 * @layers_init:
+	 *
+	 * This callback is used to allocate, initialize and register
+	 * the layers supported by that backend.
+	 *
+	 * This function is mandatory.
+	 *
+	 * RETURNS:
+	 *
+	 * The array of struct drm_plane backing the layers, or an
+	 * error pointer on failure.
+	 */
 	struct drm_plane **(*layers_init)(struct drm_device *drm,
 					  struct sunxi_engine *engine);
 
-	void (*apply_color_correction)(struct sunxi_engine *engine);
-	void (*disable_color_correction)(struct sunxi_engine *engine);
 };
 
 /**
-- 
git-series 0.9.1

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

* [PATCH v2 02/12] sun4i/drm: backend: Document the engine operations
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: linux-arm-kernel

Our operations were missing some documentation to explain what was expected
from them.

Let's make that clearer.

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

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;
 
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index 4cb70ae65c79..36c8388b1646 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -15,13 +15,60 @@ struct drm_device;
 
 struct sunxi_engine;
 
+/**
+ * struct sunxi_engine_ops - helper operations for sunXi engines
+ *
+ * These hooks are used by the common part of the DRM driver to
+ * implement the proper behaviour.
+ */
 struct sunxi_engine_ops {
+	/**
+	 * @apply_color_correction:
+	 *
+	 * This callback will enable the color correction in the
+	 * backend. This is useful only for the composite output.
+	 *
+	 * This function is optional.
+	 */
+	void (*apply_color_correction)(struct sunxi_engine *engine);
+
+	/**
+	 * @commit:
+	 *
+	 * This callback will trigger the hardware switch to commit
+	 * the new configuration that has been setup during the next
+	 * vblank period.
+	 *
+	 * This function is optional.
+	 */
 	void (*commit)(struct sunxi_engine *engine);
+
+	/**
+	 * @disable_color_correction:
+	 *
+	 * This callback will stop the color correction in the
+	 * backend. This is useful only for the composite output.
+	 *
+	 * This function is optional.
+	 */
+	void (*disable_color_correction)(struct sunxi_engine *engine);
+
+	/**
+	 * @layers_init:
+	 *
+	 * This callback is used to allocate, initialize and register
+	 * the layers supported by that backend.
+	 *
+	 * This function is mandatory.
+	 *
+	 * RETURNS:
+	 *
+	 * The array of struct drm_plane backing the layers, or an
+	 * error pointer on failure.
+	 */
 	struct drm_plane **(*layers_init)(struct drm_device *drm,
 					  struct sunxi_engine *engine);
 
-	void (*apply_color_correction)(struct sunxi_engine *engine);
-	void (*disable_color_correction)(struct sunxi_engine *engine);
 };
 
 /**
-- 
git-series 0.9.1

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

* [PATCH v2 02/12] sun4i/drm: backend: Document the engine operations
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, thomas

Our operations were missing some documentation to explain what was expected
from them.

Let's make that clearer.

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

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;
 
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index 4cb70ae65c79..36c8388b1646 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -15,13 +15,60 @@ struct drm_device;
 
 struct sunxi_engine;
 
+/**
+ * struct sunxi_engine_ops - helper operations for sunXi engines
+ *
+ * These hooks are used by the common part of the DRM driver to
+ * implement the proper behaviour.
+ */
 struct sunxi_engine_ops {
+	/**
+	 * @apply_color_correction:
+	 *
+	 * This callback will enable the color correction in the
+	 * backend. This is useful only for the composite output.
+	 *
+	 * This function is optional.
+	 */
+	void (*apply_color_correction)(struct sunxi_engine *engine);
+
+	/**
+	 * @commit:
+	 *
+	 * This callback will trigger the hardware switch to commit
+	 * the new configuration that has been setup during the next
+	 * vblank period.
+	 *
+	 * This function is optional.
+	 */
 	void (*commit)(struct sunxi_engine *engine);
+
+	/**
+	 * @disable_color_correction:
+	 *
+	 * This callback will stop the color correction in the
+	 * backend. This is useful only for the composite output.
+	 *
+	 * This function is optional.
+	 */
+	void (*disable_color_correction)(struct sunxi_engine *engine);
+
+	/**
+	 * @layers_init:
+	 *
+	 * This callback is used to allocate, initialize and register
+	 * the layers supported by that backend.
+	 *
+	 * This function is mandatory.
+	 *
+	 * RETURNS:
+	 *
+	 * The array of struct drm_plane backing the layers, or an
+	 * error pointer on failure.
+	 */
 	struct drm_plane **(*layers_init)(struct drm_device *drm,
 					  struct sunxi_engine *engine);
 
-	void (*apply_color_correction)(struct sunxi_engine *engine);
-	void (*disable_color_correction)(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] 65+ messages in thread

* [PATCH v2 03/12] drm/sun4i: backend: Add a custom plane state
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, 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.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 7bddf12548d3..b85a9a02d166 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -25,6 +25,50 @@ 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 +96,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] 65+ messages in thread

* [PATCH v2 03/12] drm/sun4i: backend: Add a custom plane state
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 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.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 7bddf12548d3..b85a9a02d166 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -25,6 +25,50 @@ 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 +96,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] 65+ messages in thread

* [PATCH v2 03/12] drm/sun4i: backend: Add a custom plane state
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, 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.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 7bddf12548d3..b85a9a02d166 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -25,6 +25,50 @@ 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 +96,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] 65+ messages in thread

* [PATCH v2 04/12] drm/sun4i: engine: Add a custom crtc atomic_check
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, 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.

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
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 | 17 +++++++++++++++++
 2 files changed, 31 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 36c8388b1646..da2dd36dfbb6 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -33,6 +33,23 @@ struct sunxi_engine_ops {
 	void (*apply_color_correction)(struct sunxi_engine *engine);
 
 	/**
+	 * @atomic_check:
+	 *
+	 * This callback allows to validate plane-update related CRTC
+	 * constraints specific to backends. This is mirroring the
+	 * &drm_crtc_helper_funcs.atomic_check callback, so any
+	 * documentation there applies.
+	 *
+	 * This function is optional.
+	 *
+	 * RETURNS:
+	 *
+	 * 0 on success or a negative error code.
+	 */
+	int (*atomic_check)(struct sunxi_engine *engine,
+			    struct drm_crtc_state *state);
+
+	/**
 	 * @commit:
 	 *
 	 * This callback will trigger the hardware switch to commit
-- 
git-series 0.9.1

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

* [PATCH v2 04/12] drm/sun4i: engine: Add a custom crtc atomic_check
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 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.

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
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 | 17 +++++++++++++++++
 2 files changed, 31 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 36c8388b1646..da2dd36dfbb6 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -33,6 +33,23 @@ struct sunxi_engine_ops {
 	void (*apply_color_correction)(struct sunxi_engine *engine);
 
 	/**
+	 * @atomic_check:
+	 *
+	 * This callback allows to validate plane-update related CRTC
+	 * constraints specific to backends. This is mirroring the
+	 * &drm_crtc_helper_funcs.atomic_check callback, so any
+	 * documentation there applies.
+	 *
+	 * This function is optional.
+	 *
+	 * RETURNS:
+	 *
+	 * 0 on success or a negative error code.
+	 */
+	int (*atomic_check)(struct sunxi_engine *engine,
+			    struct drm_crtc_state *state);
+
+	/**
 	 * @commit:
 	 *
 	 * This callback will trigger the hardware switch to commit
-- 
git-series 0.9.1

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

* [PATCH v2 04/12] drm/sun4i: engine: Add a custom crtc atomic_check
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, 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.

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
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 | 17 +++++++++++++++++
 2 files changed, 31 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 36c8388b1646..da2dd36dfbb6 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -33,6 +33,23 @@ struct sunxi_engine_ops {
 	void (*apply_color_correction)(struct sunxi_engine *engine);
 
 	/**
+	 * @atomic_check:
+	 *
+	 * This callback allows to validate plane-update related CRTC
+	 * constraints specific to backends. This is mirroring the
+	 * &drm_crtc_helper_funcs.atomic_check callback, so any
+	 * documentation there applies.
+	 *
+	 * This function is optional.
+	 *
+	 * RETURNS:
+	 *
+	 * 0 on success or a negative error code.
+	 */
+	int (*atomic_check)(struct sunxi_engine *engine,
+			    struct drm_crtc_state *state);
+
+	/**
 	 * @commit:
 	 *
 	 * This callback will trigger the hardware switch to commit
-- 
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] 65+ messages in thread

* [PATCH v2 05/12] drm/sun4i: engine: Add a VBLANK quirk callback
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, thomas

In some cases, the display engine needs to apply some quirks during the
VBLANK event. In the Display Engine 1.0 case for example, we can only
disable the frontend once the backend has been, which is at VBLANK.

Let's introduce a callback that can be implemented by the various engines.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index e122f5b2a395..55f54b54293c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -368,6 +368,7 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 	struct sun4i_tcon *tcon = private;
 	struct drm_device *drm = tcon->drm;
 	struct sun4i_crtc *scrtc = tcon->crtc;
+	struct sunxi_engine *engine = scrtc->engine;
 	unsigned int status;
 
 	regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
@@ -385,6 +386,9 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 			   SUN4I_TCON_GINT0_VBLANK_INT(1),
 			   0);
 
+	if (engine->ops->vblank_quirk)
+		engine->ops->vblank_quirk(engine);
+
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index da2dd36dfbb6..b810c26d78bb 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -86,6 +86,18 @@ struct sunxi_engine_ops {
 	struct drm_plane **(*layers_init)(struct drm_device *drm,
 					  struct sunxi_engine *engine);
 
+	/**
+	 * @vblank_quirk:
+	 *
+	 * This callback is used to implement backend-specific
+	 * behaviour part of the VBLANK event. It is run with all the
+	 * constraints of an interrupt (can't sleep, all local
+	 * interrupts disabled) and therefore should be as fast as
+	 * possible.
+	 *
+	 * This function is optional.
+	 */
+	void (*vblank_quirk)(struct sunxi_engine *engine);
 };
 
 /**
-- 
git-series 0.9.1

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

* [PATCH v2 05/12] drm/sun4i: engine: Add a VBLANK quirk callback
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: linux-arm-kernel

In some cases, the display engine needs to apply some quirks during the
VBLANK event. In the Display Engine 1.0 case for example, we can only
disable the frontend once the backend has been, which is at VBLANK.

Let's introduce a callback that can be implemented by the various engines.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index e122f5b2a395..55f54b54293c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -368,6 +368,7 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 	struct sun4i_tcon *tcon = private;
 	struct drm_device *drm = tcon->drm;
 	struct sun4i_crtc *scrtc = tcon->crtc;
+	struct sunxi_engine *engine = scrtc->engine;
 	unsigned int status;
 
 	regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
@@ -385,6 +386,9 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 			   SUN4I_TCON_GINT0_VBLANK_INT(1),
 			   0);
 
+	if (engine->ops->vblank_quirk)
+		engine->ops->vblank_quirk(engine);
+
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index da2dd36dfbb6..b810c26d78bb 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -86,6 +86,18 @@ struct sunxi_engine_ops {
 	struct drm_plane **(*layers_init)(struct drm_device *drm,
 					  struct sunxi_engine *engine);
 
+	/**
+	 * @vblank_quirk:
+	 *
+	 * This callback is used to implement backend-specific
+	 * behaviour part of the VBLANK event. It is run with all the
+	 * constraints of an interrupt (can't sleep, all local
+	 * interrupts disabled) and therefore should be as fast as
+	 * possible.
+	 *
+	 * This function is optional.
+	 */
+	void (*vblank_quirk)(struct sunxi_engine *engine);
 };
 
 /**
-- 
git-series 0.9.1

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

* [PATCH v2 05/12] drm/sun4i: engine: Add a VBLANK quirk callback
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, thomas

In some cases, the display engine needs to apply some quirks during the
VBLANK event. In the Display Engine 1.0 case for example, we can only
disable the frontend once the backend has been, which is at VBLANK.

Let's introduce a callback that can be implemented by the various engines.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index e122f5b2a395..55f54b54293c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -368,6 +368,7 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 	struct sun4i_tcon *tcon = private;
 	struct drm_device *drm = tcon->drm;
 	struct sun4i_crtc *scrtc = tcon->crtc;
+	struct sunxi_engine *engine = scrtc->engine;
 	unsigned int status;
 
 	regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
@@ -385,6 +386,9 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 			   SUN4I_TCON_GINT0_VBLANK_INT(1),
 			   0);
 
+	if (engine->ops->vblank_quirk)
+		engine->ops->vblank_quirk(engine);
+
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index da2dd36dfbb6..b810c26d78bb 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -86,6 +86,18 @@ struct sunxi_engine_ops {
 	struct drm_plane **(*layers_init)(struct drm_device *drm,
 					  struct sunxi_engine *engine);
 
+	/**
+	 * @vblank_quirk:
+	 *
+	 * This callback is used to implement backend-specific
+	 * behaviour part of the VBLANK event. It is run with all the
+	 * constraints of an interrupt (can't sleep, all local
+	 * interrupts disabled) and therefore should be as fast as
+	 * possible.
+	 *
+	 * This function is optional.
+	 */
+	void (*vblank_quirk)(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] 65+ messages in thread

* [PATCH v2 06/12] drm/sun4i: engine: Create an atomic_begin callback
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, thomas

We have to implement some display engine specific behaviours in
atomic_begin. Let's add a function for that.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 2a565325714f..f549f2874353 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -64,6 +64,7 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 {
 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
+	struct sunxi_engine *engine = scrtc->engine;
 	unsigned long flags;
 
 	if (crtc->state->event) {
@@ -73,7 +74,10 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 		scrtc->event = crtc->state->event;
 		spin_unlock_irqrestore(&dev->event_lock, flags);
 		crtc->state->event = NULL;
-	 }
+	}
+
+	if (engine->ops->atomic_begin)
+		engine->ops->atomic_begin(engine, old_state);
 }
 
 static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index b810c26d78bb..ec4d54f596d4 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -33,6 +33,19 @@ struct sunxi_engine_ops {
 	void (*apply_color_correction)(struct sunxi_engine *engine);
 
 	/**
+	 * @atomic_begin:
+	 *
+	 * This callback allows to prepare our backend for an atomic
+	 * update. This is mirroring the
+	 * &drm_crtc_helper_funcs.atomic_begin callback, so any
+	 * documentation there applies.
+	 *
+	 * This function is optional.
+	 */
+	void (*atomic_begin)(struct sunxi_engine *engine,
+			     struct drm_crtc_state *old_state);
+
+	/**
 	 * @atomic_check:
 	 *
 	 * This callback allows to validate plane-update related CRTC
-- 
git-series 0.9.1

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

* [PATCH v2 06/12] drm/sun4i: engine: Create an atomic_begin callback
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: linux-arm-kernel

We have to implement some display engine specific behaviours in
atomic_begin. Let's add a function for that.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 2a565325714f..f549f2874353 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -64,6 +64,7 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 {
 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
+	struct sunxi_engine *engine = scrtc->engine;
 	unsigned long flags;
 
 	if (crtc->state->event) {
@@ -73,7 +74,10 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 		scrtc->event = crtc->state->event;
 		spin_unlock_irqrestore(&dev->event_lock, flags);
 		crtc->state->event = NULL;
-	 }
+	}
+
+	if (engine->ops->atomic_begin)
+		engine->ops->atomic_begin(engine, old_state);
 }
 
 static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index b810c26d78bb..ec4d54f596d4 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -33,6 +33,19 @@ struct sunxi_engine_ops {
 	void (*apply_color_correction)(struct sunxi_engine *engine);
 
 	/**
+	 * @atomic_begin:
+	 *
+	 * This callback allows to prepare our backend for an atomic
+	 * update. This is mirroring the
+	 * &drm_crtc_helper_funcs.atomic_begin callback, so any
+	 * documentation there applies.
+	 *
+	 * This function is optional.
+	 */
+	void (*atomic_begin)(struct sunxi_engine *engine,
+			     struct drm_crtc_state *old_state);
+
+	/**
 	 * @atomic_check:
 	 *
 	 * This callback allows to validate plane-update related CRTC
-- 
git-series 0.9.1

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

* [PATCH v2 06/12] drm/sun4i: engine: Create an atomic_begin callback
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, thomas

We have to implement some display engine specific behaviours in
atomic_begin. Let's add a function for that.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 2a565325714f..f549f2874353 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -64,6 +64,7 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 {
 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
+	struct sunxi_engine *engine = scrtc->engine;
 	unsigned long flags;
 
 	if (crtc->state->event) {
@@ -73,7 +74,10 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 		scrtc->event = crtc->state->event;
 		spin_unlock_irqrestore(&dev->event_lock, flags);
 		crtc->state->event = NULL;
-	 }
+	}
+
+	if (engine->ops->atomic_begin)
+		engine->ops->atomic_begin(engine, old_state);
 }
 
 static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index b810c26d78bb..ec4d54f596d4 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -33,6 +33,19 @@ struct sunxi_engine_ops {
 	void (*apply_color_correction)(struct sunxi_engine *engine);
 
 	/**
+	 * @atomic_begin:
+	 *
+	 * This callback allows to prepare our backend for an atomic
+	 * update. This is mirroring the
+	 * &drm_crtc_helper_funcs.atomic_begin callback, so any
+	 * documentation there applies.
+	 *
+	 * This function is optional.
+	 */
+	void (*atomic_begin)(struct sunxi_engine *engine,
+			     struct drm_crtc_state *old_state);
+
+	/**
 	 * @atomic_check:
 	 *
 	 * This callback allows to validate plane-update related CRTC
-- 
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] 65+ messages in thread

* [PATCH v2 07/12] drm/sun4i: Add a driver for the display frontend
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, 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_drv.c      |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c | 392 ++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h |  96 ++++++-
 5 files changed, 503 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_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..fb3e96ab57f7
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ */
+#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/pm_runtime.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)
+{
+	return pm_runtime_get_sync(frontend->dev);
+}
+EXPORT_SYMBOL(sun4i_frontend_init);
+
+void sun4i_frontend_exit(struct sun4i_frontend *frontend)
+{
+	pm_runtime_put(frontend->dev);
+}
+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);
+}
+EXPORT_SYMBOL(sun4i_frontend_update_buffer);
+
+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,
+		     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,
+		     SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1));
+
+	return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_update_formats);
+
+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->dev = dev;
+	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);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void sun4i_frontend_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+	list_del(&frontend->list);
+	pm_runtime_force_suspend(dev);
+}
+
+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 int sun4i_frontend_runtime_resume(struct device *dev)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+	int ret;
+
+	ret = reset_control_deassert(frontend->reset);
+	if (ret) {
+		dev_err(dev, "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);
+
+	return 0;
+}
+
+static int sun4i_frontend_runtime_suspend(struct device *dev)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(frontend->ram_clk);
+	clk_disable_unprepare(frontend->mod_clk);
+	clk_disable_unprepare(frontend->bus_clk);
+
+	reset_control_assert(frontend->reset);
+
+	return 0;
+}
+
+static const struct dev_pm_ops sun4i_frontend_pm_ops = {
+	.runtime_resume		= sun4i_frontend_runtime_resume,
+	.runtime_suspend	= sun4i_frontend_runtime_suspend,
+};
+
+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,
+		.pm		= &sun4i_frontend_pm_ops,
+	},
+};
+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..5adc2c7266bc
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ */
+
+#ifndef _SUN4I_FRONTEND_H_
+#define _SUN4I_FRONTEND_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;
+	struct device		*dev;
+	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] 65+ messages in thread

* [PATCH v2 07/12] drm/sun4i: Add a driver for the display frontend
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 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_drv.c      |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c | 392 ++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h |  96 ++++++-
 5 files changed, 503 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_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..fb3e96ab57f7
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ */
+#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/pm_runtime.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)
+{
+	return pm_runtime_get_sync(frontend->dev);
+}
+EXPORT_SYMBOL(sun4i_frontend_init);
+
+void sun4i_frontend_exit(struct sun4i_frontend *frontend)
+{
+	pm_runtime_put(frontend->dev);
+}
+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);
+}
+EXPORT_SYMBOL(sun4i_frontend_update_buffer);
+
+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,
+		     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,
+		     SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1));
+
+	return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_update_formats);
+
+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->dev = dev;
+	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);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void sun4i_frontend_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+	list_del(&frontend->list);
+	pm_runtime_force_suspend(dev);
+}
+
+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 int sun4i_frontend_runtime_resume(struct device *dev)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+	int ret;
+
+	ret = reset_control_deassert(frontend->reset);
+	if (ret) {
+		dev_err(dev, "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);
+
+	return 0;
+}
+
+static int sun4i_frontend_runtime_suspend(struct device *dev)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(frontend->ram_clk);
+	clk_disable_unprepare(frontend->mod_clk);
+	clk_disable_unprepare(frontend->bus_clk);
+
+	reset_control_assert(frontend->reset);
+
+	return 0;
+}
+
+static const struct dev_pm_ops sun4i_frontend_pm_ops = {
+	.runtime_resume		= sun4i_frontend_runtime_resume,
+	.runtime_suspend	= sun4i_frontend_runtime_suspend,
+};
+
+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,
+		.pm		= &sun4i_frontend_pm_ops,
+	},
+};
+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..5adc2c7266bc
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ */
+
+#ifndef _SUN4I_FRONTEND_H_
+#define _SUN4I_FRONTEND_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;
+	struct device		*dev;
+	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] 65+ messages in thread

* [PATCH v2 07/12] drm/sun4i: Add a driver for the display frontend
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, 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_drv.c      |  16 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
 drivers/gpu/drm/sun4i/sun4i_frontend.c | 392 ++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_frontend.h |  96 ++++++-
 5 files changed, 503 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_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..fb3e96ab57f7
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ */
+#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/pm_runtime.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)
+{
+	return pm_runtime_get_sync(frontend->dev);
+}
+EXPORT_SYMBOL(sun4i_frontend_init);
+
+void sun4i_frontend_exit(struct sun4i_frontend *frontend)
+{
+	pm_runtime_put(frontend->dev);
+}
+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);
+}
+EXPORT_SYMBOL(sun4i_frontend_update_buffer);
+
+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,
+		     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,
+		     SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1));
+
+	return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_update_formats);
+
+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->dev = dev;
+	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);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void sun4i_frontend_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+	list_del(&frontend->list);
+	pm_runtime_force_suspend(dev);
+}
+
+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 int sun4i_frontend_runtime_resume(struct device *dev)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+	int ret;
+
+	ret = reset_control_deassert(frontend->reset);
+	if (ret) {
+		dev_err(dev, "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);
+
+	return 0;
+}
+
+static int sun4i_frontend_runtime_suspend(struct device *dev)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(frontend->ram_clk);
+	clk_disable_unprepare(frontend->mod_clk);
+	clk_disable_unprepare(frontend->bus_clk);
+
+	reset_control_assert(frontend->reset);
+
+	return 0;
+}
+
+static const struct dev_pm_ops sun4i_frontend_pm_ops = {
+	.runtime_resume		= sun4i_frontend_runtime_resume,
+	.runtime_suspend	= sun4i_frontend_runtime_suspend,
+};
+
+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,
+		.pm		= &sun4i_frontend_pm_ops,
+	},
+};
+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..5adc2c7266bc
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ */
+
+#ifndef _SUN4I_FRONTEND_H_
+#define _SUN4I_FRONTEND_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;
+	struct device		*dev;
+	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] 65+ messages in thread

* [PATCH v2 08/12] drm/sun4i: backend: Wire in the frontend
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, 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 | 90 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h |  8 ++-
 drivers/gpu/drm/sun4i/sun4i_crtc.c    |  1 +-
 drivers/gpu/drm/sun4i/sun4i_layer.c   | 33 +++++++++-
 drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
 5 files changed, 130 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index f971d3fb5ee4..29e1ca7e01fe 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)
 {
@@ -246,6 +271,36 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	return 0;
 }
 
+static void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
+{
+	struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
+	struct sun4i_frontend *frontend = backend->frontend;
+
+	if (!frontend)
+		return;
+
+	/*
+	 * In a teardown scenario with the frontend involved, we have
+	 * to keep the frontend enabled until the next vblank, and
+	 * only then disable it.
+	 *
+	 * This is due to the fact that the backend will not take into
+	 * account the new configuration (with the plane that used to
+	 * be fed by the frontend now disabled) until we write to the
+	 * commit bit and the hardware fetches the new configuration
+	 * during the next vblank.
+	 *
+	 * So we keep the frontend around in order to prevent any
+	 * visual artifacts.
+	 */
+	spin_lock(&backend->frontend_lock);
+	if (backend->frontend_teardown) {
+		sun4i_frontend_exit(frontend);
+		backend->frontend_teardown = false;
+	}
+	spin_unlock(&backend->frontend_lock);
+};
+
 static int sun4i_backend_init_sat(struct device *dev) {
 	struct sun4i_backend *backend = dev_get_drvdata(dev);
 	int ret;
@@ -330,11 +385,40 @@ 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,
 	.apply_color_correction		= sun4i_backend_apply_color_correction,
 	.disable_color_correction	= sun4i_backend_disable_color_correction,
+	.vblank_quirk			= sun4i_backend_vblank_quirk,
 };
 
 static struct regmap_config sun4i_backend_regmap_config = {
@@ -360,6 +444,7 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 	if (!backend)
 		return -ENOMEM;
 	dev_set_drvdata(dev, backend);
+	spin_lock_init(&backend->frontend_lock);
 
 	backend->engine.node = dev->of_node;
 	backend->engine.ops = &sun4i_backend_engine_ops;
@@ -367,6 +452,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_warn(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..350a2dbde31a 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)
@@ -145,6 +146,7 @@
 
 struct sun4i_backend {
 	struct sunxi_engine	engine;
+	struct sun4i_frontend	*frontend;
 
 	struct reset_control	*reset;
 
@@ -154,6 +156,10 @@ struct sun4i_backend {
 
 	struct clk		*sat_clk;
 	struct reset_control	*sat_reset;
+
+	/* Protects against races in the frontend teardown */
+	spinlock_t		frontend_lock;
+	bool			frontend_teardown;
 };
 
 static inline struct sun4i_backend *
@@ -170,5 +176,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_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index f549f2874353..3b2d11b675e8 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -25,6 +25,7 @@
 
 #include <video/videomode.h>
 
+#include "sun4i_backend.h"
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
 #include "sunxi_engine.h"
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index b85a9a02d166..4652b25be0d2 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"
 
@@ -48,6 +49,7 @@ static void sun4i_backend_layer_reset(struct drm_plane *plane)
 static struct drm_plane_state *
 sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
 {
+	struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state);
 	struct sun4i_layer_state *copy;
 
 	copy = kzalloc(sizeof(*copy), GFP_KERNEL);
@@ -55,6 +57,7 @@ sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
 		return NULL;
 
 	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
+	copy->uses_frontend = orig->uses_frontend;
 
 	return &copy->state;
 }
@@ -72,21 +75,45 @@ 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;
 
 	sun4i_backend_layer_enable(backend, layer->id, false);
+
+	if (layer_state->uses_frontend) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&backend->frontend_lock, flags);
+		backend->frontend_teardown = true;
+		spin_unlock_irqrestore(&backend->frontend_lock, flags);
+	}
 }
 
 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] 65+ messages in thread

* [PATCH v2 08/12] drm/sun4i: backend: Wire in the frontend
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 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 | 90 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h |  8 ++-
 drivers/gpu/drm/sun4i/sun4i_crtc.c    |  1 +-
 drivers/gpu/drm/sun4i/sun4i_layer.c   | 33 +++++++++-
 drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
 5 files changed, 130 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index f971d3fb5ee4..29e1ca7e01fe 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)
 {
@@ -246,6 +271,36 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	return 0;
 }
 
+static void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
+{
+	struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
+	struct sun4i_frontend *frontend = backend->frontend;
+
+	if (!frontend)
+		return;
+
+	/*
+	 * In a teardown scenario with the frontend involved, we have
+	 * to keep the frontend enabled until the next vblank, and
+	 * only then disable it.
+	 *
+	 * This is due to the fact that the backend will not take into
+	 * account the new configuration (with the plane that used to
+	 * be fed by the frontend now disabled) until we write to the
+	 * commit bit and the hardware fetches the new configuration
+	 * during the next vblank.
+	 *
+	 * So we keep the frontend around in order to prevent any
+	 * visual artifacts.
+	 */
+	spin_lock(&backend->frontend_lock);
+	if (backend->frontend_teardown) {
+		sun4i_frontend_exit(frontend);
+		backend->frontend_teardown = false;
+	}
+	spin_unlock(&backend->frontend_lock);
+};
+
 static int sun4i_backend_init_sat(struct device *dev) {
 	struct sun4i_backend *backend = dev_get_drvdata(dev);
 	int ret;
@@ -330,11 +385,40 @@ 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,
 	.apply_color_correction		= sun4i_backend_apply_color_correction,
 	.disable_color_correction	= sun4i_backend_disable_color_correction,
+	.vblank_quirk			= sun4i_backend_vblank_quirk,
 };
 
 static struct regmap_config sun4i_backend_regmap_config = {
@@ -360,6 +444,7 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 	if (!backend)
 		return -ENOMEM;
 	dev_set_drvdata(dev, backend);
+	spin_lock_init(&backend->frontend_lock);
 
 	backend->engine.node = dev->of_node;
 	backend->engine.ops = &sun4i_backend_engine_ops;
@@ -367,6 +452,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_warn(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..350a2dbde31a 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)
@@ -145,6 +146,7 @@
 
 struct sun4i_backend {
 	struct sunxi_engine	engine;
+	struct sun4i_frontend	*frontend;
 
 	struct reset_control	*reset;
 
@@ -154,6 +156,10 @@ struct sun4i_backend {
 
 	struct clk		*sat_clk;
 	struct reset_control	*sat_reset;
+
+	/* Protects against races in the frontend teardown */
+	spinlock_t		frontend_lock;
+	bool			frontend_teardown;
 };
 
 static inline struct sun4i_backend *
@@ -170,5 +176,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_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index f549f2874353..3b2d11b675e8 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -25,6 +25,7 @@
 
 #include <video/videomode.h>
 
+#include "sun4i_backend.h"
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
 #include "sunxi_engine.h"
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index b85a9a02d166..4652b25be0d2 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"
 
@@ -48,6 +49,7 @@ static void sun4i_backend_layer_reset(struct drm_plane *plane)
 static struct drm_plane_state *
 sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
 {
+	struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state);
 	struct sun4i_layer_state *copy;
 
 	copy = kzalloc(sizeof(*copy), GFP_KERNEL);
@@ -55,6 +57,7 @@ sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
 		return NULL;
 
 	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
+	copy->uses_frontend = orig->uses_frontend;
 
 	return &copy->state;
 }
@@ -72,21 +75,45 @@ 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;
 
 	sun4i_backend_layer_enable(backend, layer->id, false);
+
+	if (layer_state->uses_frontend) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&backend->frontend_lock, flags);
+		backend->frontend_teardown = true;
+		spin_unlock_irqrestore(&backend->frontend_lock, flags);
+	}
 }
 
 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] 65+ messages in thread

* [PATCH v2 08/12] drm/sun4i: backend: Wire in the frontend
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, 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 | 90 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h |  8 ++-
 drivers/gpu/drm/sun4i/sun4i_crtc.c    |  1 +-
 drivers/gpu/drm/sun4i/sun4i_layer.c   | 33 +++++++++-
 drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
 5 files changed, 130 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index f971d3fb5ee4..29e1ca7e01fe 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)
 {
@@ -246,6 +271,36 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	return 0;
 }
 
+static void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
+{
+	struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
+	struct sun4i_frontend *frontend = backend->frontend;
+
+	if (!frontend)
+		return;
+
+	/*
+	 * In a teardown scenario with the frontend involved, we have
+	 * to keep the frontend enabled until the next vblank, and
+	 * only then disable it.
+	 *
+	 * This is due to the fact that the backend will not take into
+	 * account the new configuration (with the plane that used to
+	 * be fed by the frontend now disabled) until we write to the
+	 * commit bit and the hardware fetches the new configuration
+	 * during the next vblank.
+	 *
+	 * So we keep the frontend around in order to prevent any
+	 * visual artifacts.
+	 */
+	spin_lock(&backend->frontend_lock);
+	if (backend->frontend_teardown) {
+		sun4i_frontend_exit(frontend);
+		backend->frontend_teardown = false;
+	}
+	spin_unlock(&backend->frontend_lock);
+};
+
 static int sun4i_backend_init_sat(struct device *dev) {
 	struct sun4i_backend *backend = dev_get_drvdata(dev);
 	int ret;
@@ -330,11 +385,40 @@ 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,
 	.apply_color_correction		= sun4i_backend_apply_color_correction,
 	.disable_color_correction	= sun4i_backend_disable_color_correction,
+	.vblank_quirk			= sun4i_backend_vblank_quirk,
 };
 
 static struct regmap_config sun4i_backend_regmap_config = {
@@ -360,6 +444,7 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 	if (!backend)
 		return -ENOMEM;
 	dev_set_drvdata(dev, backend);
+	spin_lock_init(&backend->frontend_lock);
 
 	backend->engine.node = dev->of_node;
 	backend->engine.ops = &sun4i_backend_engine_ops;
@@ -367,6 +452,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_warn(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..350a2dbde31a 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)
@@ -145,6 +146,7 @@
 
 struct sun4i_backend {
 	struct sunxi_engine	engine;
+	struct sun4i_frontend	*frontend;
 
 	struct reset_control	*reset;
 
@@ -154,6 +156,10 @@ struct sun4i_backend {
 
 	struct clk		*sat_clk;
 	struct reset_control	*sat_reset;
+
+	/* Protects against races in the frontend teardown */
+	spinlock_t		frontend_lock;
+	bool			frontend_teardown;
 };
 
 static inline struct sun4i_backend *
@@ -170,5 +176,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_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index f549f2874353..3b2d11b675e8 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -25,6 +25,7 @@
 
 #include <video/videomode.h>
 
+#include "sun4i_backend.h"
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
 #include "sunxi_engine.h"
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index b85a9a02d166..4652b25be0d2 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"
 
@@ -48,6 +49,7 @@ static void sun4i_backend_layer_reset(struct drm_plane *plane)
 static struct drm_plane_state *
 sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
 {
+	struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state);
 	struct sun4i_layer_state *copy;
 
 	copy = kzalloc(sizeof(*copy), GFP_KERNEL);
@@ -55,6 +57,7 @@ sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
 		return NULL;
 
 	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
+	copy->uses_frontend = orig->uses_frontend;
 
 	return &copy->state;
 }
@@ -72,21 +75,45 @@ 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;
 
 	sun4i_backend_layer_enable(backend, layer->id, false);
+
+	if (layer_state->uses_frontend) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&backend->frontend_lock, flags);
+		backend->frontend_teardown = true;
+		spin_unlock_irqrestore(&backend->frontend_lock, flags);
+	}
 }
 
 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 09/12] drm/sun4i: backend: Add a custom atomic_check for the frontend
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, 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.

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
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 29e1ca7e01fe..4642f933765e 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 void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
 {
 	struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
@@ -414,6 +478,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 350a2dbde31a..b5edf2d50a24 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] 65+ messages in thread

* [PATCH v2 09/12] drm/sun4i: backend: Add a custom atomic_check for the frontend
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 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.

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
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 29e1ca7e01fe..4642f933765e 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 void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
 {
 	struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
@@ -414,6 +478,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 350a2dbde31a..b5edf2d50a24 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] 65+ messages in thread

* [PATCH v2 09/12] drm/sun4i: backend: Add a custom atomic_check for the frontend
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, 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.

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
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 29e1ca7e01fe..4642f933765e 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 void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
 {
 	struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
@@ -414,6 +478,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 350a2dbde31a..b5edf2d50a24 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] 65+ messages in thread

* [PATCH v2 10/12] drm/sun4i: backend: Use runtime_pm variant of atomic_commit_tail
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, thomas

During a hardware commit, the commit bit in the backend will only be
cleared if the TCON is enabled. Use the runtime_pm variant of the
atomic_commit_tail hook that makes sure that the CRTC, our TCON, is enabled
when we perform an atomic_commit.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
index 2992f0a6b349..a01a5b7d46e6 100644
--- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
@@ -10,6 +10,7 @@
  * the License, or (at your option) any later version.
  */
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -32,6 +33,10 @@ static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
 	.fb_create		= drm_gem_fb_create,
 };
 
+static struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = {
+	.atomic_commit_tail	= drm_atomic_helper_commit_tail_rpm,
+};
+
 struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm)
 {
 	drm_mode_config_reset(drm);
@@ -40,6 +45,7 @@ struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm)
 	drm->mode_config.max_height = 8192;
 
 	drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
+	drm->mode_config.helper_private = &sun4i_de_mode_config_helpers;
 
 	return drm_fbdev_cma_init(drm, 32, drm->mode_config.num_connector);
 }
-- 
git-series 0.9.1

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

* [PATCH v2 10/12] drm/sun4i: backend: Use runtime_pm variant of atomic_commit_tail
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: linux-arm-kernel

During a hardware commit, the commit bit in the backend will only be
cleared if the TCON is enabled. Use the runtime_pm variant of the
atomic_commit_tail hook that makes sure that the CRTC, our TCON, is enabled
when we perform an atomic_commit.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
index 2992f0a6b349..a01a5b7d46e6 100644
--- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
@@ -10,6 +10,7 @@
  * the License, or (at your option) any later version.
  */
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -32,6 +33,10 @@ static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
 	.fb_create		= drm_gem_fb_create,
 };
 
+static struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = {
+	.atomic_commit_tail	= drm_atomic_helper_commit_tail_rpm,
+};
+
 struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm)
 {
 	drm_mode_config_reset(drm);
@@ -40,6 +45,7 @@ struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm)
 	drm->mode_config.max_height = 8192;
 
 	drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
+	drm->mode_config.helper_private = &sun4i_de_mode_config_helpers;
 
 	return drm_fbdev_cma_init(drm, 32, drm->mode_config.num_connector);
 }
-- 
git-series 0.9.1

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

* [PATCH v2 10/12] drm/sun4i: backend: Use runtime_pm variant of atomic_commit_tail
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, thomas

During a hardware commit, the commit bit in the backend will only be
cleared if the TCON is enabled. Use the runtime_pm variant of the
atomic_commit_tail hook that makes sure that the CRTC, our TCON, is enabled
when we perform an atomic_commit.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
index 2992f0a6b349..a01a5b7d46e6 100644
--- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
@@ -10,6 +10,7 @@
  * the License, or (at your option) any later version.
  */
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -32,6 +33,10 @@ static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
 	.fb_create		= drm_gem_fb_create,
 };
 
+static struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = {
+	.atomic_commit_tail	= drm_atomic_helper_commit_tail_rpm,
+};
+
 struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm)
 {
 	drm_mode_config_reset(drm);
@@ -40,6 +45,7 @@ struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm)
 	drm->mode_config.max_height = 8192;
 
 	drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
+	drm->mode_config.helper_private = &sun4i_de_mode_config_helpers;
 
 	return drm_fbdev_cma_init(drm, 32, drm->mode_config.num_connector);
 }
-- 
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] 65+ messages in thread

* [PATCH v2 11/12] drm/sun4i: backend: Make sure we don't have a commit pending
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, thomas

If we try to read the backend registers while it fetches the new values, we
end up with the value of some random register instead of the one we asked
for.

In order to prevent that, let's make sure that the very first thing we do
during our atomic modesetting is to let the commit bit come to a rest.

We don't have to worry about anything else since the only time we will
trigger a new transaction is during the atomic_commit which comes much
later.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 4642f933765e..a18c86a15748 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -297,6 +297,17 @@ static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
 	return sun4i_backend_plane_uses_scaler(state);
 }
 
+static void sun4i_backend_atomic_begin(struct sunxi_engine *engine,
+				       struct drm_crtc_state *old_state)
+{
+	u32 val;
+
+	WARN_ON(regmap_read_poll_timeout(engine->regs,
+					 SUN4I_BACKEND_REGBUFFCTL_REG,
+					 val, !(val & SUN4I_BACKEND_REGBUFFCTL_LOADCTL),
+					 100, 50000));
+}
+
 static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
 				      struct drm_crtc_state *crtc_state)
 {
@@ -478,6 +489,7 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
 }
 
 static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
+	.atomic_begin			= sun4i_backend_atomic_begin,
 	.atomic_check			= sun4i_backend_atomic_check,
 	.commit				= sun4i_backend_commit,
 	.layers_init			= sun4i_layers_init,
-- 
git-series 0.9.1

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

* [PATCH v2 11/12] drm/sun4i: backend: Make sure we don't have a commit pending
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: linux-arm-kernel

If we try to read the backend registers while it fetches the new values, we
end up with the value of some random register instead of the one we asked
for.

In order to prevent that, let's make sure that the very first thing we do
during our atomic modesetting is to let the commit bit come to a rest.

We don't have to worry about anything else since the only time we will
trigger a new transaction is during the atomic_commit which comes much
later.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 4642f933765e..a18c86a15748 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -297,6 +297,17 @@ static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
 	return sun4i_backend_plane_uses_scaler(state);
 }
 
+static void sun4i_backend_atomic_begin(struct sunxi_engine *engine,
+				       struct drm_crtc_state *old_state)
+{
+	u32 val;
+
+	WARN_ON(regmap_read_poll_timeout(engine->regs,
+					 SUN4I_BACKEND_REGBUFFCTL_REG,
+					 val, !(val & SUN4I_BACKEND_REGBUFFCTL_LOADCTL),
+					 100, 50000));
+}
+
 static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
 				      struct drm_crtc_state *crtc_state)
 {
@@ -478,6 +489,7 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
 }
 
 static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
+	.atomic_begin			= sun4i_backend_atomic_begin,
 	.atomic_check			= sun4i_backend_atomic_check,
 	.commit				= sun4i_backend_commit,
 	.layers_init			= sun4i_layers_init,
-- 
git-series 0.9.1

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

* [PATCH v2 11/12] drm/sun4i: backend: Make sure we don't have a commit pending
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, thomas

If we try to read the backend registers while it fetches the new values, we
end up with the value of some random register instead of the one we asked
for.

In order to prevent that, let's make sure that the very first thing we do
during our atomic modesetting is to let the commit bit come to a rest.

We don't have to worry about anything else since the only time we will
trigger a new transaction is during the atomic_commit which comes much
later.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 4642f933765e..a18c86a15748 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -297,6 +297,17 @@ static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
 	return sun4i_backend_plane_uses_scaler(state);
 }
 
+static void sun4i_backend_atomic_begin(struct sunxi_engine *engine,
+				       struct drm_crtc_state *old_state)
+{
+	u32 val;
+
+	WARN_ON(regmap_read_poll_timeout(engine->regs,
+					 SUN4I_BACKEND_REGBUFFCTL_REG,
+					 val, !(val & SUN4I_BACKEND_REGBUFFCTL_LOADCTL),
+					 100, 50000));
+}
+
 static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
 				      struct drm_crtc_state *crtc_state)
 {
@@ -478,6 +489,7 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
 }
 
 static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
+	.atomic_begin			= sun4i_backend_atomic_begin,
 	.atomic_check			= sun4i_backend_atomic_check,
 	.commit				= sun4i_backend_commit,
 	.layers_init			= sun4i_layers_init,
-- 
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] 65+ messages in thread

* [PATCH v2 12/12] ARM: dts: sun8i: a33 Enable our display frontend
  2017-12-18 14:57 ` Maxime Ripard
  (?)
@ 2017-12-18 14:57   ` Maxime Ripard
  -1 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: dri-devel, linux-kernel, linux-arm-kernel, Thomas Petazzoni,
	narmstrong, 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] 65+ messages in thread

* [PATCH v2 12/12] ARM: dts: sun8i: a33 Enable our display frontend
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 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] 65+ messages in thread

* [PATCH v2 12/12] ARM: dts: sun8i: a33 Enable our display frontend
@ 2017-12-18 14:57   ` Maxime Ripard
  0 siblings, 0 replies; 65+ messages in thread
From: Maxime Ripard @ 2017-12-18 14:57 UTC (permalink / raw)
  To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
  Cc: Thomas Petazzoni, narmstrong, linux-kernel, dri-devel,
	linux-arm-kernel, 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 01/12] drm/sun4i: backend: Move line stride setup to buffer setup function
  2017-12-18 14:57   ` Maxime Ripard
  (?)
  (?)
@ 2017-12-19  5:04   ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2017-12-19  5:04 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, Chen-Yu Tsai, dri-devel,
	linux-kernel, linux-arm-kernel, Thomas Petazzoni, Neil Armstrong,
	thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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.
>
> Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

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

* Re: [PATCH v2 02/12] sun4i/drm: backend: Document the engine operations
  2017-12-18 14:57   ` Maxime Ripard
@ 2017-12-19  5:06     ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2017-12-19  5:06 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, Chen-Yu Tsai, dri-devel,
	linux-kernel, linux-arm-kernel, Thomas Petazzoni, Neil Armstrong,
	thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Our operations were missing some documentation to explain what was expected
> from them.
>
> Let's make that clearer.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c |  2 +-
>  drivers/gpu/drm/sun4i/sunxi_engine.h  | 51 ++++++++++++++++++++++++++--
>  2 files changed, 50 insertions(+), 3 deletions(-)
>
> 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;

Stray hunk?

>
> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
> index 4cb70ae65c79..36c8388b1646 100644
> --- a/drivers/gpu/drm/sun4i/sunxi_engine.h
> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
> @@ -15,13 +15,60 @@ struct drm_device;
>
>  struct sunxi_engine;
>
> +/**
> + * struct sunxi_engine_ops - helper operations for sunXi engines
> + *
> + * These hooks are used by the common part of the DRM driver to
> + * implement the proper behaviour.
> + */
>  struct sunxi_engine_ops {
> +       /**
> +        * @apply_color_correction:
> +        *
> +        * This callback will enable the color correction in the
> +        * backend. This is useful only for the composite output.
> +        *
> +        * This function is optional.
> +        */
> +       void (*apply_color_correction)(struct sunxi_engine *engine);
> +
> +       /**
> +        * @commit:
> +        *
> +        * This callback will trigger the hardware switch to commit
> +        * the new configuration that has been setup during the next
> +        * vblank period.
> +        *
> +        * This function is optional.
> +        */
>         void (*commit)(struct sunxi_engine *engine);
> +
> +       /**
> +        * @disable_color_correction:
> +        *
> +        * This callback will stop the color correction in the
> +        * backend. This is useful only for the composite output.
> +        *
> +        * This function is optional.
> +        */
> +       void (*disable_color_correction)(struct sunxi_engine *engine);
> +
> +       /**
> +        * @layers_init:
> +        *
> +        * This callback is used to allocate, initialize and register
> +        * the layers supported by that backend.
> +        *
> +        * This function is mandatory.
> +        *
> +        * RETURNS:
> +        *
> +        * The array of struct drm_plane backing the layers, or an
> +        * error pointer on failure.
> +        */
>         struct drm_plane **(*layers_init)(struct drm_device *drm,
>                                           struct sunxi_engine *engine);
>
> -       void (*apply_color_correction)(struct sunxi_engine *engine);
> -       void (*disable_color_correction)(struct sunxi_engine *engine);

I think keeping the grouping would make more sense, i.e. have the
enable/disable ops placed together.

Otherwise,
Reviewed-by: Chen-Yu Tsai <wens@csie.org>

>  };
>
>  /**
> --
> git-series 0.9.1

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

* Re: [PATCH v2 02/12] sun4i/drm: backend: Document the engine operations
@ 2017-12-19  5:06     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2017-12-19  5:06 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Thomas Petazzoni, Neil Armstrong, David Airlie, linux-kernel,
	dri-devel, Chen-Yu Tsai, Daniel Vetter, linux-arm-kernel, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Our operations were missing some documentation to explain what was expected
> from them.
>
> Let's make that clearer.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c |  2 +-
>  drivers/gpu/drm/sun4i/sunxi_engine.h  | 51 ++++++++++++++++++++++++++--
>  2 files changed, 50 insertions(+), 3 deletions(-)
>
> 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;

Stray hunk?

>
> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
> index 4cb70ae65c79..36c8388b1646 100644
> --- a/drivers/gpu/drm/sun4i/sunxi_engine.h
> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
> @@ -15,13 +15,60 @@ struct drm_device;
>
>  struct sunxi_engine;
>
> +/**
> + * struct sunxi_engine_ops - helper operations for sunXi engines
> + *
> + * These hooks are used by the common part of the DRM driver to
> + * implement the proper behaviour.
> + */
>  struct sunxi_engine_ops {
> +       /**
> +        * @apply_color_correction:
> +        *
> +        * This callback will enable the color correction in the
> +        * backend. This is useful only for the composite output.
> +        *
> +        * This function is optional.
> +        */
> +       void (*apply_color_correction)(struct sunxi_engine *engine);
> +
> +       /**
> +        * @commit:
> +        *
> +        * This callback will trigger the hardware switch to commit
> +        * the new configuration that has been setup during the next
> +        * vblank period.
> +        *
> +        * This function is optional.
> +        */
>         void (*commit)(struct sunxi_engine *engine);
> +
> +       /**
> +        * @disable_color_correction:
> +        *
> +        * This callback will stop the color correction in the
> +        * backend. This is useful only for the composite output.
> +        *
> +        * This function is optional.
> +        */
> +       void (*disable_color_correction)(struct sunxi_engine *engine);
> +
> +       /**
> +        * @layers_init:
> +        *
> +        * This callback is used to allocate, initialize and register
> +        * the layers supported by that backend.
> +        *
> +        * This function is mandatory.
> +        *
> +        * RETURNS:
> +        *
> +        * The array of struct drm_plane backing the layers, or an
> +        * error pointer on failure.
> +        */
>         struct drm_plane **(*layers_init)(struct drm_device *drm,
>                                           struct sunxi_engine *engine);
>
> -       void (*apply_color_correction)(struct sunxi_engine *engine);
> -       void (*disable_color_correction)(struct sunxi_engine *engine);

I think keeping the grouping would make more sense, i.e. have the
enable/disable ops placed together.

Otherwise,
Reviewed-by: Chen-Yu Tsai <wens@csie.org>

>  };
>
>  /**
> --
> 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] 65+ messages in thread

* Re: [PATCH v2 03/12] drm/sun4i: backend: Add a custom plane state
  2017-12-18 14:57   ` Maxime Ripard
@ 2017-12-19  5:07     ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2017-12-19  5:07 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, Chen-Yu Tsai, dri-devel,
	linux-kernel, linux-arm-kernel, Thomas Petazzoni, Neil Armstrong,
	thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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.
>
> Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

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

* Re: [PATCH v2 03/12] drm/sun4i: backend: Add a custom plane state
@ 2017-12-19  5:07     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2017-12-19  5:07 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Thomas Petazzoni, Neil Armstrong, David Airlie, linux-kernel,
	dri-devel, Chen-Yu Tsai, Daniel Vetter, linux-arm-kernel, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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.
>
> Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 04/12] drm/sun4i: engine: Add a custom crtc atomic_check
  2017-12-18 14:57   ` Maxime Ripard
@ 2017-12-19  5:08     ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2017-12-19  5:08 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, Chen-Yu Tsai, dri-devel,
	linux-kernel, linux-arm-kernel, Thomas Petazzoni, Neil Armstrong,
	thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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.
>
> Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

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

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

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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.
>
> Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 05/12] drm/sun4i: engine: Add a VBLANK quirk callback
  2017-12-18 14:57   ` Maxime Ripard
@ 2017-12-19  5:09     ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2017-12-19  5:09 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, Chen-Yu Tsai, dri-devel,
	linux-kernel, linux-arm-kernel, Thomas Petazzoni, Neil Armstrong,
	thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> In some cases, the display engine needs to apply some quirks during the
> VBLANK event. In the Display Engine 1.0 case for example, we can only
> disable the frontend once the backend has been, which is at VBLANK.
>
> Let's introduce a callback that can be implemented by the various engines.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_tcon.c   |  4 ++++
>  drivers/gpu/drm/sun4i/sunxi_engine.h | 12 ++++++++++++
>  2 files changed, 16 insertions(+)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index e122f5b2a395..55f54b54293c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -368,6 +368,7 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
>         struct sun4i_tcon *tcon = private;
>         struct drm_device *drm = tcon->drm;
>         struct sun4i_crtc *scrtc = tcon->crtc;
> +       struct sunxi_engine *engine = scrtc->engine;
>         unsigned int status;
>
>         regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
> @@ -385,6 +386,9 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
>                            SUN4I_TCON_GINT0_VBLANK_INT(1),
>                            0);
>
> +       if (engine->ops->vblank_quirk)
> +               engine->ops->vblank_quirk(engine);
> +
>         return IRQ_HANDLED;
>  }
>
> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
> index da2dd36dfbb6..b810c26d78bb 100644
> --- a/drivers/gpu/drm/sun4i/sunxi_engine.h
> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
> @@ -86,6 +86,18 @@ struct sunxi_engine_ops {
>         struct drm_plane **(*layers_init)(struct drm_device *drm,
>                                           struct sunxi_engine *engine);
>
> +       /**
> +        * @vblank_quirk:
> +        *
> +        * This callback is used to implement backend-specific

                                                ^ engine

Otherwise,

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

> +        * behaviour part of the VBLANK event. It is run with all the
> +        * constraints of an interrupt (can't sleep, all local
> +        * interrupts disabled) and therefore should be as fast as
> +        * possible.
> +        *
> +        * This function is optional.
> +        */
> +       void (*vblank_quirk)(struct sunxi_engine *engine);
>  };
>
>  /**
> --
> git-series 0.9.1

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

* Re: [PATCH v2 05/12] drm/sun4i: engine: Add a VBLANK quirk callback
@ 2017-12-19  5:09     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2017-12-19  5:09 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Thomas Petazzoni, Neil Armstrong, David Airlie, linux-kernel,
	dri-devel, Chen-Yu Tsai, Daniel Vetter, linux-arm-kernel, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> In some cases, the display engine needs to apply some quirks during the
> VBLANK event. In the Display Engine 1.0 case for example, we can only
> disable the frontend once the backend has been, which is at VBLANK.
>
> Let's introduce a callback that can be implemented by the various engines.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_tcon.c   |  4 ++++
>  drivers/gpu/drm/sun4i/sunxi_engine.h | 12 ++++++++++++
>  2 files changed, 16 insertions(+)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index e122f5b2a395..55f54b54293c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -368,6 +368,7 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
>         struct sun4i_tcon *tcon = private;
>         struct drm_device *drm = tcon->drm;
>         struct sun4i_crtc *scrtc = tcon->crtc;
> +       struct sunxi_engine *engine = scrtc->engine;
>         unsigned int status;
>
>         regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
> @@ -385,6 +386,9 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
>                            SUN4I_TCON_GINT0_VBLANK_INT(1),
>                            0);
>
> +       if (engine->ops->vblank_quirk)
> +               engine->ops->vblank_quirk(engine);
> +
>         return IRQ_HANDLED;
>  }
>
> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
> index da2dd36dfbb6..b810c26d78bb 100644
> --- a/drivers/gpu/drm/sun4i/sunxi_engine.h
> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
> @@ -86,6 +86,18 @@ struct sunxi_engine_ops {
>         struct drm_plane **(*layers_init)(struct drm_device *drm,
>                                           struct sunxi_engine *engine);
>
> +       /**
> +        * @vblank_quirk:
> +        *
> +        * This callback is used to implement backend-specific

                                                ^ engine

Otherwise,

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

> +        * behaviour part of the VBLANK event. It is run with all the
> +        * constraints of an interrupt (can't sleep, all local
> +        * interrupts disabled) and therefore should be as fast as
> +        * possible.
> +        *
> +        * This function is optional.
> +        */
> +       void (*vblank_quirk)(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	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 06/12] drm/sun4i: engine: Create an atomic_begin callback
  2017-12-18 14:57   ` Maxime Ripard
@ 2017-12-19  5:14     ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2017-12-19  5:14 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, Chen-Yu Tsai, dri-devel,
	linux-kernel, linux-arm-kernel, Thomas Petazzoni, Neil Armstrong,
	thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> We have to implement some display engine specific behaviours in
> atomic_begin. Let's add a function for that.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_crtc.c   |  6 +++++-
>  drivers/gpu/drm/sun4i/sunxi_engine.h | 13 +++++++++++++
>  2 files changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> index 2a565325714f..f549f2874353 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> @@ -64,6 +64,7 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
>  {
>         struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
>         struct drm_device *dev = crtc->dev;
> +       struct sunxi_engine *engine = scrtc->engine;
>         unsigned long flags;
>
>         if (crtc->state->event) {
> @@ -73,7 +74,10 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
>                 scrtc->event = crtc->state->event;
>                 spin_unlock_irqrestore(&dev->event_lock, flags);
>                 crtc->state->event = NULL;
> -        }
> +       }
> +
> +       if (engine->ops->atomic_begin)
> +               engine->ops->atomic_begin(engine, old_state);
>  }
>
>  static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
> index b810c26d78bb..ec4d54f596d4 100644
> --- a/drivers/gpu/drm/sun4i/sunxi_engine.h
> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
> @@ -33,6 +33,19 @@ struct sunxi_engine_ops {
>         void (*apply_color_correction)(struct sunxi_engine *engine);
>
>         /**
> +        * @atomic_begin:
> +        *
> +        * This callback allows to prepare our backend for an atomic

... our engine ...

Otherwise,

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

> +        * update. This is mirroring the
> +        * &drm_crtc_helper_funcs.atomic_begin callback, so any
> +        * documentation there applies.
> +        *
> +        * This function is optional.
> +        */
> +       void (*atomic_begin)(struct sunxi_engine *engine,
> +                            struct drm_crtc_state *old_state);
> +
> +       /**
>          * @atomic_check:
>          *
>          * This callback allows to validate plane-update related CRTC
> --
> git-series 0.9.1

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

* Re: [PATCH v2 06/12] drm/sun4i: engine: Create an atomic_begin callback
@ 2017-12-19  5:14     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2017-12-19  5:14 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Thomas Petazzoni, Neil Armstrong, David Airlie, linux-kernel,
	dri-devel, Chen-Yu Tsai, Daniel Vetter, linux-arm-kernel, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> We have to implement some display engine specific behaviours in
> atomic_begin. Let's add a function for that.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_crtc.c   |  6 +++++-
>  drivers/gpu/drm/sun4i/sunxi_engine.h | 13 +++++++++++++
>  2 files changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> index 2a565325714f..f549f2874353 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> @@ -64,6 +64,7 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
>  {
>         struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
>         struct drm_device *dev = crtc->dev;
> +       struct sunxi_engine *engine = scrtc->engine;
>         unsigned long flags;
>
>         if (crtc->state->event) {
> @@ -73,7 +74,10 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
>                 scrtc->event = crtc->state->event;
>                 spin_unlock_irqrestore(&dev->event_lock, flags);
>                 crtc->state->event = NULL;
> -        }
> +       }
> +
> +       if (engine->ops->atomic_begin)
> +               engine->ops->atomic_begin(engine, old_state);
>  }
>
>  static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
> index b810c26d78bb..ec4d54f596d4 100644
> --- a/drivers/gpu/drm/sun4i/sunxi_engine.h
> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
> @@ -33,6 +33,19 @@ struct sunxi_engine_ops {
>         void (*apply_color_correction)(struct sunxi_engine *engine);
>
>         /**
> +        * @atomic_begin:
> +        *
> +        * This callback allows to prepare our backend for an atomic

... our engine ...

Otherwise,

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

> +        * update. This is mirroring the
> +        * &drm_crtc_helper_funcs.atomic_begin callback, so any
> +        * documentation there applies.
> +        *
> +        * This function is optional.
> +        */
> +       void (*atomic_begin)(struct sunxi_engine *engine,
> +                            struct drm_crtc_state *old_state);
> +
> +       /**
>          * @atomic_check:
>          *
>          * This callback allows to validate plane-update related CRTC
> --
> 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] 65+ messages in thread

* Re: [PATCH v2 10/12] drm/sun4i: backend: Use runtime_pm variant of atomic_commit_tail
  2017-12-18 14:57   ` Maxime Ripard
@ 2018-01-04 14:50     ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 14:50 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, dri-devel, linux-kernel,
	linux-arm-kernel, Thomas Petazzoni, Neil Armstrong, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> During a hardware commit, the commit bit in the backend will only be
> cleared if the TCON is enabled. Use the runtime_pm variant of the
> atomic_commit_tail hook that makes sure that the CRTC, our TCON, is enabled
> when we perform an atomic_commit.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

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

* [PATCH v2 10/12] drm/sun4i: backend: Use runtime_pm variant of atomic_commit_tail
@ 2018-01-04 14:50     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> During a hardware commit, the commit bit in the backend will only be
> cleared if the TCON is enabled. Use the runtime_pm variant of the
> atomic_commit_tail hook that makes sure that the CRTC, our TCON, is enabled
> when we perform an atomic_commit.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

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

* Re: [PATCH v2 11/12] drm/sun4i: backend: Make sure we don't have a commit pending
  2017-12-18 14:57   ` Maxime Ripard
  (?)
@ 2018-01-04 14:50     ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 14:50 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, dri-devel, linux-kernel,
	linux-arm-kernel, Thomas Petazzoni, Neil Armstrong, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> If we try to read the backend registers while it fetches the new values, we
> end up with the value of some random register instead of the one we asked
> for.
>
> In order to prevent that, let's make sure that the very first thing we do
> during our atomic modesetting is to let the commit bit come to a rest.
>
> We don't have to worry about anything else since the only time we will
> trigger a new transaction is during the atomic_commit which comes much
> later.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

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

* [PATCH v2 11/12] drm/sun4i: backend: Make sure we don't have a commit pending
@ 2018-01-04 14:50     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> If we try to read the backend registers while it fetches the new values, we
> end up with the value of some random register instead of the one we asked
> for.
>
> In order to prevent that, let's make sure that the very first thing we do
> during our atomic modesetting is to let the commit bit come to a rest.
>
> We don't have to worry about anything else since the only time we will
> trigger a new transaction is during the atomic_commit which comes much
> later.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

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

* Re: [PATCH v2 11/12] drm/sun4i: backend: Make sure we don't have a commit pending
@ 2018-01-04 14:50     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 14:50 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Thomas Petazzoni, Neil Armstrong, David Airlie, linux-kernel,
	dri-devel, Daniel Vetter, linux-arm-kernel, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> If we try to read the backend registers while it fetches the new values, we
> end up with the value of some random register instead of the one we asked
> for.
>
> In order to prevent that, let's make sure that the very first thing we do
> during our atomic modesetting is to let the commit bit come to a rest.
>
> We don't have to worry about anything else since the only time we will
> trigger a new transaction is during the atomic_commit which comes much
> later.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/12] ARM: dts: sun8i: a33 Enable our display frontend
  2017-12-18 14:57   ` Maxime Ripard
  (?)
@ 2018-01-04 14:51     ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 14:51 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, dri-devel, linux-kernel,
	linux-arm-kernel, Thomas Petazzoni, Neil Armstrong, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> 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>

Acked-by: Chen-Yu Tsai <wens@csie.org>

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

* [PATCH v2 12/12] ARM: dts: sun8i: a33 Enable our display frontend
@ 2018-01-04 14:51     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> 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>

Acked-by: Chen-Yu Tsai <wens@csie.org>

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

* Re: [PATCH v2 12/12] ARM: dts: sun8i: a33 Enable our display frontend
@ 2018-01-04 14:51     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 14:51 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Thomas Petazzoni, Neil Armstrong, David Airlie, linux-kernel,
	dri-devel, Daniel Vetter, linux-arm-kernel, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> 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>

Acked-by: Chen-Yu Tsai <wens@csie.org>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 07/12] drm/sun4i: Add a driver for the display frontend
  2017-12-18 14:57   ` Maxime Ripard
  (?)
@ 2018-01-04 15:35     ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 15:35 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, dri-devel, linux-kernel,
	linux-arm-kernel, Thomas Petazzoni, Neil Armstrong, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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_drv.c      |  16 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_frontend.c | 392 ++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_frontend.h |  96 ++++++-
>  5 files changed, 503 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_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

Not quite... I left them enabled in all the ones I did (A10/A20/A31)...

> +        * 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..fb3e96ab57f7
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> @@ -0,0 +1,392 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2017 Free Electrons
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + */
> +#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/pm_runtime.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)
> +{
> +       return pm_runtime_get_sync(frontend->dev);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_init);
> +
> +void sun4i_frontend_exit(struct sun4i_frontend *frontend)
> +{
> +       pm_runtime_put(frontend->dev);
> +}
> +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];

You can use drm_fb_cma_get_gem_addr(fb, state, 0), instead of open
coding it.

Do we need to convert the address, like with the backend?

> +
> +       DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> +       regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_buffer);
> +
> +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);

I really don't understand any of this. :(

> +
> +       regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
> +                    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,
> +                    SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1));

You don't seem to be using the values you got from the helper functions.
Moreover, they don't match the values you claim to support.

> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_formats);
> +
> +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));

Slighty off-topic, but does the kernel provide helpers for 16.16
fixed point arithmetic?

> +
> +       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));

Do you need to set the line stride registers?

> +
> +       DRM_DEBUG_DRIVER("Frontend horizontal scaling factor %d.%d\n", 1, 0);

Value doesn't match what is programmed.

> +       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);

Neither does this.

> +       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);

I don't think you need to program any of the channel 1 registers for
interleaved data.

> +
> +       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->dev = dev;
> +       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);

Maybe force a reset here?

> +       pm_runtime_enable(dev);
> +
> +       return 0;
> +}
> +
> +static void sun4i_frontend_unbind(struct device *dev, struct device *master,
> +                           void *data)
> +{
> +       struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +
> +       list_del(&frontend->list);
> +       pm_runtime_force_suspend(dev);
> +}
> +
> +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 int sun4i_frontend_runtime_resume(struct device *dev)
> +{
> +       struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +       int ret;
> +
> +       ret = reset_control_deassert(frontend->reset);
> +       if (ret) {
> +               dev_err(dev, "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);

I wonder if the clocks should be enabled first, so the registers
and internal state gets properly reset?

> +
> +       regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
> +                          SUN4I_FRONTEND_EN_EN,
> +                          SUN4I_FRONTEND_EN_EN);
> +

You also need to set OUT_PORT_SEL in FRM_CTRL_REG so that frontend1
correctly outputs to backend1, assuming a static mapping.

> +       regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
> +                          SUN4I_FRONTEND_BYPASS_CSC_EN,
> +                          SUN4I_FRONTEND_BYPASS_CSC_EN);
> +
> +       sun4i_frontend_scaler_init(frontend);
> +
> +       return 0;
> +}
> +
> +static int sun4i_frontend_runtime_suspend(struct device *dev)
> +{
> +       struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +
> +       clk_disable_unprepare(frontend->ram_clk);
> +       clk_disable_unprepare(frontend->mod_clk);
> +       clk_disable_unprepare(frontend->bus_clk);
> +
> +       reset_control_assert(frontend->reset);
> +
> +       return 0;
> +}
> +
> +static const struct dev_pm_ops sun4i_frontend_pm_ops = {
> +       .runtime_resume         = sun4i_frontend_runtime_resume,
> +       .runtime_suspend        = sun4i_frontend_runtime_suspend,
> +};
> +
> +static const struct of_device_id sun4i_frontend_of_table[] = {
> +       { .compatible = "allwinner,sun5i-a13-display-frontend" },
> +       { .compatible = "allwinner,sun6i-a31-display-frontend" },

What about A10 and A20?

Regards
ChenYu

> +       { .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,
> +               .pm             = &sun4i_frontend_pm_ops,
> +       },
> +};
> +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..5adc2c7266bc
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2017 Free Electrons
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + */
> +
> +#ifndef _SUN4I_FRONTEND_H_
> +#define _SUN4I_FRONTEND_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;
> +       struct device           *dev;
> +       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	[flat|nested] 65+ messages in thread

* [PATCH v2 07/12] drm/sun4i: Add a driver for the display frontend
@ 2018-01-04 15:35     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 15:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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_drv.c      |  16 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_frontend.c | 392 ++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_frontend.h |  96 ++++++-
>  5 files changed, 503 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_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

Not quite... I left them enabled in all the ones I did (A10/A20/A31)...

> +        * 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..fb3e96ab57f7
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> @@ -0,0 +1,392 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2017 Free Electrons
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + */
> +#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/pm_runtime.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)
> +{
> +       return pm_runtime_get_sync(frontend->dev);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_init);
> +
> +void sun4i_frontend_exit(struct sun4i_frontend *frontend)
> +{
> +       pm_runtime_put(frontend->dev);
> +}
> +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];

You can use drm_fb_cma_get_gem_addr(fb, state, 0), instead of open
coding it.

Do we need to convert the address, like with the backend?

> +
> +       DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> +       regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_buffer);
> +
> +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);

I really don't understand any of this. :(

> +
> +       regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
> +                    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,
> +                    SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1));

You don't seem to be using the values you got from the helper functions.
Moreover, they don't match the values you claim to support.

> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_formats);
> +
> +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));

Slighty off-topic, but does the kernel provide helpers for 16.16
fixed point arithmetic?

> +
> +       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));

Do you need to set the line stride registers?

> +
> +       DRM_DEBUG_DRIVER("Frontend horizontal scaling factor %d.%d\n", 1, 0);

Value doesn't match what is programmed.

> +       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);

Neither does this.

> +       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);

I don't think you need to program any of the channel 1 registers for
interleaved data.

> +
> +       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->dev = dev;
> +       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);

Maybe force a reset here?

> +       pm_runtime_enable(dev);
> +
> +       return 0;
> +}
> +
> +static void sun4i_frontend_unbind(struct device *dev, struct device *master,
> +                           void *data)
> +{
> +       struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +
> +       list_del(&frontend->list);
> +       pm_runtime_force_suspend(dev);
> +}
> +
> +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 int sun4i_frontend_runtime_resume(struct device *dev)
> +{
> +       struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +       int ret;
> +
> +       ret = reset_control_deassert(frontend->reset);
> +       if (ret) {
> +               dev_err(dev, "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);

I wonder if the clocks should be enabled first, so the registers
and internal state gets properly reset?

> +
> +       regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
> +                          SUN4I_FRONTEND_EN_EN,
> +                          SUN4I_FRONTEND_EN_EN);
> +

You also need to set OUT_PORT_SEL in FRM_CTRL_REG so that frontend1
correctly outputs to backend1, assuming a static mapping.

> +       regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
> +                          SUN4I_FRONTEND_BYPASS_CSC_EN,
> +                          SUN4I_FRONTEND_BYPASS_CSC_EN);
> +
> +       sun4i_frontend_scaler_init(frontend);
> +
> +       return 0;
> +}
> +
> +static int sun4i_frontend_runtime_suspend(struct device *dev)
> +{
> +       struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +
> +       clk_disable_unprepare(frontend->ram_clk);
> +       clk_disable_unprepare(frontend->mod_clk);
> +       clk_disable_unprepare(frontend->bus_clk);
> +
> +       reset_control_assert(frontend->reset);
> +
> +       return 0;
> +}
> +
> +static const struct dev_pm_ops sun4i_frontend_pm_ops = {
> +       .runtime_resume         = sun4i_frontend_runtime_resume,
> +       .runtime_suspend        = sun4i_frontend_runtime_suspend,
> +};
> +
> +static const struct of_device_id sun4i_frontend_of_table[] = {
> +       { .compatible = "allwinner,sun5i-a13-display-frontend" },
> +       { .compatible = "allwinner,sun6i-a31-display-frontend" },

What about A10 and A20?

Regards
ChenYu

> +       { .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,
> +               .pm             = &sun4i_frontend_pm_ops,
> +       },
> +};
> +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..5adc2c7266bc
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2017 Free Electrons
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + */
> +
> +#ifndef _SUN4I_FRONTEND_H_
> +#define _SUN4I_FRONTEND_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;
> +       struct device           *dev;
> +       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	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 07/12] drm/sun4i: Add a driver for the display frontend
@ 2018-01-04 15:35     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 15:35 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Thomas Petazzoni, Neil Armstrong, David Airlie, linux-kernel,
	dri-devel, Daniel Vetter, linux-arm-kernel, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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_drv.c      |  16 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.h      |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_frontend.c | 392 ++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_frontend.h |  96 ++++++-
>  5 files changed, 503 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_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

Not quite... I left them enabled in all the ones I did (A10/A20/A31)...

> +        * 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..fb3e96ab57f7
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> @@ -0,0 +1,392 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2017 Free Electrons
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + */
> +#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/pm_runtime.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)
> +{
> +       return pm_runtime_get_sync(frontend->dev);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_init);
> +
> +void sun4i_frontend_exit(struct sun4i_frontend *frontend)
> +{
> +       pm_runtime_put(frontend->dev);
> +}
> +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];

You can use drm_fb_cma_get_gem_addr(fb, state, 0), instead of open
coding it.

Do we need to convert the address, like with the backend?

> +
> +       DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> +       regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_buffer);
> +
> +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);

I really don't understand any of this. :(

> +
> +       regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
> +                    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,
> +                    SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1));

You don't seem to be using the values you got from the helper functions.
Moreover, they don't match the values you claim to support.

> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_formats);
> +
> +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));

Slighty off-topic, but does the kernel provide helpers for 16.16
fixed point arithmetic?

> +
> +       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));

Do you need to set the line stride registers?

> +
> +       DRM_DEBUG_DRIVER("Frontend horizontal scaling factor %d.%d\n", 1, 0);

Value doesn't match what is programmed.

> +       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);

Neither does this.

> +       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);

I don't think you need to program any of the channel 1 registers for
interleaved data.

> +
> +       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->dev = dev;
> +       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);

Maybe force a reset here?

> +       pm_runtime_enable(dev);
> +
> +       return 0;
> +}
> +
> +static void sun4i_frontend_unbind(struct device *dev, struct device *master,
> +                           void *data)
> +{
> +       struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +
> +       list_del(&frontend->list);
> +       pm_runtime_force_suspend(dev);
> +}
> +
> +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 int sun4i_frontend_runtime_resume(struct device *dev)
> +{
> +       struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +       int ret;
> +
> +       ret = reset_control_deassert(frontend->reset);
> +       if (ret) {
> +               dev_err(dev, "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);

I wonder if the clocks should be enabled first, so the registers
and internal state gets properly reset?

> +
> +       regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
> +                          SUN4I_FRONTEND_EN_EN,
> +                          SUN4I_FRONTEND_EN_EN);
> +

You also need to set OUT_PORT_SEL in FRM_CTRL_REG so that frontend1
correctly outputs to backend1, assuming a static mapping.

> +       regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
> +                          SUN4I_FRONTEND_BYPASS_CSC_EN,
> +                          SUN4I_FRONTEND_BYPASS_CSC_EN);
> +
> +       sun4i_frontend_scaler_init(frontend);
> +
> +       return 0;
> +}
> +
> +static int sun4i_frontend_runtime_suspend(struct device *dev)
> +{
> +       struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +
> +       clk_disable_unprepare(frontend->ram_clk);
> +       clk_disable_unprepare(frontend->mod_clk);
> +       clk_disable_unprepare(frontend->bus_clk);
> +
> +       reset_control_assert(frontend->reset);
> +
> +       return 0;
> +}
> +
> +static const struct dev_pm_ops sun4i_frontend_pm_ops = {
> +       .runtime_resume         = sun4i_frontend_runtime_resume,
> +       .runtime_suspend        = sun4i_frontend_runtime_suspend,
> +};
> +
> +static const struct of_device_id sun4i_frontend_of_table[] = {
> +       { .compatible = "allwinner,sun5i-a13-display-frontend" },
> +       { .compatible = "allwinner,sun6i-a31-display-frontend" },

What about A10 and A20?

Regards
ChenYu

> +       { .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,
> +               .pm             = &sun4i_frontend_pm_ops,
> +       },
> +};
> +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..5adc2c7266bc
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2017 Free Electrons
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + */
> +
> +#ifndef _SUN4I_FRONTEND_H_
> +#define _SUN4I_FRONTEND_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;
> +       struct device           *dev;
> +       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	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 08/12] drm/sun4i: backend: Wire in the frontend
  2017-12-18 14:57   ` Maxime Ripard
@ 2018-01-04 15:47     ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 15:47 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, dri-devel, linux-kernel,
	linux-arm-kernel, Thomas Petazzoni, Neil Armstrong, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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 | 90 ++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h |  8 ++-
>  drivers/gpu/drm/sun4i/sun4i_crtc.c    |  1 +-
>  drivers/gpu/drm/sun4i/sun4i_layer.c   | 33 +++++++++-
>  drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
>  5 files changed, 130 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index f971d3fb5ee4..29e1ca7e01fe 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);

You also need to select which frontend to use by setting LAY_VDOSEL.

> +
> +       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)
>  {
> @@ -246,6 +271,36 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>         return 0;
>  }
>
> +static void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
> +{
> +       struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
> +       struct sun4i_frontend *frontend = backend->frontend;
> +
> +       if (!frontend)
> +               return;
> +
> +       /*
> +        * In a teardown scenario with the frontend involved, we have
> +        * to keep the frontend enabled until the next vblank, and
> +        * only then disable it.
> +        *
> +        * This is due to the fact that the backend will not take into
> +        * account the new configuration (with the plane that used to
> +        * be fed by the frontend now disabled) until we write to the
> +        * commit bit and the hardware fetches the new configuration
> +        * during the next vblank.
> +        *
> +        * So we keep the frontend around in order to prevent any
> +        * visual artifacts.
> +        */
> +       spin_lock(&backend->frontend_lock);
> +       if (backend->frontend_teardown) {
> +               sun4i_frontend_exit(frontend);
> +               backend->frontend_teardown = false;
> +       }
> +       spin_unlock(&backend->frontend_lock);
> +};
> +
>  static int sun4i_backend_init_sat(struct device *dev) {
>         struct sun4i_backend *backend = dev_get_drvdata(dev);
>         int ret;
> @@ -330,11 +385,40 @@ 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;

This would return the same frontend for both backends in a dual pipeline setup.
Remember that we now have cross-connecting links between frontends and backends
of both pipelines.

Instead just match the frontend's ID to the backend's ID. BTW I think you left
out the ID thing in the frontend driver.

The rest looks good.

ChenYu

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

* [PATCH v2 08/12] drm/sun4i: backend: Wire in the frontend
@ 2018-01-04 15:47     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 15:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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 | 90 ++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_backend.h |  8 ++-
>  drivers/gpu/drm/sun4i/sun4i_crtc.c    |  1 +-
>  drivers/gpu/drm/sun4i/sun4i_layer.c   | 33 +++++++++-
>  drivers/gpu/drm/sun4i/sun4i_layer.h   |  1 +-
>  5 files changed, 130 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index f971d3fb5ee4..29e1ca7e01fe 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);

You also need to select which frontend to use by setting LAY_VDOSEL.

> +
> +       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)
>  {
> @@ -246,6 +271,36 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>         return 0;
>  }
>
> +static void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
> +{
> +       struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
> +       struct sun4i_frontend *frontend = backend->frontend;
> +
> +       if (!frontend)
> +               return;
> +
> +       /*
> +        * In a teardown scenario with the frontend involved, we have
> +        * to keep the frontend enabled until the next vblank, and
> +        * only then disable it.
> +        *
> +        * This is due to the fact that the backend will not take into
> +        * account the new configuration (with the plane that used to
> +        * be fed by the frontend now disabled) until we write to the
> +        * commit bit and the hardware fetches the new configuration
> +        * during the next vblank.
> +        *
> +        * So we keep the frontend around in order to prevent any
> +        * visual artifacts.
> +        */
> +       spin_lock(&backend->frontend_lock);
> +       if (backend->frontend_teardown) {
> +               sun4i_frontend_exit(frontend);
> +               backend->frontend_teardown = false;
> +       }
> +       spin_unlock(&backend->frontend_lock);
> +};
> +
>  static int sun4i_backend_init_sat(struct device *dev) {
>         struct sun4i_backend *backend = dev_get_drvdata(dev);
>         int ret;
> @@ -330,11 +385,40 @@ 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;

This would return the same frontend for both backends in a dual pipeline setup.
Remember that we now have cross-connecting links between frontends and backends
of both pipelines.

Instead just match the frontend's ID to the backend's ID. BTW I think you left
out the ID thing in the frontend driver.

The rest looks good.

ChenYu

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

* Re: [PATCH v2 09/12] drm/sun4i: backend: Add a custom atomic_check for the frontend
  2017-12-18 14:57   ` Maxime Ripard
@ 2018-01-04 15:49     ` Chen-Yu Tsai
  -1 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 15:49 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Daniel Vetter, David Airlie, dri-devel, linux-kernel,
	linux-arm-kernel, Thomas Petazzoni, Neil Armstrong, thomas

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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.
>
> Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

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

* [PATCH v2 09/12] drm/sun4i: backend: Add a custom atomic_check for the frontend
@ 2018-01-04 15:49     ` Chen-Yu Tsai
  0 siblings, 0 replies; 65+ messages in thread
From: Chen-Yu Tsai @ 2018-01-04 15:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> 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.
>
> Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

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

end of thread, other threads:[~2018-01-04 15:49 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-18 14:57 [PATCH v2 00/12] drm/sun4i: Support the Display Engine frontend Maxime Ripard
2017-12-18 14:57 ` Maxime Ripard
2017-12-18 14:57 ` Maxime Ripard
2017-12-18 14:57 ` [PATCH v2 01/12] drm/sun4i: backend: Move line stride setup to buffer setup function Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-19  5:04   ` Chen-Yu Tsai
2017-12-18 14:57 ` [PATCH v2 02/12] sun4i/drm: backend: Document the engine operations Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-19  5:06   ` Chen-Yu Tsai
2017-12-19  5:06     ` Chen-Yu Tsai
2017-12-18 14:57 ` [PATCH v2 03/12] drm/sun4i: backend: Add a custom plane state Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-19  5:07   ` Chen-Yu Tsai
2017-12-19  5:07     ` Chen-Yu Tsai
2017-12-18 14:57 ` [PATCH v2 04/12] drm/sun4i: engine: Add a custom crtc atomic_check Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-19  5:08   ` Chen-Yu Tsai
2017-12-19  5:08     ` Chen-Yu Tsai
2017-12-18 14:57 ` [PATCH v2 05/12] drm/sun4i: engine: Add a VBLANK quirk callback Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-19  5:09   ` Chen-Yu Tsai
2017-12-19  5:09     ` Chen-Yu Tsai
2017-12-18 14:57 ` [PATCH v2 06/12] drm/sun4i: engine: Create an atomic_begin callback Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-19  5:14   ` Chen-Yu Tsai
2017-12-19  5:14     ` Chen-Yu Tsai
2017-12-18 14:57 ` [PATCH v2 07/12] drm/sun4i: Add a driver for the display frontend Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2018-01-04 15:35   ` Chen-Yu Tsai
2018-01-04 15:35     ` Chen-Yu Tsai
2018-01-04 15:35     ` Chen-Yu Tsai
2017-12-18 14:57 ` [PATCH v2 08/12] drm/sun4i: backend: Wire in the frontend Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2018-01-04 15:47   ` Chen-Yu Tsai
2018-01-04 15:47     ` Chen-Yu Tsai
2017-12-18 14:57 ` [PATCH v2 09/12] drm/sun4i: backend: Add a custom atomic_check for " Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2018-01-04 15:49   ` Chen-Yu Tsai
2018-01-04 15:49     ` Chen-Yu Tsai
2017-12-18 14:57 ` [PATCH v2 10/12] drm/sun4i: backend: Use runtime_pm variant of atomic_commit_tail Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2018-01-04 14:50   ` Chen-Yu Tsai
2018-01-04 14:50     ` Chen-Yu Tsai
2017-12-18 14:57 ` [PATCH v2 11/12] drm/sun4i: backend: Make sure we don't have a commit pending Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2018-01-04 14:50   ` Chen-Yu Tsai
2018-01-04 14:50     ` Chen-Yu Tsai
2018-01-04 14:50     ` Chen-Yu Tsai
2017-12-18 14:57 ` [PATCH v2 12/12] ARM: dts: sun8i: a33 Enable our display frontend Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2017-12-18 14:57   ` Maxime Ripard
2018-01-04 14:51   ` Chen-Yu Tsai
2018-01-04 14:51     ` Chen-Yu Tsai
2018-01-04 14:51     ` Chen-Yu Tsai

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.