Re: [PATCH v2 08/12] drm/sun4i: backend: Wire in the frontend

2018-01-04 Thread Chen-Yu Tsai
On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
 wrote:
> Now that we have a driver, we can make use of it. This is done by
> adding a flag to our custom plane state that will trigger whether we should
> use the frontend on that particular plane or not.
>
> The rest is just plumbing to set up the backend to not perform the DMA but
> receive its data from the frontend.
>
> Note that we're still not making any use of the frontend itself, as no one
> is setting the flag yet.
>
> Signed-off-by: Maxime Ripard 
> ---
>  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, );
> +   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(>frontend_lock);
> +   if (backend->frontend_teardown) {
> +   sun4i_frontend_exit(frontend);
> +   backend->frontend_teardown = false;
> +   }
> +   spin_unlock(>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, >frontend_list, list) {
> +   if (remote == frontend->node) {
> +   of_node_put(remote);
> +   of_node_put(port);
> +   return 

[PATCH v2 08/12] drm/sun4i: backend: Wire in the frontend

2017-12-18 Thread Maxime Ripard
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 
---
 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, );
+   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(>frontend_lock);
+   if (backend->frontend_teardown) {
+   sun4i_frontend_exit(frontend);
+   backend->frontend_teardown = false;
+   }
+   spin_unlock(>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, >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,