summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/platform/vsp1/vsp1_dl.c23
-rw-r--r--drivers/media/platform/vsp1/vsp1_dl.h3
-rw-r--r--drivers/media/platform/vsp1/vsp1_drm.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c2
4 files changed, 26 insertions, 4 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 662fa2a..30ad4916 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -72,6 +72,7 @@ struct vsp1_dl_body {
* @fragments: list of extra display list bodies
* @has_chain: if true, indicates that there's a partition chain
* @chain: entry in the display list partition chain
+ * @internal: whether the display list is used for internal purpose
*/
struct vsp1_dl_list {
struct list_head list;
@@ -85,6 +86,8 @@ struct vsp1_dl_list {
bool has_chain;
struct list_head chain;
+
+ bool internal;
};
enum vsp1_dl_mode {
@@ -550,8 +553,16 @@ static void vsp1_dl_list_commit_continuous(struct vsp1_dl_list *dl)
* case we can't replace the queued list by the new one, as we could
* race with the hardware. We thus mark the update as pending, it will
* be queued up to the hardware by the frame end interrupt handler.
+ *
+ * If a display list is already pending we simply drop it as the new
+ * display list is assumed to contain a more recent configuration. It is
+ * an error if the already pending list has the internal flag set, as
+ * there is then a process waiting for that list to complete. This
+ * shouldn't happen as the waiting process should perform proper
+ * locking, but warn just in case.
*/
if (vsp1_dl_list_hw_update_pending(dlm)) {
+ WARN_ON(dlm->pending && dlm->pending->internal);
__vsp1_dl_list_put(dlm->pending);
dlm->pending = dl;
return;
@@ -581,7 +592,7 @@ static void vsp1_dl_list_commit_singleshot(struct vsp1_dl_list *dl)
dlm->active = dl;
}
-void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl, bool internal)
{
struct vsp1_dl_manager *dlm = dl->dlm;
struct vsp1_dl_list *dl_child;
@@ -598,6 +609,8 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
}
}
+ dl->internal = internal;
+
spin_lock_irqsave(&dlm->lock, flags);
if (dlm->singleshot)
@@ -624,6 +637,10 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
* raced with the frame end interrupt. The function always returns with the flag
* set in header mode as display list processing is then not continuous and
* races never occur.
+ *
+ * The VSP1_DL_FRAME_END_INTERNAL flag indicates that the previous display list
+ * has completed and had been queued with the internal notification flag.
+ * Internal notification is only supported for continuous mode.
*/
unsigned int vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
{
@@ -656,6 +673,10 @@ unsigned int vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
* frame end interrupt. The display list thus becomes active.
*/
if (dlm->queued) {
+ if (dlm->queued->internal)
+ flags |= VSP1_DL_FRAME_END_INTERNAL;
+ dlm->queued->internal = false;
+
__vsp1_dl_list_put(dlm->active);
dlm->active = dlm->queued;
dlm->queued = NULL;
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index cbc2fc5..1a5bbd5 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -21,6 +21,7 @@ struct vsp1_dl_list;
struct vsp1_dl_manager;
#define VSP1_DL_FRAME_END_COMPLETED BIT(0)
+#define VSP1_DL_FRAME_END_INTERNAL BIT(1)
void vsp1_dlm_setup(struct vsp1_device *vsp1);
@@ -34,7 +35,7 @@ unsigned int vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm);
struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm);
void vsp1_dl_list_put(struct vsp1_dl_list *dl);
void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data);
-void vsp1_dl_list_commit(struct vsp1_dl_list *dl);
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl, bool internal);
struct vsp1_dl_body *vsp1_dl_fragment_alloc(struct vsp1_device *vsp1,
unsigned int num_entries);
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 541473b..68b1260 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -370,7 +370,7 @@ static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
}
}
- vsp1_dl_list_commit(dl);
+ vsp1_dl_list_commit(dl, false);
}
/* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 4152704..a76a446 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -437,7 +437,7 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
}
/* Complete, and commit the head display list. */
- vsp1_dl_list_commit(pipe->dl);
+ vsp1_dl_list_commit(pipe->dl, false);
pipe->dl = NULL;
vsp1_pipeline_run(pipe);
OpenPOWER on IntegriCloud