v4l: vsp1: extend VSP1 module API to allow DRM callbacks
To be able to perform page flips in DRM without flicker we need to be
able to notify the rcar-du module when the VSP has completed its
processing.
We must not have bidirectional dependencies on the two components to
maintain support for loadable modules, thus we extend the API to allow
a callback to be registered within the VSP DRM interface.
Calls to rcar_du_vsp_atomic_flush() can provide a private data variable,
which will be returned through the callback when the frame has
completed.
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
---
v2:
- vsp1_du_setup_lif() uses config structure to set callbacks
- vsp1_du_pipeline_frame_end() moved to interrupt section
- vsp1_du_pipeline_frame_end registered in vsp1_drm_init()
- Adapted callback to always call, The receiver should determine if the
meaning of any NULL values
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index b0ff304..9736b228 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -85,7 +85,7 @@ void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc)
void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc)
{
- vsp1_du_atomic_flush(crtc->vsp->vsp);
+ vsp1_du_atomic_flush(crtc->vsp->vsp, NULL);
}
/* Keep the two tables in sync. */
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 7dce5504..0983ccc 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -36,6 +36,18 @@ void vsp1_drm_display_start(struct vsp1_device *vsp1)
vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm);
}
+static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe)
+{
+ struct vsp1_drm *drm = to_vsp1_drm(pipe);
+
+ if (drm->du_complete)
+ drm->du_complete(drm->du_private, drm->active_data);
+
+ /* The pending frame is now active */
+ drm->active_data = drm->pending_data;
+ drm->pending_data = NULL;
+}
+
/* -----------------------------------------------------------------------------
* DU Driver API
*/
@@ -95,6 +107,7 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg)
}
pipe->num_inputs = 0;
+ vsp1->drm->du_complete = NULL;
vsp1_dlm_reset(pipe->output->dlm);
vsp1_device_put(vsp1);
@@ -196,6 +209,13 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg)
if (ret < 0)
return ret;
+ /*
+ * Register a callback to allow us to notify the DRM framework of frame
+ * completion events.
+ */
+ vsp1->drm->du_complete = cfg->callback;
+ vsp1->drm->du_private = cfg->callback_data;
+
ret = media_pipeline_start(&pipe->output->entity.subdev.entity,
&pipe->pipe);
if (ret < 0) {
@@ -420,7 +440,7 @@ static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf)
* vsp1_du_atomic_flush - Commit an atomic update
* @dev: the VSP device
*/
-void vsp1_du_atomic_flush(struct device *dev)
+void vsp1_du_atomic_flush(struct device *dev, void *data)
{
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
@@ -504,6 +524,7 @@ void vsp1_du_atomic_flush(struct device *dev)
vsp1_dl_list_commit(pipe->dl);
pipe->dl = NULL;
+ vsp1->drm->pending_data = data;
/* Start or stop the pipeline if needed. */
if (!vsp1->drm->num_inputs && pipe->num_inputs) {
@@ -597,6 +618,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
pipe->lif = &vsp1->lif->entity;
pipe->output = vsp1->wpf[0];
pipe->output->pipe = pipe;
+ pipe->frame_end = vsp1_du_pipeline_frame_end;
return 0;
}
diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h
index 9e28ab9..fdec045 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/vsp1/vsp1_drm.h
@@ -33,8 +33,19 @@ struct vsp1_drm {
struct v4l2_rect compose;
unsigned int zpos;
} inputs[VSP1_MAX_RPF];
+
+ /* Frame syncronisation */
+ void (*du_complete)(void *, void *);
+ void *du_private;
+ void *pending_data;
+ void *active_data;
};
+static inline struct vsp1_drm * to_vsp1_drm(struct vsp1_pipeline *pipe)
+{
+ return container_of(pipe, struct vsp1_drm, pipe);
+}
+
int vsp1_drm_init(struct vsp1_device *vsp1);
void vsp1_drm_cleanup(struct vsp1_device *vsp1);
int vsp1_drm_create_links(struct vsp1_device *vsp1);
diff --git a/include/media/vsp1.h b/include/media/vsp1.h
index bfc701f..a809600 100644
--- a/include/media/vsp1.h
+++ b/include/media/vsp1.h
@@ -23,6 +23,9 @@ int vsp1_du_init(struct device *dev);
struct vsp1_du_lif_config {
unsigned int width;
unsigned int height;
+
+ void (*callback)(void *, void*);
+ void *callback_data;
};
int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg);
@@ -40,6 +43,6 @@ struct vsp1_du_atomic_config {
void vsp1_du_atomic_begin(struct device *dev);
int vsp1_du_atomic_update(struct device *dev, unsigned int rpf,
const struct vsp1_du_atomic_config *cfg);
-void vsp1_du_atomic_flush(struct device *dev);
+void vsp1_du_atomic_flush(struct device *dev, void *data);
#endif /* __MEDIA_VSP1_H__ */