From: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

Break vsp1_du_setup_lif() into components more suited to the DRM Atomic
API. The existing vsp1_du_setup_lif() API call is maintained as it is
still used from the DU.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>
---
Changes since v2:

- Minor formatting changes
- Fix NULL pointer dereference in vsp1_du_setup_lif()
---
 drivers/media/platform/vsp1/vsp1_drm.c | 220 ++++++++++++++++++-------
 include/media/vsp1.h                   |  32 +++-
 2 files changed, 189 insertions(+), 63 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c 
b/drivers/media/platform/vsp1/vsp1_drm.c
index a4a45d68a6ef..7957e1439de0 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -616,10 +616,10 @@ int vsp1_du_init(struct device *dev)
 EXPORT_SYMBOL_GPL(vsp1_du_init);
 
 /**
- * vsp1_du_setup_lif - Setup the output part of the VSP pipeline
+ * vsp1_du_atomic_modeset - Configure the mode as part of an atomic update
  * @dev: the VSP device
  * @pipe_index: the DRM pipeline index
- * @cfg: the LIF configuration
+ * @cfg: the mode configuration
  *
  * Configure the output part of VSP DRM pipeline for the given frame @cfg.width
  * and @cfg.height. This sets up formats on the BRx source pad, the WPF sink 
and
@@ -636,14 +636,12 @@ EXPORT_SYMBOL_GPL(vsp1_du_init);
  *
  * Return 0 on success or a negative error code on failure.
  */
-int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
-                     const struct vsp1_du_lif_config *cfg)
+int vsp1_du_atomic_modeset(struct device *dev, unsigned int pipe_index,
+                          const struct vsp1_du_modeset_config *cfg)
 {
        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
        struct vsp1_drm_pipeline *drm_pipe;
        struct vsp1_pipeline *pipe;
-       unsigned long flags;
-       unsigned int i;
        int ret;
 
        if (pipe_index >= vsp1->info->lif_count)
@@ -652,60 +650,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int 
pipe_index,
        drm_pipe = &vsp1->drm->pipe[pipe_index];
        pipe = &drm_pipe->pipe;
 
-       if (!cfg) {
-               struct vsp1_brx *brx;
-
-               mutex_lock(&vsp1->drm->lock);
-
-               brx = to_brx(&pipe->brx->subdev);
-
-               /*
-                * NULL configuration means the CRTC is being disabled, stop
-                * the pipeline and turn the light off.
-                */
-               ret = vsp1_pipeline_stop(pipe);
-               if (ret == -ETIMEDOUT)
-                       dev_err(vsp1->dev, "DRM pipeline stop timeout\n");
-
-               for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
-                       struct vsp1_rwpf *rpf = pipe->inputs[i];
-
-                       if (!rpf)
-                               continue;
-
-                       /*
-                        * Remove the RPF from the pipe and the list of BRx
-                        * inputs.
-                        */
-                       WARN_ON(!rpf->entity.pipe);
-                       rpf->entity.pipe = NULL;
-                       list_del(&rpf->entity.list_pipe);
-                       pipe->inputs[i] = NULL;
-
-                       brx->inputs[rpf->brx_input].rpf = NULL;
-               }
-
-               drm_pipe->du_complete = NULL;
-               pipe->num_inputs = 0;
-
-               dev_dbg(vsp1->dev, "%s: pipe %u: releasing %s\n",
-                       __func__, pipe->lif->index,
-                       BRX_NAME(pipe->brx));
-
-               list_del(&pipe->brx->list_pipe);
-               pipe->brx->pipe = NULL;
-               pipe->brx = NULL;
-
-               mutex_unlock(&vsp1->drm->lock);
-
-               vsp1_dlm_reset(pipe->output->dlm);
-               vsp1_device_put(vsp1);
-
-               dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
-
-               return 0;
-       }
-
        drm_pipe->width = cfg->width;
        drm_pipe->height = cfg->height;
        pipe->interlaced = cfg->interlaced;
@@ -722,8 +666,43 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int 
pipe_index,
                goto unlock;
 
        ret = vsp1_du_pipeline_setup_output(vsp1, pipe);
-       if (ret < 0)
-               goto unlock;
+
+unlock:
+       mutex_unlock(&vsp1->drm->lock);
+
+       return ret;
+}
+
+/**
+ * vsp1_du_atomic_enable - Enable and start a DU pipeline
+ * @dev: the VSP device
+ * @pipe_index: the DRM pipeline index
+ * @cfg: the enablement configuration
+ *
+ * The @pipe_index argument selects which DRM pipeline to enable. The number of
+ * available pipelines depend on the VSP instance.
+ *
+ * The configuration passes a callback function to register notification of
+ * frame completion events.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+int vsp1_du_atomic_enable(struct device *dev, unsigned int pipe_index,
+                         const struct vsp1_du_enable_config *cfg)
+{
+       struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+       struct vsp1_drm_pipeline *drm_pipe;
+       struct vsp1_pipeline *pipe;
+       unsigned long flags;
+       int ret;
+
+       if (pipe_index >= vsp1->info->lif_count)
+               return -EINVAL;
+
+       drm_pipe = &vsp1->drm->pipe[pipe_index];
+       pipe = &drm_pipe->pipe;
+
+       mutex_lock(&vsp1->drm->lock);
 
        /* Enable the VSP1. */
        ret = vsp1_device_get(vsp1);
@@ -758,6 +737,123 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int 
pipe_index,
        dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__);
 
        return 0;
+
+}
+EXPORT_SYMBOL_GPL(vsp1_du_atomic_enable);
+
+/**
+ * vsp1_du_atomic_disable - Disable and stop a DU pipeline
+ * @dev: the VSP device
+ * @pipe_index: the DRM pipeline index
+ *
+ * The @pipe_index argument selects which DRM pipeline to disable. The number
+ * of available pipelines depend on the VSP instance.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+int vsp1_du_atomic_disable(struct device *dev, unsigned int pipe_index)
+{
+       struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+       struct vsp1_drm_pipeline *drm_pipe;
+       struct vsp1_pipeline *pipe;
+       struct vsp1_brx *brx;
+       unsigned int i;
+       int ret;
+
+       if (pipe_index >= vsp1->info->lif_count)
+               return -EINVAL;
+
+       drm_pipe = &vsp1->drm->pipe[pipe_index];
+       pipe = &drm_pipe->pipe;
+
+       mutex_lock(&vsp1->drm->lock);
+
+       brx = to_brx(&pipe->brx->subdev);
+
+       /* Stop the pipeline and turn the light off. */
+       ret = vsp1_pipeline_stop(pipe);
+       if (ret == -ETIMEDOUT)
+               dev_err(vsp1->dev, "DRM pipeline stop timeout\n");
+
+       for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
+               struct vsp1_rwpf *rpf = pipe->inputs[i];
+
+               if (!rpf)
+                       continue;
+
+               /* Remove the RPF from the pipe and the list of BRx inputs. */
+               WARN_ON(!rpf->entity.pipe);
+               rpf->entity.pipe = NULL;
+               list_del(&rpf->entity.list_pipe);
+               pipe->inputs[i] = NULL;
+
+               brx->inputs[rpf->brx_input].rpf = NULL;
+       }
+
+       drm_pipe->du_complete = NULL;
+       pipe->num_inputs = 0;
+
+       dev_dbg(vsp1->dev, "%s: pipe %u: releasing %s\n", __func__,
+               pipe->lif->index, BRX_NAME(pipe->brx));
+
+       list_del(&pipe->brx->list_pipe);
+       pipe->brx->pipe = NULL;
+       pipe->brx = NULL;
+
+       mutex_unlock(&vsp1->drm->lock);
+
+       vsp1_dlm_reset(pipe->output->dlm);
+       vsp1_device_put(vsp1);
+
+       dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vsp1_du_atomic_disable);
+
+/**
+ * vsp1_du_setup_lif - Setup the output part of the VSP pipeline
+ * @dev: the VSP device
+ * @pipe_index: the DRM pipeline index
+ * @cfg: the LIF configuration
+ *
+ * Configure the output part of VSP DRM pipeline for the given frame @cfg.width
+ * and @cfg.height. This sets up formats on the BRx source pad, the WPF sink 
and
+ * source pads, and the LIF sink pad.
+ *
+ * The @pipe_index argument selects which DRM pipeline to setup. The number of
+ * available pipelines depend on the VSP instance.
+ *
+ * As the media bus code on the blend unit source pad is conditioned by the
+ * configuration of its sink 0 pad, we also set up the formats on all blend 
unit
+ * sinks, even if the configuration will be overwritten later by
+ * vsp1_du_setup_rpf(). This ensures that the blend unit configuration is set 
to
+ * a well defined state.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
+                     const struct vsp1_du_lif_config *cfg)
+{
+       struct vsp1_du_modeset_config modes;
+       struct vsp1_du_enable_config enable;
+       int ret;
+
+       if (!cfg)
+               return vsp1_du_atomic_disable(dev, pipe_index);
+
+       modes.width = cfg->width;
+       modes.height = cfg->height;
+       modes.interlaced = cfg->interlaced;
+
+       ret = vsp1_du_atomic_modeset(dev, pipe_index, &modes);
+       if (ret)
+               return ret;
+
+       enable.callback = cfg->callback;
+       enable.callback_data = cfg->callback_data;
+
+       return vsp1_du_atomic_enable(dev, pipe_index, &enable);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_setup_lif);
 
diff --git a/include/media/vsp1.h b/include/media/vsp1.h
index cc1b0d42ce95..56643f97d4c9 100644
--- a/include/media/vsp1.h
+++ b/include/media/vsp1.h
@@ -21,7 +21,7 @@ int vsp1_du_init(struct device *dev);
 #define VSP1_DU_STATUS_WRITEBACK       BIT(1)
 
 /**
- * struct vsp1_du_lif_config - VSP LIF configuration
+ * struct vsp1_du_lif_config - VSP LIF configuration - Deprecated
  * @width: output frame width
  * @height: output frame height
  * @interlaced: true for interlaced pipelines
@@ -42,6 +42,30 @@ struct vsp1_du_lif_config {
 int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
                      const struct vsp1_du_lif_config *cfg);
 
+/**
+ * struct vsp1_du_modeset_config - VSP display mode configuration
+ * @width: output frame width
+ * @height: output frame height
+ * @interlaced: true for interlaced pipelines
+ */
+struct vsp1_du_modeset_config {
+       unsigned int width;
+       unsigned int height;
+       bool interlaced;
+};
+
+/**
+ * struct vsp1_du_enable_config - VSP enable configuration
+ * @callback: frame completion callback function (optional). When a callback
+ *           is provided, the VSP driver guarantees that it will be called once
+ *           and only once for each vsp1_du_atomic_flush() call.
+ * @callback_data: data to be passed to the frame completion callback
+ */
+struct vsp1_du_enable_config {
+       void (*callback)(void *data, unsigned int status, u32 crc);
+       void *callback_data;
+};
+
 /**
  * struct vsp1_du_atomic_config - VSP atomic configuration parameters
  * @pixelformat: plane pixel format (V4L2 4CC)
@@ -106,6 +130,12 @@ struct vsp1_du_atomic_pipe_config {
        struct vsp1_du_writeback_config writeback;
 };
 
+
+int vsp1_du_atomic_modeset(struct device *dev, unsigned int pipe_index,
+                   const struct vsp1_du_modeset_config *cfg);
+int vsp1_du_atomic_enable(struct device *dev, unsigned int pipe_index,
+                  const struct vsp1_du_enable_config *cfg);
+int vsp1_du_atomic_disable(struct device *dev, unsigned int pipe_index);
 void vsp1_du_atomic_begin(struct device *dev, unsigned int pipe_index);
 int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index,
                          unsigned int rpf,
-- 
Regards,

Laurent Pinchart

Reply via email to