[PATCHv2 0/2] vsp1 writeback prototype

2016-11-04 Thread Kieran Bingham
Resending this patch series to bring in dri-devel, and interested parties.
Apologies for the resend to linux-media and linux-renesas-soc.

This short series extends the VSP1 on the RCar platforms to allow creating a
V4L2 video node on display pipelines where the hardware allows writing to
memory simultaneously.

In this instance, the hardware restricts the output to match the display size
(no rescaling) but does allow pixel format conversion.

A current limitation (that the DRI devs might have ideas about) is that the vb2
buffers are swapped on the atomic_flush() calls rather than on vsync events.

Ideally swapping buffers would occur on every vsync such that the output rate
of the video node would match the display rate, however the timing here proves
more difficult to synchronise the updates from a vysnc and flush without adding
latency to the flush.

Is there anything I can do to synchronise the v4l2 buffers with the DRM/KMS
interfaces currently? Or does anyone have any suggestions for extending as
such?

And of course ideas on anything that could be done generically to support other
targets as well would be worth considering - though currently this
implementation is very RCar/VSP1 specific.


Kieran Bingham (2):
  Revert "[media] v4l: vsp1: Supply frames to the DU continuously"
  v4l: vsp1: Provide a writeback video device

 drivers/media/platform/vsp1/vsp1.h   |   1 +
 drivers/media/platform/vsp1/vsp1_drm.c   |  19 
 drivers/media/platform/vsp1/vsp1_drv.c   |   5 +-
 drivers/media/platform/vsp1/vsp1_rwpf.h  |   1 +
 drivers/media/platform/vsp1/vsp1_video.c | 161 ---
 drivers/media/platform/vsp1/vsp1_video.h |   5 +
 drivers/media/platform/vsp1/vsp1_wpf.c   |  19 +++-
 7 files changed, 193 insertions(+), 18 deletions(-)

-- 
2.7.4



[PATCHv2 1/2] Revert "[media] v4l: vsp1: Supply frames to the DU continuously"

2016-11-04 Thread Kieran Bingham
This reverts commit 3299ba5c0b21 ("[media] v4l: vsp1: Supply frames to
the DU continuously")

The DU output mode does not rely on frames being supplied on the WPF as
its pipeline is supplied from DRM. For the upcoming WPF writeback
functionality, we will choose to enable writeback mode if there is an
output buffer, or disable it (leaving the existing display pipeline
unharmed) otherwise.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 11 ---
 1 file changed, 11 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index 94b428596c4f..f10401065cd3 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -296,11 +296,6 @@ static struct v4l2_rect vsp1_video_partition(struct 
vsp1_pipeline *pipe,
  * This function completes the current buffer by filling its sequence number,
  * time stamp and payload size, and hands it back to the videobuf core.
  *
- * When operating in DU output mode (deep pipeline to the DU through the LIF),
- * the VSP1 needs to constantly supply frames to the display. In that case, if
- * no other buffer is queued, reuse the one that has just been processed 
instead
- * of handing it back to the videobuf core.
- *
  * Return the next queued buffer or NULL if the queue is empty.
  */
 static struct vsp1_vb2_buffer *
@@ -322,12 +317,6 @@ vsp1_video_complete_buffer(struct vsp1_video *video)
done = list_first_entry(>irqqueue,
struct vsp1_vb2_buffer, queue);
 
-   /* In DU output mode reuse the buffer if the list is singular. */
-   if (pipe->lif && list_is_singular(>irqqueue)) {
-   spin_unlock_irqrestore(>irqlock, flags);
-   return done;
-   }
-
list_del(>queue);
 
if (!list_empty(>irqqueue))
-- 
2.7.4



[PATCH 2/4] v4l: vsp1: Move vsp1_video_pipeline_setup_partitions() function

2016-11-04 Thread Kieran Bingham
Separate the code change from the function move so that code changes can
be clearly identified. This commit has no functional change.

The partition algorithm functions will be changed, and
vsp1_video_partition() will call vsp1_video_pipeline_setup_partitions().
To prepare for that, move the function without any code change.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 74 
 1 file changed, 37 insertions(+), 37 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index d1d3413c6fdf..6d43c02bbc56 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -175,43 +175,6 @@ static int __vsp1_video_try_format(struct vsp1_video 
*video,
  * VSP1 Partition Algorithm support
  */
 
-static void vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
-{
-   struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
-   const struct v4l2_mbus_framefmt *format;
-   struct vsp1_entity *entity;
-   unsigned int div_size;
-
-   /*
-* Partitions are computed on the size before rotation, use the format
-* at the WPF sink.
-*/
-   format = vsp1_entity_get_pad_format(>output->entity,
-   pipe->output->entity.config,
-   RWPF_PAD_SINK);
-   div_size = format->width;
-
-   /* Gen2 hardware doesn't require image partitioning. */
-   if (vsp1->info->gen == 2) {
-   pipe->div_size = div_size;
-   pipe->partitions = 1;
-   return;
-   }
-
-   list_for_each_entry(entity, >entities, list_pipe) {
-   unsigned int entity_max = VSP1_VIDEO_MAX_WIDTH;
-
-   if (entity->ops->max_width) {
-   entity_max = entity->ops->max_width(entity, pipe);
-   if (entity_max)
-   div_size = min(div_size, entity_max);
-   }
-   }
-
-   pipe->div_size = div_size;
-   pipe->partitions = DIV_ROUND_UP(format->width, div_size);
-}
-
 /**
  * vsp1_video_partition - Calculate the active partition output window
  *
@@ -286,6 +249,43 @@ static struct v4l2_rect vsp1_video_partition(struct 
vsp1_pipeline *pipe,
return partition;
 }
 
+static void vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
+{
+   struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+   const struct v4l2_mbus_framefmt *format;
+   struct vsp1_entity *entity;
+   unsigned int div_size;
+
+   /*
+* Partitions are computed on the size before rotation, use the format
+* at the WPF sink.
+*/
+   format = vsp1_entity_get_pad_format(>output->entity,
+   pipe->output->entity.config,
+   RWPF_PAD_SINK);
+   div_size = format->width;
+
+   /* Gen2 hardware doesn't require image partitioning. */
+   if (vsp1->info->gen == 2) {
+   pipe->div_size = div_size;
+   pipe->partitions = 1;
+   return;
+   }
+
+   list_for_each_entry(entity, >entities, list_pipe) {
+   unsigned int entity_max = VSP1_VIDEO_MAX_WIDTH;
+
+   if (entity->ops->max_width) {
+   entity_max = entity->ops->max_width(entity, pipe);
+   if (entity_max)
+   div_size = min(div_size, entity_max);
+   }
+   }
+
+   pipe->div_size = div_size;
+   pipe->partitions = DIV_ROUND_UP(format->width, div_size);
+}
+
 /* 
-
  * Pipeline Management
  */
-- 
2.7.4



[PATCH 3/4] v4l: vsp1: Calculate partition sizes at stream start.

2016-11-04 Thread Kieran Bingham
Previously the active window and partition sizes for each partition is
calculated for each partition every frame. This data is constant and
only needs to be calculated once at the start of the stream.

Extend the vsp1_pipe object to store the maximum number of partitions
possible and pre-calculate the partition sizes into this table.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_pipe.h  | 6 ++
 drivers/media/platform/vsp1/vsp1_video.c | 8 ++--
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index f181949824c9..3af96c4ea244 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -20,6 +20,9 @@
 
 #include 
 
+/* Max Video Width / Min Partition Size = 8190/128 */
+#define VSP1_PIPE_MAX_PARTITIONS 64
+
 struct vsp1_dl_list;
 struct vsp1_rwpf;
 
@@ -81,7 +84,9 @@ enum vsp1_pipeline_state {
  * @dl: display list associated with the pipeline
  * @div_size: The maximum allowed partition size for the pipeline
  * @partitions: The number of partitions used to process one frame
+ * @partition: The current partition for configuration to process
  * @current_partition: The partition number currently being configured
+ * @part_table: The pre-calculated partitions used by the pipeline
  */
 struct vsp1_pipeline {
struct media_pipeline pipe;
@@ -116,6 +121,7 @@ struct vsp1_pipeline {
unsigned int partitions;
struct v4l2_rect partition;
unsigned int current_partition;
+   struct v4l2_rect part_table[VSP1_PIPE_MAX_PARTITIONS];
 };
 
 void vsp1_pipeline_reset(struct vsp1_pipeline *pipe);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index 6d43c02bbc56..c4a8c30df108 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -255,6 +255,7 @@ static void vsp1_video_pipeline_setup_partitions(struct 
vsp1_pipeline *pipe)
const struct v4l2_mbus_framefmt *format;
struct vsp1_entity *entity;
unsigned int div_size;
+   int i;
 
/*
 * Partitions are computed on the size before rotation, use the format
@@ -269,6 +270,7 @@ static void vsp1_video_pipeline_setup_partitions(struct 
vsp1_pipeline *pipe)
if (vsp1->info->gen == 2) {
pipe->div_size = div_size;
pipe->partitions = 1;
+   pipe->part_table[0] = vsp1_video_partition(pipe, div_size, 0);
return;
}
 
@@ -284,6 +286,9 @@ static void vsp1_video_pipeline_setup_partitions(struct 
vsp1_pipeline *pipe)
 
pipe->div_size = div_size;
pipe->partitions = DIV_ROUND_UP(format->width, div_size);
+
+   for (i = 0; i < pipe->partitions; i++)
+   pipe->part_table[i] = vsp1_video_partition(pipe, div_size, i);
 }
 
 /* 
-
@@ -355,8 +360,7 @@ static void vsp1_video_pipeline_run_partition(struct 
vsp1_pipeline *pipe,
 {
struct vsp1_entity *entity;
 
-   pipe->partition = vsp1_video_partition(pipe, pipe->div_size,
-  pipe->current_partition);
+   pipe->partition = pipe->part_table[pipe->current_partition];
 
list_for_each_entry(entity, >entities, list_pipe) {
if (entity->ops->configure)
-- 
2.7.4



[PATCH 0/4] vsp1 partition algorithm improvements

2016-11-04 Thread Kieran Bingham
Some updates and initial improvements for the VSP1 partition algorithm that
remove redundant processing and variables, reducing the processing done in
interrupt context slightly.

Patch 1 brings in some protection against invalid pipeline configurations that
are not supported by the partition algorithm on Gen3 hardware.

Patches 2,3 and 4 clean up the calculation of the partition sizes such that they
are only calculated once at streamon - and the partition windows are stored in
the vsp1_pipeline object.

Kieran Bingham (4):
  v4l: vsp1: Implement partition algorithm restrictions
  v4l: vsp1: Move vsp1_video_pipeline_setup_partitions() function
  v4l: vsp1: Calculate partition sizes at stream start.
  v4l: vsp1: Remove redundant context variables

 drivers/media/platform/vsp1/vsp1_pipe.h  |  10 ++-
 drivers/media/platform/vsp1/vsp1_sru.c   |   7 +-
 drivers/media/platform/vsp1/vsp1_sru.h   |   1 +
 drivers/media/platform/vsp1/vsp1_video.c | 124 +++
 4 files changed, 89 insertions(+), 53 deletions(-)

-- 
2.7.4



[PATCH 4/4] v4l: vsp1: Remove redundant context variables

2016-11-04 Thread Kieran Bingham
The vsp1_pipe object context variables for div_size and
current_partition allowed state to be maintained through processing the
partitions during processing.

Now that the partition tables are calculated during stream on, there is
no requirement to store these variables in the pipe object.

Utilise local variables for the processing as required.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_pipe.h  |  4 
 drivers/media/platform/vsp1/vsp1_video.c | 19 +--
 2 files changed, 9 insertions(+), 14 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index 3af96c4ea244..9e108ddcceb6 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -82,10 +82,8 @@ enum vsp1_pipeline_state {
  * @uds_input: entity at the input of the UDS, if the UDS is present
  * @entities: list of entities in the pipeline
  * @dl: display list associated with the pipeline
- * @div_size: The maximum allowed partition size for the pipeline
  * @partitions: The number of partitions used to process one frame
  * @partition: The current partition for configuration to process
- * @current_partition: The partition number currently being configured
  * @part_table: The pre-calculated partitions used by the pipeline
  */
 struct vsp1_pipeline {
@@ -117,10 +115,8 @@ struct vsp1_pipeline {
 
struct vsp1_dl_list *dl;
 
-   unsigned int div_size;
unsigned int partitions;
struct v4l2_rect partition;
-   unsigned int current_partition;
struct v4l2_rect part_table[VSP1_PIPE_MAX_PARTITIONS];
 };
 
diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index c4a8c30df108..9efaab2cc982 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -268,7 +268,6 @@ static void vsp1_video_pipeline_setup_partitions(struct 
vsp1_pipeline *pipe)
 
/* Gen2 hardware doesn't require image partitioning. */
if (vsp1->info->gen == 2) {
-   pipe->div_size = div_size;
pipe->partitions = 1;
pipe->part_table[0] = vsp1_video_partition(pipe, div_size, 0);
return;
@@ -284,7 +283,6 @@ static void vsp1_video_pipeline_setup_partitions(struct 
vsp1_pipeline *pipe)
}
}
 
-   pipe->div_size = div_size;
pipe->partitions = DIV_ROUND_UP(format->width, div_size);
 
for (i = 0; i < pipe->partitions; i++)
@@ -356,11 +354,12 @@ static void vsp1_video_frame_end(struct vsp1_pipeline 
*pipe,
 }
 
 static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe,
- struct vsp1_dl_list *dl)
+ struct vsp1_dl_list *dl,
+ unsigned int partition_number)
 {
struct vsp1_entity *entity;
 
-   pipe->partition = pipe->part_table[pipe->current_partition];
+   pipe->partition = pipe->part_table[partition_number];
 
list_for_each_entry(entity, >entities, list_pipe) {
if (entity->ops->configure)
@@ -373,6 +372,7 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline 
*pipe)
 {
struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
struct vsp1_entity *entity;
+   unsigned int current_partition = 0;
 
if (!pipe->dl)
pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
@@ -389,13 +389,12 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline 
*pipe)
}
 
/* Run the first partition */
-   pipe->current_partition = 0;
-   vsp1_video_pipeline_run_partition(pipe, pipe->dl);
+   vsp1_video_pipeline_run_partition(pipe, pipe->dl, current_partition);
 
/* Process consecutive partitions as necessary */
-   for (pipe->current_partition = 1;
-pipe->current_partition < pipe->partitions;
-pipe->current_partition++) {
+   for (current_partition = 1;
+current_partition < pipe->partitions;
+current_partition++) {
struct vsp1_dl_list *dl;
 
/*
@@ -415,7 +414,7 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline 
*pipe)
break;
}
 
-   vsp1_video_pipeline_run_partition(pipe, dl);
+   vsp1_video_pipeline_run_partition(pipe, dl, current_partition);
vsp1_dl_list_add_chain(pipe->dl, dl);
}
 
-- 
2.7.4



[PATCH 1/4] v4l: vsp1: Implement partition algorithm restrictions

2016-11-04 Thread Kieran Bingham
The partition algorithm introduced to support scaling, and rotation on
Gen3 hardware has some restrictions on pipeline configuration.

The UDS must not be connected after the SRU in a pipeline, and whilst an
SRU can be connected before the UDS, it can only do so in identity mode.

On Gen3 hardware, the use of an SRU will always engage the partition
algorithm, therefore we must always ensure the restrictions are met on
Gen3 hardware utilising an SRU in the pipeline.

A pipeline with an SRU connected after the UDS will disable any scaling
features of the SRU.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_sru.c   |  7 +--
 drivers/media/platform/vsp1/vsp1_sru.h   |  1 +
 drivers/media/platform/vsp1/vsp1_video.c | 29 -
 3 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_sru.c 
b/drivers/media/platform/vsp1/vsp1_sru.c
index b4e568a3b4ed..42a3ed6d9461 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -152,7 +152,8 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
fse->min_width = format->width;
fse->min_height = format->height;
if (format->width <= SRU_MAX_SIZE / 2 &&
-   format->height <= SRU_MAX_SIZE / 2) {
+   format->height <= SRU_MAX_SIZE / 2 &&
+   sru->force_identity_mode == false) {
fse->max_width = format->width * 2;
fse->max_height = format->height * 2;
} else {
@@ -203,7 +204,8 @@ static void sru_try_format(struct vsp1_sru *sru,
 
if (fmt->width <= SRU_MAX_SIZE / 2 &&
fmt->height <= SRU_MAX_SIZE / 2 &&
-   output_area > input_area * 9 / 4) {
+   output_area > input_area * 9 / 4 &&
+   sru->force_identity_mode == false) {
fmt->width = format->width * 2;
fmt->height = format->height * 2;
} else {
@@ -355,6 +357,7 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
v4l2_ctrl_new_custom(>ctrls, _intensity_control, NULL);
 
sru->intensity = 1;
+   sru->force_identity_mode = false;
 
sru->entity.subdev.ctrl_handler = >ctrls;
 
diff --git a/drivers/media/platform/vsp1/vsp1_sru.h 
b/drivers/media/platform/vsp1/vsp1_sru.h
index 85e241457af2..f8652c04268e 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.h
+++ b/drivers/media/platform/vsp1/vsp1_sru.h
@@ -30,6 +30,7 @@ struct vsp1_sru {
struct v4l2_ctrl_handler ctrls;
 
unsigned int intensity;
+   bool force_identity_mode;
 };
 
 static inline struct vsp1_sru *to_sru(struct v4l2_subdev *subdev)
diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index f19d879ce5ee..d1d3413c6fdf 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -35,6 +35,7 @@
 #include "vsp1_hgt.h"
 #include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
+#include "vsp1_sru.h"
 #include "vsp1_uds.h"
 #include "vsp1_video.h"
 
@@ -458,10 +459,12 @@ static int vsp1_video_pipeline_build_branch(struct 
vsp1_pipeline *pipe,
struct vsp1_rwpf *input,
struct vsp1_rwpf *output)
 {
+   struct vsp1_device *vsp1 = output->entity.vsp1;
struct media_entity_enum ent_enum;
struct vsp1_entity *entity;
struct media_pad *pad;
bool bru_found = false;
+   bool sru_found = false;
int ret;
 
ret = media_entity_enum_init(_enum, >entity.vsp1->media_dev);
@@ -512,13 +515,37 @@ static int vsp1_video_pipeline_build_branch(struct 
vsp1_pipeline *pipe,
goto out;
}
 
-   /* UDS can't be chained. */
+   if (entity->type == VSP1_ENTITY_SRU) {
+   struct vsp1_sru *sru = to_sru(>subdev);
+
+   /*
+* Gen3 partition algorithm restricts SRU double-scaled
+* resolution if it is connected after a UDS entity
+*/
+   if (vsp1->info->gen == 3 && pipe->uds)
+   sru->force_identity_mode = true;
+
+   sru_found = true;
+   }
+
if (entity->type == VSP1_ENTITY_UDS) {
+   /* UDS can't be chained. */
if (pipe->uds) {
ret = -EPIPE;
goto out;
  

Re: [PATCHv3 RFC 4/4] media: Catch null pipes on pipeline stop

2016-12-14 Thread Kieran Bingham
Hi Sakari,

On 14/12/16 07:28, Sakari Ailus wrote:
> Hi Kieran,
> 
> On Tue, Dec 13, 2016 at 05:59:44PM +0000, Kieran Bingham wrote:
>> media_entity_pipeline_stop() can be called through error paths with a
>> NULL entity pipe object. In this instance, stopping is a no-op, so
>> simply return without any action
> 
> The approach of returning silently is wrong; the streaming count is indeed a
> count: you have to decrement it the exactly same number of times it's been
> increased. Code that attempts to call __media_entity_pipeline_stop() on an
> entity that's not streaming is simply buggy.

Ok, Thanks for the heads up on where to look, as I suspected we are in
section B) of my comments below :D

> I've got a patch here that adds a warning to graph traversal on streaming
> count being zero. I sent a pull request including that some days ago:
> 
> <URL:http://www.spinics.net/lists/linux-media/msg108980.html>
> <URL:http://www.spinics.net/lists/linux-media/msg108995.html>

Excellent, thanks, I've merged your branch into mine, and I'll
investigate where the error is actually coming from.

--
Ok - so I've merged your patches, (and dropped this patch) but they
don't fire any warning before I hit my null-pointer dereference in
__media_pipeline_stop(), on the WARN_ON(!pipe->streaming_count);

So I think this is a case of calling stop on an invalid entity rather
than an unbalanced start/stop somehow:

[  613.830334] vsp1 fea38000.vsp: failed to reset wpf.0
[  613.838137] PM: resume of devices complete after 124.410 msecs
[  613.847390] PM: Finishing wakeup.
[  613.852247] Restarting tasks ... done.
[  615.864801] ravb e680.ethernet eth0: Link is Up - 100Mbps/Full -
flow control rx/tx
[  617.011299] vsp1 fea38000.vsp: failed to reset wpf.0
[  617.01] vsp1 fea38000.vsp: DRM pipeline stop timeout
[  617.024649] Unable to handle kernel NULL pointer dereference at
virtual address 
[  617.034273] pgd = ff80098c5000
[  617.039171] [] *pgd=00073fffe003[  617.043336] ,
*pud=00073fffe003
, *pmd=[  617.050353]
[  617.053282] Internal error: Oops: 9605 [#1] PREEMPT SMP
[  617.060309] Modules linked in:
[  617.064793] CPU: 1 PID: 683 Comm: kworker/1:2 Not tainted
4.9.0-00506-g4d2a939ea654 #350
[  617.074320] Hardware name: Renesas Salvator-X board based on r8a7795 (DT)
[  617.082578] Workqueue: events drm_mode_rmfb_work_fn
[  617.04] task: ffc6fabd2b00 task.stack: ffc6f9d9
[  617.096246] PC is at __media_pipeline_stop+0x24/0xe8
[  617.102644] LR is at media_pipeline_stop+0x34/0x48



[  617.863386] [] __media_pipeline_stop+0x24/0xe8
[  617.870417] [] media_pipeline_stop+0x34/0x48
[  617.877272] [] vsp1_du_setup_lif+0x68/0x5a8
[  617.884047] [] rcar_du_vsp_disable+0x2c/0x38
[  617.890898] [] rcar_du_crtc_stop+0x198/0x1e8
[  617.897749] [] rcar_du_crtc_disable+0x20/0x38
[  617.904683] []
drm_atomic_helper_commit_modeset_disables+0x1b0/0x3d8
[  617.913634] [] rcar_du_atomic_complete+0x34/0xc8
[  617.920828] [] rcar_du_atomic_commit+0x2c0/0x2d0
[  617.928012] [] drm_atomic_commit+0x5c/0x68
[  617.934663] [] drm_atomic_helper_set_config+0x90/0xd0
[  617.942288] [] drm_mode_set_config_internal+0x70/0x100
[  617.949996] [] drm_crtc_force_disable+0x30/0x40
[  617.957084] [] drm_framebuffer_remove+0x100/0x128
[  617.964347] [] drm_mode_rmfb_work_fn+0x48/0x60
[  617.971352] [] process_one_work+0x1e0/0x738
[  617.978084] [] worker_thread+0x25c/0x4a0
[  617.984546] [] kthread+0xd4/0xe8
[  617.990305] [] ret_from_fork+0x10/0x50


So, I'll have to schedule some time to investigate this deeper and find
out where we are calling stop on an invalid entity object.

I agree that this patch should simply be dropped though, it was more to
promote a bit of discussion on the area to help me understand what was
going on, which it has!.

Thankyou Sakari!

--
Regards

Kieran


> I think the check here could simply be removed as the check is done for
> every entity in the pipeline with the above patch.
> 
> If there's still a wish to check for the pipe field which should not be
> written by drivers, it should be done during pipeline traversal so that it
> applies to all entities in the pipeline, not just where traversal starts.
> 
>>
>> Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
>> ---
>>
>> I've marked this patch as RFC, although if deemed suitable, by all means
>> integrate it as is.
>>
>> When testing suspend/resume operations on VSP1, I encountered a segfault on 
>> the
>> WARN_ON(!pipe->streaming_count) line, where 'pipe == NULL'. The simple
>> protection fix is to return early in this instance, as this patch does 
>> however:
>>
>> A) Does this early return path warrant a WARN() statement itself, to identify
>> drivers which are incorrectly calling media_

[PATCHv3 1/4] v4l: vsp1: Move vsp1_video_setup_pipeline()

2016-12-13 Thread Kieran Bingham
Move the static vsp1_video_setup_pipeline() function in preparation for
the callee updates so that the vsp1_video_pipeline_run() call can
configure pipelines following suspend resume actions.

This commit is just a code move for clarity performing no functional
change.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 82 
 1 file changed, 41 insertions(+), 41 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index d351b9c768d2..44b687c0b8df 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -350,6 +350,47 @@ static void vsp1_video_frame_end(struct vsp1_pipeline 
*pipe,
pipe->buffers_ready |= 1 << video->pipe_index;
 }
 
+static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
+{
+   struct vsp1_entity *entity;
+
+   /* Determine this pipelines sizes for image partitioning support. */
+   vsp1_video_pipeline_setup_partitions(pipe);
+
+   /* Prepare the display list. */
+   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+   if (!pipe->dl)
+   return -ENOMEM;
+
+   if (pipe->uds) {
+   struct vsp1_uds *uds = to_uds(>uds->subdev);
+
+   /* If a BRU is present in the pipeline before the UDS, the alpha
+* component doesn't need to be scaled as the BRU output alpha
+* value is fixed to 255. Otherwise we need to scale the alpha
+* component only when available at the input RPF.
+*/
+   if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
+   uds->scale_alpha = false;
+   } else {
+   struct vsp1_rwpf *rpf =
+   to_rwpf(>uds_input->subdev);
+
+   uds->scale_alpha = rpf->fmtinfo->alpha;
+   }
+   }
+
+   list_for_each_entry(entity, >entities, list_pipe) {
+   vsp1_entity_route_setup(entity, pipe->dl);
+
+   if (entity->ops->configure)
+   entity->ops->configure(entity, pipe, pipe->dl,
+  VSP1_ENTITY_PARAMS_INIT);
+   }
+
+   return 0;
+}
+
 static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe,
  struct vsp1_dl_list *dl)
 {
@@ -747,47 +788,6 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(>irqlock, flags);
 }
 
-static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
-{
-   struct vsp1_entity *entity;
-
-   /* Determine this pipelines sizes for image partitioning support. */
-   vsp1_video_pipeline_setup_partitions(pipe);
-
-   /* Prepare the display list. */
-   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
-   if (!pipe->dl)
-   return -ENOMEM;
-
-   if (pipe->uds) {
-   struct vsp1_uds *uds = to_uds(>uds->subdev);
-
-   /* If a BRU is present in the pipeline before the UDS, the alpha
-* component doesn't need to be scaled as the BRU output alpha
-* value is fixed to 255. Otherwise we need to scale the alpha
-* component only when available at the input RPF.
-*/
-   if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
-   uds->scale_alpha = false;
-   } else {
-   struct vsp1_rwpf *rpf =
-   to_rwpf(>uds_input->subdev);
-
-   uds->scale_alpha = rpf->fmtinfo->alpha;
-   }
-   }
-
-   list_for_each_entry(entity, >entities, list_pipe) {
-   vsp1_entity_route_setup(entity, pipe->dl);
-
-   if (entity->ops->configure)
-   entity->ops->configure(entity, pipe, pipe->dl,
-  VSP1_ENTITY_PARAMS_INIT);
-   }
-
-   return 0;
-}
-
 static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
struct vsp1_video *video = vb2_get_drv_priv(vq);
-- 
2.7.4



[PATCHv3 0/4] v4l: vsp1: Fix suspend/resume and race on M2M pipelines

2016-12-13 Thread Kieran Bingham
This small patchset helps rework the VSP1 driver to repair an issue on
suspend/resume operations whereby the pipeline does not get reconfigured after
it has been re-initialised following a resume operation.

Along side this, there was an intrinsic race in the vsp1_video_start_streaming()
function whereby multiple streams operating through a BRU, could find themselves
commencing an operation before the pipeline has been configured, or worse -
commencing, just as the pipeline is being configured resulting in a null pointer
dereference on pipe->dl.

This series superceeds a previous effort to fix the BRU race.

Patch [1/4] is a code move only, with no functional change.
Patch [2/4] refactors the vsp1_video_start_streaming() function and fixes both
suspend/resume, and the BRU race in a single change
Patch [3/4] removes the context scoped 'pipe->dl' which has been susceptible to
races and isn't required to be in the context.
Patch [4/4] is an RFC patch really, that fixes a segfault on error paths  and I
certainly expect feedback and brief discussion. Please drop Patch 4
in the event of any further discussion, and don't consider it as
blocking for the first three patches of this series.

v3:
 - Move configured=false from vsp1_device_init to vsp1_reset_wpf()
 - Clean up flag dereferencing with a local struct *

v2:
 - Refactor video pipeline configuration implementation to solve both suspend
   resume and the VSP BRU race in a single change

v1:
 - Original pipeline configuration rework

Kieran Bingham (4):
  v4l: vsp1: Move vsp1_video_setup_pipeline()
  v4l: vsp1: Refactor video pipeline configuration
  v4l: vsp1: Use local display lists and remove global pipe->dl
  media: Catch null pipes on pipeline stop

 drivers/media/media-entity.c |   2 +
 drivers/media/platform/vsp1/vsp1_drm.c   |  20 ++---
 drivers/media/platform/vsp1/vsp1_drv.c   |   4 +
 drivers/media/platform/vsp1/vsp1_pipe.c  |   1 +
 drivers/media/platform/vsp1/vsp1_pipe.h  |   4 +-
 drivers/media/platform/vsp1/vsp1_video.c | 127 +++
 6 files changed, 79 insertions(+), 79 deletions(-)

-- 
2.7.4



[GIT PULL FOR renesas-drivers] Fix suspend/resume and race on M2M pipelines

2016-12-13 Thread Kieran Bingham
From: Kieran Bingham <kieran.bing...@ideasonboard.com>

The following changes since commit 69973b830859bc6529a7a0468ba0d80ee5117826:

  Linux 4.9 (2016-12-11 11:17:54 -0800)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/kbingham/rcar.git 
vsp1/suspend-resume-race

for you to fetch changes up to a952e0103f86d818a444923adeef50fdcb3f70b9:

  media: Catch null pipes on pipeline stop (2016-12-13 16:25:13 +)

----
Kieran Bingham (4):
  v4l: vsp1: Move vsp1_video_setup_pipeline()
  v4l: vsp1: Refactor video pipeline configuration
  v4l: vsp1: Use local display lists and remove global pipe->dl
  media: Catch null pipes on pipeline stop

 drivers/media/media-entity.c |   2 +
 drivers/media/platform/vsp1/vsp1_drm.c   |  20 ++---
 drivers/media/platform/vsp1/vsp1_drv.c   |   4 +
 drivers/media/platform/vsp1/vsp1_pipe.c  |   1 +
 drivers/media/platform/vsp1/vsp1_pipe.h  |   4 +-
 drivers/media/platform/vsp1/vsp1_video.c | 127 +++
 6 files changed, 79 insertions(+), 79 deletions(-)


[PATCHv3 3/4] v4l: vsp1: Use local display lists and remove global pipe->dl

2016-12-13 Thread Kieran Bingham
The usage of pipe->dl is susceptible to races, and it is redundant to
keep this pointer in a larger scoped context.

Now that the calling order of vsp1_video_setup_pipeline() has been
adapted, it is possible to remove the pipe->dl and pass the variable as
required.

Currently the pipe->dl is set during the atomic begin hook, but it is
not utilised until the flush. Moving this should do no harm.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drm.c   | 20 +++---
 drivers/media/platform/vsp1/vsp1_pipe.h  |  2 --
 drivers/media/platform/vsp1/vsp1_video.c | 45 ++--
 3 files changed, 30 insertions(+), 37 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c 
b/drivers/media/platform/vsp1/vsp1_drm.c
index cd209dccff1b..bf735e85b597 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -220,9 +220,6 @@ void vsp1_du_atomic_begin(struct device *dev)
struct vsp1_pipeline *pipe = >drm->pipe;
 
vsp1->drm->num_inputs = pipe->num_inputs;
-
-   /* Prepare the display list. */
-   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
 
@@ -426,10 +423,14 @@ void vsp1_du_atomic_flush(struct device *dev)
struct vsp1_pipeline *pipe = >drm->pipe;
struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
struct vsp1_entity *entity;
+   struct vsp1_dl_list *dl;
unsigned long flags;
unsigned int i;
int ret;
 
+   /* Prepare the display list. */
+   dl = vsp1_dl_list_get(pipe->output->dlm);
+
/* Count the number of enabled inputs and sort them by Z-order. */
pipe->num_inputs = 0;
 
@@ -484,26 +485,25 @@ void vsp1_du_atomic_flush(struct device *dev)
struct vsp1_rwpf *rpf = to_rwpf(>subdev);
 
if (!pipe->inputs[rpf->entity.index]) {
-   vsp1_dl_list_write(pipe->dl, entity->route->reg,
+   vsp1_dl_list_write(dl, entity->route->reg,
   VI6_DPR_NODE_UNUSED);
continue;
}
}
 
-   vsp1_entity_route_setup(entity, pipe->dl);
+   vsp1_entity_route_setup(entity, dl);
 
if (entity->ops->configure) {
-   entity->ops->configure(entity, pipe, pipe->dl,
+   entity->ops->configure(entity, pipe, dl,
   VSP1_ENTITY_PARAMS_INIT);
-   entity->ops->configure(entity, pipe, pipe->dl,
+   entity->ops->configure(entity, pipe, dl,
   VSP1_ENTITY_PARAMS_RUNTIME);
-   entity->ops->configure(entity, pipe, pipe->dl,
+   entity->ops->configure(entity, pipe, dl,
   VSP1_ENTITY_PARAMS_PARTITION);
}
}
 
-   vsp1_dl_list_commit(pipe->dl);
-   pipe->dl = NULL;
+   vsp1_dl_list_commit(dl);
 
/* Start or stop the pipeline if needed. */
if (!vsp1->drm->num_inputs && pipe->num_inputs) {
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index 0743b9fcb655..98980c85081f 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -108,8 +108,6 @@ struct vsp1_pipeline {
 
struct list_head entities;
 
-   struct vsp1_dl_list *dl;
-
unsigned int div_size;
unsigned int partitions;
struct v4l2_rect partition;
diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index 7ff9f4c19ff0..9619ed4dda7c 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -350,18 +350,14 @@ static void vsp1_video_frame_end(struct vsp1_pipeline 
*pipe,
pipe->buffers_ready |= 1 << video->pipe_index;
 }
 
-static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
+static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe,
+struct vsp1_dl_list *dl)
 {
struct vsp1_entity *entity;
 
/* Determine this pipelines sizes for image partitioning support. */
vsp1_video_pipeline_setup_partitions(pipe);
 
-   /* Prepare the display list. */
-   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
-   if (!pipe->dl)
-   return -ENOMEM;
-
if (pipe->uds) {
struct vsp1_uds *uds = to_uds(>uds->subdev);
 
@@ -381,10 +377,10 @@ static

[PATCHv3 RFC 4/4] media: Catch null pipes on pipeline stop

2016-12-13 Thread Kieran Bingham
media_entity_pipeline_stop() can be called through error paths with a
NULL entity pipe object. In this instance, stopping is a no-op, so
simply return without any action

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---

I've marked this patch as RFC, although if deemed suitable, by all means
integrate it as is.

When testing suspend/resume operations on VSP1, I encountered a segfault on the
WARN_ON(!pipe->streaming_count) line, where 'pipe == NULL'. The simple
protection fix is to return early in this instance, as this patch does however:

A) Does this early return path warrant a WARN() statement itself, to identify
drivers which are incorrectly calling media_entity_pipeline_stop() with an
invalid entity, or would this just be noise ...

and therefore..

B) I also partly assume this patch could simply get NAK'd with a request to go
and dig out the root cause of calling media_entity_pipeline_stop() with an
invalid entity. 

My brief investigation so far here so far shows that it's almost a second order
fault - where the first suspend resume cycle completes but leaves the entity in
an invalid state having followed an error path - and then on a second
suspend/resume - the stop fails with the affected segfault.

If statement A) or B) apply here, please drop this patch from the series, and
don't consider it a blocking issue for the other 3 patches.

Kieran


 drivers/media/media-entity.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index c68239e60487..93c9cbf4bf46 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -508,6 +508,8 @@ void __media_entity_pipeline_stop(struct media_entity 
*entity)
struct media_entity_graph *graph = >pipe->graph;
struct media_pipeline *pipe = entity->pipe;
 
+   if (!pipe)
+   return;
 
WARN_ON(!pipe->streaming_count);
media_entity_graph_walk_start(graph, entity);
-- 
2.7.4



[PATCHv3 2/4] v4l: vsp1: Refactor video pipeline configuration

2016-12-13 Thread Kieran Bingham
With multiple inputs through the BRU it is feasible for the streams to
race each other at stream-on. In the case of the video pipelines, this
can present two serious issues.

 1) A null-dereference if the pipe->dl is committed at the same time as
the vsp1_video_setup_pipeline() is processing

 2) A hardware hang, where a display list is committed without having
called vsp1_video_setup_pipeline() first

Along side these race conditions, the work done by
vsp1_video_setup_pipeline() is undone by the re-initialisation during a
suspend resume cycle, and an active pipeline does not attempt to
reconfigure the correct routing and init parameters for the entities.

To repair all of these issues, we can move the call to a conditional
inside vsp1_video_pipeline_run() and ensure that this can only be called
on the last stream which calls into vsp1_video_start_streaming()

As a convenient side effect of this, by specifying that the
configuration has been lost during suspend/resume actions - the
vsp1_video_pipeline_run() call can re-initialise pipelines when
necessary thus repairing resume actions for active m2m pipelines.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

---
v3:
 - Move 'flag reset' to be inside the vsp1_reset_wpf() function call
 - Tidy up the wpf->pipe reference for the configured flag

 drivers/media/platform/vsp1/vsp1_drv.c   |  4 
 drivers/media/platform/vsp1/vsp1_pipe.c  |  1 +
 drivers/media/platform/vsp1/vsp1_pipe.h  |  2 ++
 drivers/media/platform/vsp1/vsp1_video.c | 20 +---
 4 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drv.c 
b/drivers/media/platform/vsp1/vsp1_drv.c
index 57c713a4e1df..1dc3726c4e83 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -413,6 +413,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
 
 int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index)
 {
+   struct vsp1_rwpf *wpf = vsp1->wpf[index];
unsigned int timeout;
u32 status;
 
@@ -429,6 +430,9 @@ int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int 
index)
usleep_range(1000, 2000);
}
 
+   if (wpf->pipe)
+   wpf->pipe->configured = false;
+
if (!timeout) {
dev_err(vsp1->dev, "failed to reset wpf.%u\n", index);
return -ETIMEDOUT;
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c 
b/drivers/media/platform/vsp1/vsp1_pipe.c
index 756ca4ea7668..7ddf862ee403 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -208,6 +208,7 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
 
INIT_LIST_HEAD(>entities);
pipe->state = VSP1_PIPELINE_STOPPED;
+   pipe->configured = false;
 }
 
 /* Must be called with the pipe irqlock held. */
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index ac4ad261..0743b9fcb655 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -61,6 +61,7 @@ enum vsp1_pipeline_state {
  * @pipe: the media pipeline
  * @irqlock: protects the pipeline state
  * @state: current state
+ * @configured: determines routing configuration active on cell.
  * @wq: wait queue to wait for state change completion
  * @frame_end: frame end interrupt handler
  * @lock: protects the pipeline use count and stream count
@@ -86,6 +87,7 @@ struct vsp1_pipeline {
 
spinlock_t irqlock;
enum vsp1_pipeline_state state;
+   bool configured;
wait_queue_head_t wq;
 
void (*frame_end)(struct vsp1_pipeline *pipe);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index 44b687c0b8df..7ff9f4c19ff0 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -388,6 +388,8 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline 
*pipe)
   VSP1_ENTITY_PARAMS_INIT);
}
 
+   pipe->configured = true;
+
return 0;
 }
 
@@ -411,6 +413,9 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline 
*pipe)
struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
struct vsp1_entity *entity;
 
+   if (!pipe->configured)
+   vsp1_video_setup_pipeline(pipe);
+
if (!pipe->dl)
pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
 
@@ -793,25 +798,18 @@ static int vsp1_video_start_streaming(struct vb2_queue 
*vq, unsigned int count)
struct vsp1_video *video = vb2_get_drv_priv(vq);
struct vsp1_pipeline *pipe = video->rwpf->pipe;
unsigned long flags;
-   int ret;
 
mutex_lock(>lock);
if (pipe->stream_count == pipe->num_inputs)

Re: [PATCHv3 RFC 4/4] media: Catch null pipes on pipeline stop

2016-12-14 Thread Kieran Bingham
Hi Sakari,

On 14/12/16 12:43, Sakari Ailus wrote:
> Hi Kieran,
> 
> On Wed, Dec 14, 2016 at 12:27:37PM +0000, Kieran Bingham wrote:
>> Hi Sakari,
>>
>> On 14/12/16 07:28, Sakari Ailus wrote:
>>> Hi Kieran,
>>>
>>> On Tue, Dec 13, 2016 at 05:59:44PM +, Kieran Bingham wrote:
>>>> media_entity_pipeline_stop() can be called through error paths with a
>>>> NULL entity pipe object. In this instance, stopping is a no-op, so
>>>> simply return without any action
>>>
>>> The approach of returning silently is wrong; the streaming count is indeed a
>>> count: you have to decrement it the exactly same number of times it's been
>>> increased. Code that attempts to call __media_entity_pipeline_stop() on an
>>> entity that's not streaming is simply buggy.
>>
>> Ok, Thanks for the heads up on where to look, as I suspected we are in
>> section B) of my comments below :D
>>
>>> I've got a patch here that adds a warning to graph traversal on streaming
>>> count being zero. I sent a pull request including that some days ago:
>>>
>>> <URL:http://www.spinics.net/lists/linux-media/msg108980.html>
>>> <URL:http://www.spinics.net/lists/linux-media/msg108995.html>
>>
>> Excellent, thanks, I've merged your branch into mine, and I'll
>> investigate where the error is actually coming from.
>>
>> --
>> Ok - so I've merged your patches, (and dropped this patch) but they
>> don't fire any warning before I hit my null-pointer dereference in
>> __media_pipeline_stop(), on the WARN_ON(!pipe->streaming_count);
>>
>> So I think this is a case of calling stop on an invalid entity rather
>> than an unbalanced start/stop somehow:
> 
> Not necessarily. The pipe is set to NULL if the count goes to zero.
> 
> This check should be dropped, it's ill-placed anyway: if streaming count is
> zero the pipe is expected to be NULL anyway in which case you get a NULL
> pointer exception (that you saw there). With the check removed, you should
> get the warning instead.

Ahh, yes, I'd missed the part there that was setting it to NULL.

However, it will still segfault ... (though hopefully after the warning)
as the last line of the function states:

if (!--pipe->streaming_count)
media_entity_graph_walk_cleanup(graph);

So we will hit a null deref on the pipe->streaming_count there, which
still leaves an unbalanced stop as a kernel panic.

In fact, I've just tested removing that WARN_ON(!pipe->streaming_count);
 - it doesn't even get that far - and segfaults in

media_entity_graph_walk_cleanup(graph);

[   80.916558] Unable to handle kernel NULL pointer dereference at
virtual address 0110

[   81.769492] [] media_graph_walk_start+0x20/0xf0
[   81.776615] [] __media_pipeline_stop+0x3c/0xd8
[   81.783644] [] media_pipeline_stop+0x34/0x48
[   81.790505] [] vsp1_du_setup_lif+0x68/0x5a8
[   81.797279] [] rcar_du_vsp_disable+0x2c/0x38
[   81.804137] [] rcar_du_crtc_stop+0x198/0x1e8
[   81.810984] [] rcar_du_crtc_disable+0x20/0x38

due to the fact that 'graph' is dereferenced through the 'pipe'.

{
/* Entity->pipe is NULL, therefore 'graph' is invalid */
struct media_graph *graph = >pipe->graph;
struct media_pipeline *pipe = entity->pipe;

media_graph_walk_start(graph, entity);
...
}

So I suspect we do still need a warning or check in there somewhere.
Something to tell the developer that there is an unbalanced stop, would
be much better than a panic/segfault...

(And of course, we still need to look at the actual unbalanced stop in
vsp1_du_setup_lif!)

--
Kieran


Re: [PATCHv3 RFC 4/4] media: Catch null pipes on pipeline stop

2016-12-14 Thread Kieran Bingham
Hello Me.

Ok, so a bit of investigation into *why* we have an unbalanced
media_pipeline stop call.

After a suspend/resume cycle, the function vsp1_pm_runtime_resume() is
called by the PM framework.

The hardware is unable to reset successfully and the reset call returns
-ETIMEDOUT which gets passed back to the PM framework as a failure and
thus the device is not 'resumed'

This process is commenced, as the DU driver tries to enable the VSP, we
get the following call stack:

rcar_du_crtc_resume()
  rcar_du_vsp_enable()
vsp1_du_setup_lif() // returns void
  vsp1_device_get() // returns -ETIMEDOUT,

As the vsp1_du_setup_lif() returns void, the fact that the hardware
failed to start is ignored.

Later we get a call to  rcar_du_vsp_disable(), which again calls into
vsp1_du_setup_lif(), this time to disable the pipeline. And it is here,
that the call to media_pipeline_stop() is an unbalanced call, as the
corresponding media_pipeline_start() would only have been called if the
vsp1_device_get() had succeeded, thus we find ourselves with a kernel
panic on a null dereference.

Sorry for the terse notes, they are possibly/probably really for me if I
get tasked to look back at this.
--
Regards

Kieran


On 13/12/16 17:59, Kieran Bingham wrote:
> media_entity_pipeline_stop() can be called through error paths with a
> NULL entity pipe object. In this instance, stopping is a no-op, so
> simply return without any action
> 
> Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
> ---
> 
> I've marked this patch as RFC, although if deemed suitable, by all means
> integrate it as is.
> 
> When testing suspend/resume operations on VSP1, I encountered a segfault on 
> the
> WARN_ON(!pipe->streaming_count) line, where 'pipe == NULL'. The simple
> protection fix is to return early in this instance, as this patch does 
> however:
> 
> A) Does this early return path warrant a WARN() statement itself, to identify
> drivers which are incorrectly calling media_entity_pipeline_stop() with an
> invalid entity, or would this just be noise ...
> 
> and therefore..
> 
> B) I also partly assume this patch could simply get NAK'd with a request to go
> and dig out the root cause of calling media_entity_pipeline_stop() with an
> invalid entity. 
> 
> My brief investigation so far here so far shows that it's almost a second 
> order
> fault - where the first suspend resume cycle completes but leaves the entity 
> in
> an invalid state having followed an error path - and then on a second
> suspend/resume - the stop fails with the affected segfault.
> 
> If statement A) or B) apply here, please drop this patch from the series, and
> don't consider it a blocking issue for the other 3 patches.
> 
> Kieran
> 
> 
>  drivers/media/media-entity.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index c68239e60487..93c9cbf4bf46 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -508,6 +508,8 @@ void __media_entity_pipeline_stop(struct media_entity 
> *entity)
>   struct media_entity_graph *graph = >pipe->graph;
>   struct media_pipeline *pipe = entity->pipe;
>  
> + if (!pipe)
> + return;
>  
>   WARN_ON(!pipe->streaming_count);
>   media_entity_graph_walk_start(graph, entity);
> 


Re: [PATCHv3 2/4] v4l: vsp1: Refactor video pipeline configuration

2016-12-15 Thread Kieran Bingham
Hi Laurent,

On 14/12/16 16:30, Laurent Pinchart wrote:
> Hi Kieran,
> 
> Thank you for the patch.
> 
> On Tuesday 13 Dec 2016 17:59:42 Kieran Bingham wrote:
>> With multiple inputs through the BRU it is feasible for the streams to
>> race each other at stream-on.
> 
> Could you please explain the race condition in the commit message ? The issue 
> is that multiple VIDIOC_STREAMON calls racing each other could have process 
> N-1 skipping over the pipeline setup section and then start the pipeline, if 
> videobuf2 has already enqueued buffers to the driver for process N but not 
> called the .start_streaming() operation yet.
> 
>> In the case of the video pipelines, this
>> can present two serious issues.
>>
>>  1) A null-dereference if the pipe->dl is committed at the same time as
>> the vsp1_video_setup_pipeline() is processing
>>
>>  2) A hardware hang, where a display list is committed without having
>> called vsp1_video_setup_pipeline() first
>>
>> Along side these race conditions, the work done by
>> vsp1_video_setup_pipeline() is undone by the re-initialisation during a
>> suspend resume cycle, and an active pipeline does not attempt to
>> reconfigure the correct routing and init parameters for the entities.
>>
>> To repair all of these issues, we can move the call to a conditional
>> inside vsp1_video_pipeline_run() and ensure that this can only be called
>> on the last stream which calls into vsp1_video_start_streaming()
>>
>> As a convenient side effect of this, by specifying that the
>> configuration has been lost during suspend/resume actions - the
>> vsp1_video_pipeline_run() call can re-initialise pipelines when
>> necessary thus repairing resume actions for active m2m pipelines.
>>
>> Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
>>
>> ---
>> v3:
>>  - Move 'flag reset' to be inside the vsp1_reset_wpf() function call
>>  - Tidy up the wpf->pipe reference for the configured flag
>>
>>  drivers/media/platform/vsp1/vsp1_drv.c   |  4 
>>  drivers/media/platform/vsp1/vsp1_pipe.c  |  1 +
>>  drivers/media/platform/vsp1/vsp1_pipe.h  |  2 ++
>>  drivers/media/platform/vsp1/vsp1_video.c | 20 +---
>>  4 files changed, 16 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/media/platform/vsp1/vsp1_drv.c
>> b/drivers/media/platform/vsp1/vsp1_drv.c index 57c713a4e1df..1dc3726c4e83
>> 100644
>> --- a/drivers/media/platform/vsp1/vsp1_drv.c
>> +++ b/drivers/media/platform/vsp1/vsp1_drv.c
>> @@ -413,6 +413,7 @@ static int vsp1_create_entities(struct vsp1_device
>> *vsp1)
>>
>>  int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index)
>>  {
>> +struct vsp1_rwpf *wpf = vsp1->wpf[index];
>>  unsigned int timeout;
>>  u32 status;
>>
>> @@ -429,6 +430,9 @@ int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned
>> int index) usleep_range(1000, 2000);
>>  }
>>
>> +if (wpf->pipe)
>> +wpf->pipe->configured = false;
>> +
>>  if (!timeout) {
>>  dev_err(vsp1->dev, "failed to reset wpf.%u\n", index);
>>  return -ETIMEDOUT;
>> diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c
>> b/drivers/media/platform/vsp1/vsp1_pipe.c index 756ca4ea7668..7ddf862ee403
>> 100644
>> --- a/drivers/media/platform/vsp1/vsp1_pipe.c
>> +++ b/drivers/media/platform/vsp1/vsp1_pipe.c
>> @@ -208,6 +208,7 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
>>
>>  INIT_LIST_HEAD(>entities);
>>  pipe->state = VSP1_PIPELINE_STOPPED;
>> +pipe->configured = false;
>>  }
>>
>>  /* Must be called with the pipe irqlock held. */
>> diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h
>> b/drivers/media/platform/vsp1/vsp1_pipe.h index ac4ad261..0743b9fcb655
>> 100644
>> --- a/drivers/media/platform/vsp1/vsp1_pipe.h
>> +++ b/drivers/media/platform/vsp1/vsp1_pipe.h
>> @@ -61,6 +61,7 @@ enum vsp1_pipeline_state {
>>   * @pipe: the media pipeline
>>   * @irqlock: protects the pipeline state
>>   * @state: current state
>> + * @configured: determines routing configuration active on cell.
> 
> I'm not sure to understand that. How about "true if the pipeline has been set 
> up" ? Or maybe "true if the pipeline has been set up for video streaming" as 
> it only applies to pipelines handled through the V4L2 API ?


Yes, Reading it now - I have no idea what context I was writing that in.
I hope it was

[PATCHv2 1/5] scripts: Test suite runner

2016-12-01 Thread Kieran Bingham
From: Kieran Bingham <kieran.bing...@ideasonboard.com>

Provide a utility script to execute all vsp unit tests, as well
as the option to execute multiple iterations of the suite.

Signed-off-by: Kieran Bingham <kieran.bing...@ideasonboard.com>

---
v2
- remove spurious uses of ';'
- fix output logging

 scripts/vsp-tests.sh | 49 +
 1 file changed, 49 insertions(+)
 create mode 100755 scripts/vsp-tests.sh

diff --git a/scripts/vsp-tests.sh b/scripts/vsp-tests.sh
new file mode 100755
index ..8b21176ccc09
--- /dev/null
+++ b/scripts/vsp-tests.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+##
+## VSP Tests runner
+##
+## Automatically execute all vsp-unit tests
+## Move test failure results to a specific folder for
+## the running kernel version
+##
+## An argument can be provided to specify the number of
+## iterations to perform
+##
+## usage:
+##  ./vsp-tests.sh 
+##
+##   n: Number of iterations to execute test suite
+##
+
+KERNEL_VERSION=`uname -r`
+
+run_test() {
+   echo $1
+   ./$1
+
+   if [ $(ls *.bin 2>/dev/null | wc -l) != 0 ]
+   then
+   RESULTS_DIR=$KERNEL_VERSION/test-$1/$2/
+
+   echo "Moving *.bin to $RESULTS_DIR"
+   mkdir -p $RESULTS_DIR
+   mv *.bin $RESULTS_DIR
+   for f in $RESULTS_DIR/*.bin
+   do
+   ./bin2png.sh "$f"
+   done
+   fi
+}
+
+run_suite() {
+   echo "Test loop $1"
+
+   for test in vsp-unit-test*.sh; do
+   run_test $test $1;
+   done;
+}
+
+for loop in `seq 1 1 $1`; do
+   run_suite $loop
+done;
-- 
2.7.4



[PATCHv2 2/5] scripts: Provide bin2png.sh helper

2016-12-01 Thread Kieran Bingham
From: Kieran Bingham <kieran.bing...@ideasonboard.com>

Identify the size and format from the test output filename, and pass
to raw2rgbpnm for conversion to a PNM file.

>From there we can convert easily to a PNG output file.

Signed-off-by: Kieran Bingham <kieran.bing...@ideasonboard.com>

---
v2:

- use 'convert' to proces png files to png
- strip '.bin' from target filenames

 scripts/Makefile   |  2 +-
 scripts/bin2png.sh | 36 
 2 files changed, 37 insertions(+), 1 deletion(-)
 create mode 100755 scripts/bin2png.sh

diff --git a/scripts/Makefile b/scripts/Makefile
index 8c452f4c54ce..6586b2989aed 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -1,4 +1,4 @@
-SCRIPTS=logger.sh vsp-lib.sh
+SCRIPTS=$(wildcard *.sh)
 
 all:
 
diff --git a/scripts/bin2png.sh b/scripts/bin2png.sh
new file mode 100755
index ..bde1ddfa3eab
--- /dev/null
+++ b/scripts/bin2png.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+FILE="$1"
+
+PNM=$(echo $FILE | sed -e 's|\.bin$|.pnm|')
+PNG=$(echo $FILE | sed -e 's|\.bin$|.png|')
+
+fmt=$(echo $FILE | sed -e 's|.*-\([[:alnum:]]*\)-\([0-9]*x[0-9]*\).*.bin|\1|')
+size=$(echo $FILE | sed -e 's|.*-\([[:alnum:]]*\)-\([0-9]*x[0-9]*\).*.bin|\2|')
+
+case $fmt in
+   yuv410m|yvu410m|yuv411m|yuv420m|yvu420m|yuv422m|yvu422m|yuv444m|yvu444m)
+   fmt=`echo $fmt | tr '[:lower:]' '[:upper:]'`
+   fmt=`echo $fmt | tr 'M' 'P'`
+   ;;
+   nv12m|nv21m|nv16m|nv61m)
+   fmt=`echo $fmt | tr '[:lower:]' '[:upper:]'`
+   fmt=`echo $fmt | tr -d 'M'`
+   ;;
+   argb555|xrgb555)
+   fmt=RGB555X
+   ;;
+   argb32|xrgb32)
+   fmt=RGB32
+   ;;
+   abgr32|xbgr32)
+   fmt=BGR32
+   ;;
+   *)
+   fmt=`echo $fmt | tr '[:lower:]' '[:upper:]'`
+   ;;
+esac
+
+raw2rgbpnm -s $size -f $fmt $FILE $PNM && \
+   convert $PNM $PNG
+rm $PNM
-- 
2.7.4



[PATCHv2 5/5] tests: Test suspend/resume on active pipelines

2016-12-01 Thread Kieran Bingham
From: Kieran Bingham <kieran.bing...@ideasonboard.com>

Provide a test to verify the hardware completes a functional test whilst
performing a suspend resume cycle in parallel. Make use of the
/sys/power/pm_test functionality provided by CONFIG_PM_DEBUG to perform
the testing

Signed-off-by: Kieran Bingham <kieran.bing...@ideasonboard.com>

---
v2:

- removed format iteration loop
- modified test reporting to be once per 'suspend mode'
- verify the pm_test mode is available, or skip

 tests/vsp-unit-test-0020.sh | 97 +
 1 file changed, 97 insertions(+)
 create mode 100755 tests/vsp-unit-test-0020.sh

diff --git a/tests/vsp-unit-test-0020.sh b/tests/vsp-unit-test-0020.sh
new file mode 100755
index ..c9e6b79e5d06
--- /dev/null
+++ b/tests/vsp-unit-test-0020.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+
+#
+# Test power-management suspend/resume whilst pipelines are active
+#
+# Utilise the basic RPF->WPF packing test case as a measure that the hardware
+# is operable while we perform test suspend and resume, and verify that it is
+# still successful even with a suspend resume cycle in the middle of the test.
+#
+
+source vsp-lib.sh
+
+features="rpf.0 wpf.0"
+
+# These can be extracted from /sys/power/pm_test
+suspend_modes="freezer devices platform processors core"
+
+# This extended function performs the same
+# as it's non-extended name-sake - but runs the pipeline
+# for 300 frames. The suspend action occurs between frame #150~#200
+
+test_extended_wpf_packing() {
+   pipe_configure rpf-wpf 0 0
+   format_configure rpf-wpf 0 0 ARGB32 1024x768 $format
+
+   vsp_runner rpf.0 --count=300 &
+   vsp_runner wpf.0 --count=300 --skip=297
+
+   local result=$(compare_frames)
+
+   test_complete $result
+}
+
+test_hw_pipe() {
+   local format
+
+   for format in $formats ; do
+   test_extended_wpf_packing RGB24
+   done
+}
+
+test_suspend_resume() {
+   local result
+   local test_pid
+
+   test_start "Testing active pipeline suspend/resume in suspend:$mode"
+
+   # Verify the test is available
+   grep -q $mode /sys/power/pm_test
+   if [ $? != 0 ]; then
+   test_complete skip
+   return
+   fi
+
+   # Set the hardware running in parallel while we suspend
+   test_hw_pipe &
+   test_pid=$!
+
+   # Make sure the pipeline has time to start
+   sleep 1
+
+   # Set the test mode
+   echo $mode > /sys/power/pm_test
+
+   # Comence suspend
+   # The pm_test framework will automatically resume after 5 seconds
+   echo mem > /sys/power/state
+
+   # Wait for the pipeline to complete
+   wait $test_pid
+   result=$?
+
+   if [ $result == 0 ]; then
+   test_complete pass
+   else
+   test_complete fail
+   fi
+}
+
+test_main() {
+   local mode;
+   local suspend_test_failures
+
+   # Check for pm-suspend test option
+   if [ ! -e /sys/power/pm_test ] ; then
+   echo "$0: Suspend Resume testing requires CONFIG_PM_DEBUG"
+   test_complete skip
+   return
+   fi;
+
+   for mode in $suspend_modes ; do
+   test_suspend_resume $mode
+   done;
+}
+
+test_init $0 "$features"
+test_run
-- 
2.7.4



[PATCHv2 4/5] tests: Test suspend/resume on idle pipelines

2016-12-01 Thread Kieran Bingham
From: Kieran Bingham <kieran.bing...@ideasonboard.com>

Provide a test to verify the hardware is functional both before and
after entering a suspend / resume cycle. Make use of the
/sys/power/pm_test functionality provided by CONFIG_PM_DEBUG to perform
the testing

Signed-off-by: Kieran Bingham <kieran.bing...@ideasonboard.com>

---
v2:

- extended pipeline test to run twice to verify stop->start process
- added return value checking to track test progress
- modified test reporting to be once per 'suspend mode'
- removed trailing ';' uses
- verify the pm_test mode is available, or skip

 tests/vsp-unit-test-0019.sh | 101 
 1 file changed, 101 insertions(+)
 create mode 100755 tests/vsp-unit-test-0019.sh

diff --git a/tests/vsp-unit-test-0019.sh b/tests/vsp-unit-test-0019.sh
new file mode 100755
index ..728dcdda29e6
--- /dev/null
+++ b/tests/vsp-unit-test-0019.sh
@@ -0,0 +1,101 @@
+#!/bin/sh
+
+#
+# Test power-management suspend/resume whilst pipelines are idle
+#
+# Utilise the basic RPF->WPF packing test case as a measure that the hardware
+# is operable while we perform test suspend and resume, and verify that it is
+# still operable after resume.
+#
+# Format iteration loops are maintained, even with only one format so that this
+# test can be easily extended to try further formats if needed in the future.
+#
+
+source vsp-lib.sh
+
+features="rpf.0 wpf.0"
+
+# Two formats are specified so that the test is run twice.
+# This ensures that stop -> start works both before and after suspend
+formats="RGB24 RGB24"
+
+# These can be extracted from /sys/power/pm_test
+suspend_modes="freezer devices platform processors core"
+
+test_wpf_packing() {
+   pipe_configure rpf-wpf 0 0
+   format_configure rpf-wpf 0 0 ARGB32 1024x768 $format
+
+   vsp_runner rpf.0 &
+   vsp_runner wpf.0
+
+   local result=$(compare_frames)
+   [ x$result == xpass ] && return 0 || return 1
+}
+
+test_hw_pipe() {
+   local format
+   local result
+
+   for format in $formats ; do
+   test_wpf_packing $format
+   result=$?
+
+   # return early on failure
+   [ $result != 0 ] && return 1
+   done
+
+   return 0
+}
+
+test_suspend_resume() {
+   local result=0
+
+   test_start "non-active pipeline suspend/resume in suspend:$mode"
+
+   # Verify the test is available
+   grep -q $mode /sys/power/pm_test
+   if [ $? != 0 ]; then
+   test_complete skip
+   return
+   fi
+
+   # Test the hardware each side of suspend resume
+   test_hw_pipe
+   result=$((result+$?))
+
+   # Set the test mode
+   echo $mode > /sys/power/pm_test
+
+   # Comence suspend
+   # The pm_test framework will automatically resume after 5 seconds
+   echo mem > /sys/power/state
+
+   # Verify the hardware is still operational
+   test_hw_pipe
+   result=$((result+$?))
+
+   if [ $result != 0 ]; then
+   test_complete "failed"
+   else
+   test_complete "passed"
+   fi
+}
+
+test_main() {
+   local mode
+
+   # Check for pm-suspend test option
+   if [ ! -e /sys/power/pm_test ] ; then
+   echo "$0: Suspend Resume testing requires CONFIG_PM_DEBUG"
+   test_complete skip
+   return
+   fi
+
+   for mode in $suspend_modes ; do
+   test_suspend_resume $mode
+   done
+}
+
+test_init $0 "$features"
+test_run
-- 
2.7.4



[PATCHv2 3/5] logger: Log to the FTrace buffer if tracing is enabled

2016-12-01 Thread Kieran Bingham
From: Kieran Bingham <kieran.bing...@ideasonboard.com>

Extend the logger such that it will detect the tracing system, and also
append print statement to this ring buffer.

This provides the relevant logging output interspersed in the ftrace
logs for an effective solution to identifying the actions that caused
the traces to occur

Signed-off-by: Kieran Bingham <kieran.bing...@ideasonboard.com>
---
 scripts/logger.sh | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/scripts/logger.sh b/scripts/logger.sh
index 8123f0c9f6e3..8412b0ba9a08 100755
--- a/scripts/logger.sh
+++ b/scripts/logger.sh
@@ -6,6 +6,17 @@ now() {
 
 label=${1:+ [$1]}
 
+TRACE_MARKER=/sys/kernel/debug/tracing/trace_marker
+if [ -e $TRACE_MARKER ]; then
+   extra_log_files=$TRACE_MARKER
+fi
+
 while read line ; do
-   echo "$(now)$label $line"
+   newline="$(now)$label $line"
+
+   echo "$newline"
+
+   for f in $extra_log_files; do
+   echo "$newline" >> $f;
+   done;
 done
-- 
2.7.4



[PATCHv2 0/5] VSP-Tests: Add suspend resume tests and helpers

2016-12-01 Thread Kieran Bingham
From: Kieran Bingham <kieran.bing...@ideasonboard.com>

Following on from previous useful feedback, I have reworked the supporting
scripts and tests.

Provide two tests for suspend/resume cycles. One will verify the VSP1 is
functional with a test before and after a suspend cycle. The other will
maintain an active pipeline which must succeed despite a suspend resume cycle
occuring in the middle of the test.

Along side these tests are a couple of helpers that I have locally and thought
they might be useful to others, so I'm posting for review. A test suite runner
simplifies executing all vsp-unit tests, and provides the ability to easily
repeat the test suite (for example to run an overnight longevity test).

'bin2png.sh' is a wrapper around the existing tools that helps convert the test
files generated by VSP-Tests into png files for easy viewing.

Finally, I have extended 'logger.sh' to also log to the FTrace buffer. As I have
been making greater use of ftrace for register write capture, and driver flow -
this addition helps separate multiple tests from the ftrace kernelshark view.

Kieran Bingham (5):
  scripts: Test suite runner
  scripts: Provide bin2png.sh helper
  logger: Log to the FTrace buffer if tracing is enabled
  tests: Test suspend/resume on idle pipelines
  tests: Test suspend/resume on active pipelines

 scripts/Makefile|   2 +-
 scripts/bin2png.sh  |  36 
 scripts/logger.sh   |  13 +-
 scripts/vsp-tests.sh|  49 +
 tests/vsp-unit-test-0019.sh | 101 
 tests/vsp-unit-test-0020.sh |  97 ++
 6 files changed, 296 insertions(+), 2 deletions(-)
 create mode 100755 scripts/bin2png.sh
 create mode 100755 scripts/vsp-tests.sh
 create mode 100755 tests/vsp-unit-test-0019.sh
 create mode 100755 tests/vsp-unit-test-0020.sh

-- 
2.7.4



[PATCH 1/4] v4l: vsp1: Move vsp1_video_setup_pipeline()

2016-12-06 Thread Kieran Bingham
Move the static vsp1_video_setup_pipeline() function in preparation for
the callee updates so that the vsp1_video_pipeline_run() call can
configure pipelines following suspend resume actions.

This commit is just a code move for clarity performing no functional
change.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 82 
 1 file changed, 41 insertions(+), 41 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index d351b9c768d2..44b687c0b8df 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -350,6 +350,47 @@ static void vsp1_video_frame_end(struct vsp1_pipeline 
*pipe,
pipe->buffers_ready |= 1 << video->pipe_index;
 }
 
+static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
+{
+   struct vsp1_entity *entity;
+
+   /* Determine this pipelines sizes for image partitioning support. */
+   vsp1_video_pipeline_setup_partitions(pipe);
+
+   /* Prepare the display list. */
+   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+   if (!pipe->dl)
+   return -ENOMEM;
+
+   if (pipe->uds) {
+   struct vsp1_uds *uds = to_uds(>uds->subdev);
+
+   /* If a BRU is present in the pipeline before the UDS, the alpha
+* component doesn't need to be scaled as the BRU output alpha
+* value is fixed to 255. Otherwise we need to scale the alpha
+* component only when available at the input RPF.
+*/
+   if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
+   uds->scale_alpha = false;
+   } else {
+   struct vsp1_rwpf *rpf =
+   to_rwpf(>uds_input->subdev);
+
+   uds->scale_alpha = rpf->fmtinfo->alpha;
+   }
+   }
+
+   list_for_each_entry(entity, >entities, list_pipe) {
+   vsp1_entity_route_setup(entity, pipe->dl);
+
+   if (entity->ops->configure)
+   entity->ops->configure(entity, pipe, pipe->dl,
+  VSP1_ENTITY_PARAMS_INIT);
+   }
+
+   return 0;
+}
+
 static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe,
  struct vsp1_dl_list *dl)
 {
@@ -747,47 +788,6 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(>irqlock, flags);
 }
 
-static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
-{
-   struct vsp1_entity *entity;
-
-   /* Determine this pipelines sizes for image partitioning support. */
-   vsp1_video_pipeline_setup_partitions(pipe);
-
-   /* Prepare the display list. */
-   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
-   if (!pipe->dl)
-   return -ENOMEM;
-
-   if (pipe->uds) {
-   struct vsp1_uds *uds = to_uds(>uds->subdev);
-
-   /* If a BRU is present in the pipeline before the UDS, the alpha
-* component doesn't need to be scaled as the BRU output alpha
-* value is fixed to 255. Otherwise we need to scale the alpha
-* component only when available at the input RPF.
-*/
-   if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
-   uds->scale_alpha = false;
-   } else {
-   struct vsp1_rwpf *rpf =
-   to_rwpf(>uds_input->subdev);
-
-   uds->scale_alpha = rpf->fmtinfo->alpha;
-   }
-   }
-
-   list_for_each_entry(entity, >entities, list_pipe) {
-   vsp1_entity_route_setup(entity, pipe->dl);
-
-   if (entity->ops->configure)
-   entity->ops->configure(entity, pipe, pipe->dl,
-  VSP1_ENTITY_PARAMS_INIT);
-   }
-
-   return 0;
-}
-
 static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
struct vsp1_video *video = vb2_get_drv_priv(vq);
-- 
2.7.4



[PATCH 0/4] v4l: vsp1: Fix suspend/resume and race on M2M pipelines

2016-12-06 Thread Kieran Bingham
This small patchset helps rework the VSP1 driver to repair an issue on
suspend/resume operations whereby the pipeline does not get reconfigured after
it has been re-initialised following a resume operation.

Along side this, there was an intrinsic race in the vsp1_video_start_streaming()
function whereby multiple streams operating through a BRU, could find themselves
commencing an operation before the pipeline has been configured, or worse -
commencing, just as the pipeline is being configured resulting in a null pointer
dereference on pipe->dl.

This series superceeds a previous effort to fix the BRU race.

Patch [1/4] is a code move only, with no functional change.
Patch [2/4] refactors the vsp1_video_start_streaming() function and fixes both
suspend/resume, and the BRU race in a single change
Patch [3/4] removes the context scoped 'pipe->dl' which has been susceptible to
races and isn't required to be in the context.
Patch [4/4] is an RFC patch really, that fixes a segfault on error paths  and I
certainly expect feedback and brief discussion. Please drop Patch 4
in the event of any further discussion, and don't consider it as
blocking for the first three patches of this series.

Kieran Bingham (4):
  v4l: vsp1: Move vsp1_video_setup_pipeline()
  v4l: vsp1: Refactor video pipeline configuration
  v4l: vsp1: Use local display lists and remove global pipe->dl
  media: Catch null pipes on pipeline stop

 drivers/media/media-entity.c |   2 +
 drivers/media/platform/vsp1/vsp1_drm.c   |  20 ++---
 drivers/media/platform/vsp1/vsp1_drv.c   |   3 +
 drivers/media/platform/vsp1/vsp1_pipe.c  |   1 +
 drivers/media/platform/vsp1/vsp1_pipe.h  |   4 +-
 drivers/media/platform/vsp1/vsp1_video.c | 127 +++
 6 files changed, 78 insertions(+), 79 deletions(-)

-- 
2.7.4



[PATCH 2/4] v4l: vsp1: Refactor video pipeline configuration

2016-12-06 Thread Kieran Bingham
With multiple inputs through the BRU it is feasible for the streams to
race each other at stream-on. In the case of the video pipelines, this
can present two serious issues.

 1) A null-dereference if the pipe->dl is committed at the same time as
the vsp1_video_setup_pipeline() is processing

 2) A hardware hang, where a display list is committed without having
called vsp1_video_setup_pipeline() first

Along side these race conditions, the work done by
vsp1_video_setup_pipeline() is undone by the re-initialisation during a
suspend resume cycle, and an active pipeline does not attempt to
reconfigure the correct routing and init parameters for the entities.

To repair all of these issues, we can move the call to a conditional
inside vsp1_video_pipeline_run() and ensure that this can only be called
on the last stream which calls into vsp1_video_start_streaming()

As a convenient side effect of this, by specifying that the
configuration has been lost during suspend/resume actions - the
vsp1_video_pipeline_run() call can re-initialise pipelines when
necessary thus repairing resume actions for active m2m pipelines.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drv.c   |  3 +++
 drivers/media/platform/vsp1/vsp1_pipe.c  |  1 +
 drivers/media/platform/vsp1/vsp1_pipe.h  |  2 ++
 drivers/media/platform/vsp1/vsp1_video.c | 20 +---
 4 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drv.c 
b/drivers/media/platform/vsp1/vsp1_drv.c
index 57c713a4e1df..dd26549a6912 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -447,6 +447,9 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
ret = vsp1_reset_wpf(vsp1, i);
if (ret < 0)
return ret;
+
+   if (vsp1->wpf[i] && vsp1->wpf[i]->pipe)
+   vsp1->wpf[i]->pipe->configured = false;
}
 
vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) |
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c 
b/drivers/media/platform/vsp1/vsp1_pipe.c
index 756ca4ea7668..7ddf862ee403 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -208,6 +208,7 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
 
INIT_LIST_HEAD(>entities);
pipe->state = VSP1_PIPELINE_STOPPED;
+   pipe->configured = false;
 }
 
 /* Must be called with the pipe irqlock held. */
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index ac4ad261..0743b9fcb655 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -61,6 +61,7 @@ enum vsp1_pipeline_state {
  * @pipe: the media pipeline
  * @irqlock: protects the pipeline state
  * @state: current state
+ * @configured: determines routing configuration active on cell.
  * @wq: wait queue to wait for state change completion
  * @frame_end: frame end interrupt handler
  * @lock: protects the pipeline use count and stream count
@@ -86,6 +87,7 @@ struct vsp1_pipeline {
 
spinlock_t irqlock;
enum vsp1_pipeline_state state;
+   bool configured;
wait_queue_head_t wq;
 
void (*frame_end)(struct vsp1_pipeline *pipe);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index 44b687c0b8df..7ff9f4c19ff0 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -388,6 +388,8 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline 
*pipe)
   VSP1_ENTITY_PARAMS_INIT);
}
 
+   pipe->configured = true;
+
return 0;
 }
 
@@ -411,6 +413,9 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline 
*pipe)
struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
struct vsp1_entity *entity;
 
+   if (!pipe->configured)
+   vsp1_video_setup_pipeline(pipe);
+
if (!pipe->dl)
pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
 
@@ -793,25 +798,18 @@ static int vsp1_video_start_streaming(struct vb2_queue 
*vq, unsigned int count)
struct vsp1_video *video = vb2_get_drv_priv(vq);
struct vsp1_pipeline *pipe = video->rwpf->pipe;
unsigned long flags;
-   int ret;
 
mutex_lock(>lock);
if (pipe->stream_count == pipe->num_inputs) {
-   ret = vsp1_video_setup_pipeline(pipe);
-   if (ret < 0) {
-   mutex_unlock(>lock);
-   return ret;
-   }
+   spin_lock_irqsave(>irqlock, flags);
+   if (vsp1_pipeline_ready(pipe))
+   vsp1_video_pipeline_run(p

[PATCH 3/4] v4l: vsp1: Use local display lists and remove global pipe->dl

2016-12-06 Thread Kieran Bingham
The usage of pipe->dl is susceptible to races, and it is redundant to
keep this pointer in a larger scoped context.

Now that the calling order of vsp1_video_setup_pipeline() has been
adapted, it is possible to remove the pipe->dl and pass the variable as
required.

Currently the pipe->dl is set during the atomic begin hook, but it is
not utilised until the flush. Moving this should do no harm.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drm.c   | 20 +++---
 drivers/media/platform/vsp1/vsp1_pipe.h  |  2 --
 drivers/media/platform/vsp1/vsp1_video.c | 45 ++--
 3 files changed, 30 insertions(+), 37 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c 
b/drivers/media/platform/vsp1/vsp1_drm.c
index cd209dccff1b..bf735e85b597 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -220,9 +220,6 @@ void vsp1_du_atomic_begin(struct device *dev)
struct vsp1_pipeline *pipe = >drm->pipe;
 
vsp1->drm->num_inputs = pipe->num_inputs;
-
-   /* Prepare the display list. */
-   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
 
@@ -426,10 +423,14 @@ void vsp1_du_atomic_flush(struct device *dev)
struct vsp1_pipeline *pipe = >drm->pipe;
struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
struct vsp1_entity *entity;
+   struct vsp1_dl_list *dl;
unsigned long flags;
unsigned int i;
int ret;
 
+   /* Prepare the display list. */
+   dl = vsp1_dl_list_get(pipe->output->dlm);
+
/* Count the number of enabled inputs and sort them by Z-order. */
pipe->num_inputs = 0;
 
@@ -484,26 +485,25 @@ void vsp1_du_atomic_flush(struct device *dev)
struct vsp1_rwpf *rpf = to_rwpf(>subdev);
 
if (!pipe->inputs[rpf->entity.index]) {
-   vsp1_dl_list_write(pipe->dl, entity->route->reg,
+   vsp1_dl_list_write(dl, entity->route->reg,
   VI6_DPR_NODE_UNUSED);
continue;
}
}
 
-   vsp1_entity_route_setup(entity, pipe->dl);
+   vsp1_entity_route_setup(entity, dl);
 
if (entity->ops->configure) {
-   entity->ops->configure(entity, pipe, pipe->dl,
+   entity->ops->configure(entity, pipe, dl,
   VSP1_ENTITY_PARAMS_INIT);
-   entity->ops->configure(entity, pipe, pipe->dl,
+   entity->ops->configure(entity, pipe, dl,
   VSP1_ENTITY_PARAMS_RUNTIME);
-   entity->ops->configure(entity, pipe, pipe->dl,
+   entity->ops->configure(entity, pipe, dl,
   VSP1_ENTITY_PARAMS_PARTITION);
}
}
 
-   vsp1_dl_list_commit(pipe->dl);
-   pipe->dl = NULL;
+   vsp1_dl_list_commit(dl);
 
/* Start or stop the pipeline if needed. */
if (!vsp1->drm->num_inputs && pipe->num_inputs) {
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index 0743b9fcb655..98980c85081f 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -108,8 +108,6 @@ struct vsp1_pipeline {
 
struct list_head entities;
 
-   struct vsp1_dl_list *dl;
-
unsigned int div_size;
unsigned int partitions;
struct v4l2_rect partition;
diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index 7ff9f4c19ff0..9619ed4dda7c 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -350,18 +350,14 @@ static void vsp1_video_frame_end(struct vsp1_pipeline 
*pipe,
pipe->buffers_ready |= 1 << video->pipe_index;
 }
 
-static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
+static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe,
+struct vsp1_dl_list *dl)
 {
struct vsp1_entity *entity;
 
/* Determine this pipelines sizes for image partitioning support. */
vsp1_video_pipeline_setup_partitions(pipe);
 
-   /* Prepare the display list. */
-   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
-   if (!pipe->dl)
-   return -ENOMEM;
-
if (pipe->uds) {
struct vsp1_uds *uds = to_uds(>uds->subdev);
 
@@ -381,10 +377,10 @@ static

[PATCH RFC 4/4] media: Catch null pipes on pipeline stop

2016-12-06 Thread Kieran Bingham
media_entity_pipeline_stop() can be called through error paths with a
NULL entity pipe object. In this instance, stopping is a no-op, so
simply return without any action

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---

I've marked this patch as RFC, although if deemed suitable, by all means
integrate it as is.

When testing suspend/resume operations on VSP1, I encountered a segfault on the
WARN_ON(!pipe->streaming_count) line, where 'pipe == NULL'. The simple
protection fix is to return early in this instance, as this patch does however:

A) Does this early return path warrant a WARN() statement itself, to identify
drivers which are incorrectly calling media_entity_pipeline_stop() with an
invalid entity, or would this just be noise ...

and therefore..

B) I also partly assume this patch could simply get NAK'd with a request to go
and dig out the root cause of calling media_entity_pipeline_stop() with an
invalid entity. 

My brief investigation so far here so far shows that it's almost a second order
fault - where the first suspend resume cycle completes but leaves the entity in
an invalid state having followed an error path - and then on a second
suspend/resume - the stop fails with the affected segfault.

If statement A) or B) apply here, please drop this patch from the series, and
don't consider it a blocking issue for the other 3 patches.

Kieran


 drivers/media/media-entity.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index c68239e60487..93c9cbf4bf46 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -508,6 +508,8 @@ void __media_entity_pipeline_stop(struct media_entity 
*entity)
struct media_entity_graph *graph = >pipe->graph;
struct media_pipeline *pipe = entity->pipe;
 
+   if (!pipe)
+   return;
 
WARN_ON(!pipe->streaming_count);
media_entity_graph_walk_start(graph, entity);
-- 
2.7.4



Re: [PATCH 11/22] drm: bridge: dw-hdmi: Refactor hdmi_phy_configure resolution parameter

2016-12-04 Thread Kieran Bingham
On 02/12/16 14:18, Russell King - ARM Linux wrote:
> On Fri, Dec 02, 2016 at 01:43:26AM +0200, Laurent Pinchart wrote:
>> From: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
>>
>> The current code hard codes the call of hdmi_phy_configure() to be 8bpp
>> and provides extraneous error checking to verify that this hardcoded
>> value is correct.
>>
>> Simplify the passing of the data by setting the parameter to be of the
>> enum type it represents rather than converting and then verifying the
>> value. This will allow the compiler to check the value is acceptable
>> based on the type, and remove the dead code that we currently have.
> 
> I think you're expecting too much of the compiler there.  There's no
> requirement for the compiler to check that an enum type is passed one
> of it's defined values.
> 
> Try building this and see if it even produces a warning:
> 
> enum foo {
>   FOO_1,
>   FOO_2,
> };
> 
> int func(enum foo foo)
> {
>   return foo;
> }
> 
> int test_1(void)
> {
>   return func(FOO_1);
> }
> 
> int test_2(void)
> {
>   return func(5);
> }
> 

Ahh, yes - Sorry - I appear to have got confused between the effects of
gcc/g++.

I knew I had it in my head that the compiler can do enum-type checking
... but it was from when I was working on  C++ projects.

gcc /tmp/test.c -o /tmp/test


g++ /tmp/test.cpp   -o /tmp/test
/tmp/test.cpp: In function ‘int test_2()’:
/tmp/test.cpp:23:16: error: invalid conversion from ‘int’ to ‘foo’
[-fpermissive]
   return func(5);

C++ will provide type checking on enums, but of course not C.

Sorry for the confusion, and it looks like Laurent is handling this
already, Thanks


Regards
--
Kieran Bingham


Re: [PATCHv3 2/4] v4l: vsp1: Refactor video pipeline configuration

2017-01-06 Thread Kieran Bingham
Hi Laurent,

I've been reworking this series to split things out and adapt for the
comments you've provided, but I have the following queries outstanding:

On 15/12/16 11:50, Kieran Bingham wrote:
> Hi Laurent,
> 
> On 14/12/16 16:30, Laurent Pinchart wrote:
>> Hi Kieran,
>>
>> Thank you for the patch.
>>
>> On Tuesday 13 Dec 2016 17:59:42 Kieran Bingham wrote:
>>> With multiple inputs through the BRU it is feasible for the streams to
>>> race each other at stream-on.
>>
>> Could you please explain the race condition in the commit message ? The 
>> issue 
>> is that multiple VIDIOC_STREAMON calls racing each other could have process 
>> N-1 skipping over the pipeline setup section and then start the pipeline, if 
>> videobuf2 has already enqueued buffers to the driver for process N but not 
>> called the .start_streaming() operation yet.
>>
>>> In the case of the video pipelines, this
>>> can present two serious issues.
>>>
>>>  1) A null-dereference if the pipe->dl is committed at the same time as
>>> the vsp1_video_setup_pipeline() is processing
>>>
>>>  2) A hardware hang, where a display list is committed without having
>>> called vsp1_video_setup_pipeline() first
>>>
>>> Along side these race conditions, the work done by
>>> vsp1_video_setup_pipeline() is undone by the re-initialisation during a
>>> suspend resume cycle, and an active pipeline does not attempt to
>>> reconfigure the correct routing and init parameters for the entities.
>>>
>>> To repair all of these issues, we can move the call to a conditional
>>> inside vsp1_video_pipeline_run() and ensure that this can only be called
>>> on the last stream which calls into vsp1_video_start_streaming()
>>>
>>> As a convenient side effect of this, by specifying that the
>>> configuration has been lost during suspend/resume actions - the
>>> vsp1_video_pipeline_run() call can re-initialise pipelines when
>>> necessary thus repairing resume actions for active m2m pipelines.
>>>
>>> Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
>>>
>>> ---
>>> v3:
>>>  - Move 'flag reset' to be inside the vsp1_reset_wpf() function call
>>>  - Tidy up the wpf->pipe reference for the configured flag
>>>
>>>  drivers/media/platform/vsp1/vsp1_drv.c   |  4 
>>>  drivers/media/platform/vsp1/vsp1_pipe.c  |  1 +
>>>  drivers/media/platform/vsp1/vsp1_pipe.h  |  2 ++
>>>  drivers/media/platform/vsp1/vsp1_video.c | 20 +---
>>>  4 files changed, 16 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/drivers/media/platform/vsp1/vsp1_drv.c
>>> b/drivers/media/platform/vsp1/vsp1_drv.c index 57c713a4e1df..1dc3726c4e83
>>> 100644
>>> --- a/drivers/media/platform/vsp1/vsp1_drv.c
>>> +++ b/drivers/media/platform/vsp1/vsp1_drv.c
>>> @@ -413,6 +413,7 @@ static int vsp1_create_entities(struct vsp1_device
>>> *vsp1)
>>>
>>>  int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index)
>>>  {
>>> +   struct vsp1_rwpf *wpf = vsp1->wpf[index];
>>> unsigned int timeout;
>>> u32 status;
>>>
>>> @@ -429,6 +430,9 @@ int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned
>>> int index) usleep_range(1000, 2000);
>>> }
>>>
>>> +   if (wpf->pipe)
>>> +   wpf->pipe->configured = false;
>>> +
>>> if (!timeout) {
>>> dev_err(vsp1->dev, "failed to reset wpf.%u\n", index);
>>> return -ETIMEDOUT;
>>> diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c
>>> b/drivers/media/platform/vsp1/vsp1_pipe.c index 756ca4ea7668..7ddf862ee403
>>> 100644
>>> --- a/drivers/media/platform/vsp1/vsp1_pipe.c
>>> +++ b/drivers/media/platform/vsp1/vsp1_pipe.c
>>> @@ -208,6 +208,7 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
>>>
>>> INIT_LIST_HEAD(>entities);
>>> pipe->state = VSP1_PIPELINE_STOPPED;
>>> +   pipe->configured = false;
>>>  }
>>>
>>>  /* Must be called with the pipe irqlock held. */
>>> diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h
>>> b/drivers/media/platform/vsp1/vsp1_pipe.h index ac4ad261..0743b9fcb655
>>> 100644
>>> --- a/drivers/media/platform/vsp1/vsp1_pipe.h
>>> +++ b/drivers/media/platform/vsp1/vsp1_pipe.h
>>> @@ -61,6 +61,7 @@ 

[PATCH] media: entity: Catch unbalanced media_pipeline_stop calls

2017-01-03 Thread Kieran Bingham
Drivers must not perform unbalanced calls to stop the entity pipeline,
however if they do they will fault in the core media code, as the
entity->pipe will be set as NULL. We handle this gracefully in the core
with a WARN for the developer.

Replace the erroneous check on zero streaming counts, with a check on
NULL pipe elements instead, as this is the symptom of unbalanced
media_pipeline_stop calls.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/media-entity.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index caa13e6f09f5..cb1fb2c17f85 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -534,8 +534,13 @@ void __media_pipeline_stop(struct media_entity *entity)
struct media_graph *graph = >pipe->graph;
struct media_pipeline *pipe = entity->pipe;
 
+   /*
+* If the following check fails, the driver has performed an
+* unbalanced call to media_pipeline_stop()
+*/
+   if (WARN_ON(!pipe))
+   return;
 
-   WARN_ON(!pipe->streaming_count);
media_graph_walk_start(graph, entity);
 
while ((entity = media_graph_walk_next(graph))) {
-- 
2.7.4



Re: [PATCH] media: entity: Catch unbalanced media_pipeline_stop calls

2017-01-03 Thread Kieran Bingham
On 03/01/17 13:36, Laurent Pinchart wrote:
> Hi Kieran,
> 
> Thank you for the patch.
> 
> On Tuesday 03 Jan 2017 13:12:11 Kieran Bingham wrote:
>> Drivers must not perform unbalanced calls to stop the entity pipeline,
>> however if they do they will fault in the core media code, as the
>> entity->pipe will be set as NULL. We handle this gracefully in the core
>> with a WARN for the developer.
>>
>> Replace the erroneous check on zero streaming counts, with a check on
>> NULL pipe elements instead, as this is the symptom of unbalanced
>> media_pipeline_stop calls.
>>
>> Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
> 
> This looks good to me,
> 
> Acked-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
> 
> I'll let Sakari review and merge the patch.

Ahh, yes - I forgot to mention, although perhaps it will be obvious for
Sakari - but this patch is based on top of Sakari's pending media
pipeline and graph walk cleanup series :D

--
Regards

Kieran

> 
>> ---
>>  drivers/media/media-entity.c | 7 ++-
>>  1 file changed, 6 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
>> index caa13e6f09f5..cb1fb2c17f85 100644
>> --- a/drivers/media/media-entity.c
>> +++ b/drivers/media/media-entity.c
>> @@ -534,8 +534,13 @@ void __media_pipeline_stop(struct media_entity *entity)
>> struct media_graph *graph = >pipe->graph;
>>  struct media_pipeline *pipe = entity->pipe;
>>
>> +/*
>> + * If the following check fails, the driver has performed an
>> + * unbalanced call to media_pipeline_stop()
>> + */
>> +if (WARN_ON(!pipe))
>> +return;
>>
>> -WARN_ON(!pipe->streaming_count);
>>  media_graph_walk_start(graph, entity);
>>
>>  while ((entity = media_graph_walk_next(graph))) {
> 


[PATCH v4 0/4] v4l: vsp1: Fix suspend/resume and race on M2M pipelines

2017-01-06 Thread Kieran Bingham
This small patchset helps rework the VSP1 driver to repair an issue on
suspend/resume operations whereby the pipeline does not get reconfigured after
it has been re-initialised following a resume operation.

Along side this, there was an intrinsic race in the vsp1_video_start_streaming()
function whereby multiple streams operating through a BRU, could find themselves
commencing an operation before the pipeline has been configured, or worse -
commencing, just as the pipeline is being configured resulting in a null pointer
dereference on pipe->dl.

Patch [1/4] fixes the multiple stream BRU race
Patch [2/4] is a code move only, with no functional change.
Patch [3/4] fixes the suspend/resume operations for video pipelines by marking
the new pipe configured flag as false, and configuring the pipe
during the vsp1_video_pipeline_run() call.
Patch [4/4] removes the context scoped 'pipe->dl' from vsp1_drm.c which is only
used in a single function

v4:
 - Rework and separate out the BRU race back to v1 style implementation
 - Split BRU race and Suspend Resume fixes into separate commits.

v3:
 - Move configured=false from vsp1_device_init to vsp1_reset_wpf()
 - Clean up flag dereferencing with a local struct *

v2:
 - Refactor video pipeline configuration implementation to solve both suspend
   resume and the VSP BRU race in a single change

v1:
 - Original pipeline configuration rework

Kieran Bingham (4):
  v4l: vsp1: Prevent multiple streamon race commencing pipeline early
  v4l: vsp1: Move vsp1_video_setup_pipeline()
  v4l: vsp1: Repair suspend resume operations for video pipelines
  v4l: vsp1: Remove redundant pipe->dl usage from drm

 drivers/media/platform/vsp1/vsp1_drm.c   |  20 ++--
 drivers/media/platform/vsp1/vsp1_drv.c   |   4 +-
 drivers/media/platform/vsp1/vsp1_pipe.c  |   1 +-
 drivers/media/platform/vsp1/vsp1_pipe.h  |   4 +-
 drivers/media/platform/vsp1/vsp1_video.c | 133 
 5 files changed, 86 insertions(+), 76 deletions(-)

base-commit: 16b6839d4e6f0c3fe6d5db2b4c90fb39dabc8640
-- 
git-series 0.9.1


[PATCH v4 4/4] v4l: vsp1: Remove redundant pipe->dl usage from drm

2017-01-06 Thread Kieran Bingham
The pipe->dl is used only inside vsp1_du_atomic_flush(), and can be
obtained and stored locally to simplify the code.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drm.c  | 20 ++--
 drivers/media/platform/vsp1/vsp1_pipe.h |  2 --
 2 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c 
b/drivers/media/platform/vsp1/vsp1_drm.c
index b4b583f7137a..d7ec980300dd 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -220,9 +220,6 @@ void vsp1_du_atomic_begin(struct device *dev)
struct vsp1_pipeline *pipe = >drm->pipe;
 
vsp1->drm->num_inputs = pipe->num_inputs;
-
-   /* Prepare the display list. */
-   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
 
@@ -426,10 +423,14 @@ void vsp1_du_atomic_flush(struct device *dev)
struct vsp1_pipeline *pipe = >drm->pipe;
struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
struct vsp1_entity *entity;
+   struct vsp1_dl_list *dl;
unsigned long flags;
unsigned int i;
int ret;
 
+   /* Prepare the display list. */
+   dl = vsp1_dl_list_get(pipe->output->dlm);
+
/* Count the number of enabled inputs and sort them by Z-order. */
pipe->num_inputs = 0;
 
@@ -484,26 +485,25 @@ void vsp1_du_atomic_flush(struct device *dev)
struct vsp1_rwpf *rpf = to_rwpf(>subdev);
 
if (!pipe->inputs[rpf->entity.index]) {
-   vsp1_dl_list_write(pipe->dl, entity->route->reg,
+   vsp1_dl_list_write(dl, entity->route->reg,
   VI6_DPR_NODE_UNUSED);
continue;
}
}
 
-   vsp1_entity_route_setup(entity, pipe->dl);
+   vsp1_entity_route_setup(entity, dl);
 
if (entity->ops->configure) {
-   entity->ops->configure(entity, pipe, pipe->dl,
+   entity->ops->configure(entity, pipe, dl,
   VSP1_ENTITY_PARAMS_INIT);
-   entity->ops->configure(entity, pipe, pipe->dl,
+   entity->ops->configure(entity, pipe, dl,
   VSP1_ENTITY_PARAMS_RUNTIME);
-   entity->ops->configure(entity, pipe, pipe->dl,
+   entity->ops->configure(entity, pipe, dl,
   VSP1_ENTITY_PARAMS_PARTITION);
}
}
 
-   vsp1_dl_list_commit(pipe->dl);
-   pipe->dl = NULL;
+   vsp1_dl_list_commit(dl);
 
/* Start or stop the pipeline if needed. */
if (!vsp1->drm->num_inputs && pipe->num_inputs) {
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index fff122b4874d..e59bef2653f6 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -108,8 +108,6 @@ struct vsp1_pipeline {
 
struct list_head entities;
 
-   struct vsp1_dl_list *dl;
-
unsigned int div_size;
unsigned int partitions;
struct v4l2_rect partition;
-- 
git-series 0.9.1


[PATCH v4 3/4] v4l: vsp1: Repair suspend resume operations for video pipelines

2017-01-06 Thread Kieran Bingham
When a suspend/resume action is taken, the pipeline is reset and never
reconfigured.

To correct this, we establish a new flag pipe->configured and utilise
this to establish when we write a full configuration set to the current
display list.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drv.c   |  4 ++-
 drivers/media/platform/vsp1/vsp1_pipe.c  |  1 +-
 drivers/media/platform/vsp1/vsp1_pipe.h  |  2 +-
 drivers/media/platform/vsp1/vsp1_video.c | 56 ++---
 4 files changed, 31 insertions(+), 32 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drv.c 
b/drivers/media/platform/vsp1/vsp1_drv.c
index aa237b48ad55..d596cdead1c1 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -413,6 +413,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
 
 int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index)
 {
+   struct vsp1_rwpf *wpf = vsp1->wpf[index];
unsigned int timeout;
u32 status;
 
@@ -429,6 +430,9 @@ int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int 
index)
usleep_range(1000, 2000);
}
 
+   if (wpf->pipe)
+   wpf->pipe->configured = false;
+
if (!timeout) {
dev_err(vsp1->dev, "failed to reset wpf.%u\n", index);
return -ETIMEDOUT;
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c 
b/drivers/media/platform/vsp1/vsp1_pipe.c
index 280ba0804699..c568db193fba 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -216,6 +216,7 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
 
INIT_LIST_HEAD(>entities);
pipe->state = VSP1_PIPELINE_STOPPED;
+   pipe->configured = false;
 }
 
 /* Must be called with the pipe irqlock held. */
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index ac4ad261..fff122b4874d 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -61,6 +61,7 @@ enum vsp1_pipeline_state {
  * @pipe: the media pipeline
  * @irqlock: protects the pipeline state
  * @state: current state
+ * @configured: true if the pipeline has been set up for video streaming
  * @wq: wait queue to wait for state change completion
  * @frame_end: frame end interrupt handler
  * @lock: protects the pipeline use count and stream count
@@ -86,6 +87,7 @@ struct vsp1_pipeline {
 
spinlock_t irqlock;
enum vsp1_pipeline_state state;
+   bool configured;
wait_queue_head_t wq;
 
void (*frame_end)(struct vsp1_pipeline *pipe);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index 938ecc2766ed..414303442e7c 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -355,18 +355,14 @@ static void vsp1_video_frame_end(struct vsp1_pipeline 
*pipe,
pipe->buffers_ready |= 1 << video->pipe_index;
 }
 
-static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
+static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe,
+struct vsp1_dl_list *dl)
 {
struct vsp1_entity *entity;
 
/* Determine this pipelines sizes for image partitioning support. */
vsp1_video_pipeline_setup_partitions(pipe);
 
-   /* Prepare the display list. */
-   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
-   if (!pipe->dl)
-   return -ENOMEM;
-
if (pipe->uds) {
struct vsp1_uds *uds = to_uds(>uds->subdev);
 
@@ -386,13 +382,15 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline 
*pipe)
}
 
list_for_each_entry(entity, >entities, list_pipe) {
-   vsp1_entity_route_setup(entity, pipe->dl);
+   vsp1_entity_route_setup(entity, dl);
 
if (entity->ops->configure)
-   entity->ops->configure(entity, pipe, pipe->dl,
+   entity->ops->configure(entity, pipe, dl,
   VSP1_ENTITY_PARAMS_INIT);
}
 
+   pipe->configured = true;
+
return 0;
 }
 
@@ -415,9 +413,16 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline 
*pipe)
 {
struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
struct vsp1_entity *entity;
+   struct vsp1_dl_list *dl;
 
-   if (!pipe->dl)
-   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+   dl = vsp1_dl_list_get(pipe->output->dlm);
+   if (!dl) {
+   dev_err(vsp1->dev, "Failed to obtain a dl list\n");
+   return;
+   }
+
+   if (!pipe->configured)
+   vsp1_video_se

[PATCH v4 1/4] v4l: vsp1: Prevent multiple streamon race commencing pipeline early

2017-01-06 Thread Kieran Bingham
With multiple inputs through the BRU it is feasible for the streams to
race each other at stream-on.

Multiple VIDIOC_STREAMON calls racing each other could have process
N-1 skipping over the pipeline setup section and then start the pipeline
early, if videobuf2 has already enqueued buffers to the driver for
process N but not called the .start_streaming() operation yet

In the case of the video pipelines, this
can present two serious issues.

 1) A null-dereference if the pipe->dl is committed at the same time as
the vsp1_video_setup_pipeline() is processing

 2) A hardware hang, where a display list is committed without having
called vsp1_video_setup_pipeline() first

Repair this issue, by ensuring that only the stream which configures the
pipeline is able to start it.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

---

v4:
 - Revert and rework back to v1 implementation style
 - Provide detailed comments on the race

v3:
 - Move 'flag reset' to be inside the vsp1_reset_wpf() function call
 - Tidy up the wpf->pipe reference for the configured flag

To test this race, I have used the vsp-unit-test-0007.sh from Laurent's
VSP-Tests [0] in iteration. Without this patch, failures can be seen be
seen anywhere up to the 150 iterations mark.

With this patch in place, tests have successfully iterated over 1500
loops.

The function affected by this change appears to have been around since
v4.6-rc2-105-g351bbf99f245 and thus could be included in stable trees
from that point forward. The issue may have been prevalent before that
but the solution would need reworking for earlier version.

[0] http://git.ideasonboard.com/renesas/vsp-tests.git
---
 drivers/media/platform/vsp1/vsp1_video.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index e6592b576ca3..f7dc249eb398 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -797,6 +797,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, 
unsigned int count)
 {
struct vsp1_video *video = vb2_get_drv_priv(vq);
struct vsp1_pipeline *pipe = video->rwpf->pipe;
+   bool start_pipeline = false;
unsigned long flags;
int ret;
 
@@ -807,11 +808,23 @@ static int vsp1_video_start_streaming(struct vb2_queue 
*vq, unsigned int count)
mutex_unlock(>lock);
return ret;
}
+
+   start_pipeline = true;
}
 
pipe->stream_count++;
mutex_unlock(>lock);
 
+   /*
+* vsp1_pipeline_ready() is not sufficient to establish that all streams
+* are prepared and the pipeline is configured, as multiple streams
+* can race through streamon with buffers already queued; Therefore we
+* don't even attempt to start the pipeline until the last stream has
+* called through here.
+*/
+   if (!start_pipeline)
+   return 0;
+
spin_lock_irqsave(>irqlock, flags);
if (vsp1_pipeline_ready(pipe))
vsp1_video_pipeline_run(pipe);
-- 
git-series 0.9.1


[PATCH v4 2/4] v4l: vsp1: Move vsp1_video_setup_pipeline()

2017-01-06 Thread Kieran Bingham
Move the static vsp1_video_setup_pipeline() function in preparation for
the callee updates so that the vsp1_video_pipeline_run() call can
configure pipelines following suspend resume actions.

This commit is just a code move for clarity performing no functional
change.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 82 -
 1 file changed, 41 insertions(+), 41 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index f7dc249eb398..938ecc2766ed 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -355,6 +355,47 @@ static void vsp1_video_frame_end(struct vsp1_pipeline 
*pipe,
pipe->buffers_ready |= 1 << video->pipe_index;
 }
 
+static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
+{
+   struct vsp1_entity *entity;
+
+   /* Determine this pipelines sizes for image partitioning support. */
+   vsp1_video_pipeline_setup_partitions(pipe);
+
+   /* Prepare the display list. */
+   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+   if (!pipe->dl)
+   return -ENOMEM;
+
+   if (pipe->uds) {
+   struct vsp1_uds *uds = to_uds(>uds->subdev);
+
+   /* If a BRU is present in the pipeline before the UDS, the alpha
+* component doesn't need to be scaled as the BRU output alpha
+* value is fixed to 255. Otherwise we need to scale the alpha
+* component only when available at the input RPF.
+*/
+   if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
+   uds->scale_alpha = false;
+   } else {
+   struct vsp1_rwpf *rpf =
+   to_rwpf(>uds_input->subdev);
+
+   uds->scale_alpha = rpf->fmtinfo->alpha;
+   }
+   }
+
+   list_for_each_entry(entity, >entities, list_pipe) {
+   vsp1_entity_route_setup(entity, pipe->dl);
+
+   if (entity->ops->configure)
+   entity->ops->configure(entity, pipe, pipe->dl,
+  VSP1_ENTITY_PARAMS_INIT);
+   }
+
+   return 0;
+}
+
 static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe,
  struct vsp1_dl_list *dl)
 {
@@ -752,47 +793,6 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(>irqlock, flags);
 }
 
-static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
-{
-   struct vsp1_entity *entity;
-
-   /* Determine this pipelines sizes for image partitioning support. */
-   vsp1_video_pipeline_setup_partitions(pipe);
-
-   /* Prepare the display list. */
-   pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
-   if (!pipe->dl)
-   return -ENOMEM;
-
-   if (pipe->uds) {
-   struct vsp1_uds *uds = to_uds(>uds->subdev);
-
-   /* If a BRU is present in the pipeline before the UDS, the alpha
-* component doesn't need to be scaled as the BRU output alpha
-* value is fixed to 255. Otherwise we need to scale the alpha
-* component only when available at the input RPF.
-*/
-   if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
-   uds->scale_alpha = false;
-   } else {
-   struct vsp1_rwpf *rpf =
-   to_rwpf(>uds_input->subdev);
-
-   uds->scale_alpha = rpf->fmtinfo->alpha;
-   }
-   }
-
-   list_for_each_entry(entity, >entities, list_pipe) {
-   vsp1_entity_route_setup(entity, pipe->dl);
-
-   if (entity->ops->configure)
-   entity->ops->configure(entity, pipe, pipe->dl,
-  VSP1_ENTITY_PARAMS_INIT);
-   }
-
-   return 0;
-}
-
 static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
struct vsp1_video *video = vb2_get_drv_priv(vq);
-- 
git-series 0.9.1


Re: [PATCH 1/1] [media] v4l: rcar_fdp1: use %4.4s to format a 4-byte string

2016-12-28 Thread Kieran Bingham
Hi Nicolas,

Thankyou for the patch

This looks like a good catch,

On 26/12/16 13:31, Nicolas Iooss wrote:
> Using %4s to format f->fmt.pix_mp.pixelformat in fdp1_try_fmt() and
> fdp1_s_fmt() may lead to more characters being printed (when the byte
> following field pixelformat is not zero).
> 
> Add ".4" to the format specifier to limit the number of printed
> characters to four. The resulting format specifier "%4.4s" is also used
> by other media drivers to print pixelformat value.
> 
> Signed-off-by: Nicolas Iooss <nicolas.iooss_li...@m4x.org>

Reviewed-by: Kieran Bingham <kie...@bingham.xyz>

> ---
>  drivers/media/platform/rcar_fdp1.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/rcar_fdp1.c 
> b/drivers/media/platform/rcar_fdp1.c
> index 674cc1309b43..42f25d241edd 100644
> --- a/drivers/media/platform/rcar_fdp1.c
> +++ b/drivers/media/platform/rcar_fdp1.c
> @@ -1596,7 +1596,7 @@ static int fdp1_try_fmt(struct file *file, void *priv, 
> struct v4l2_format *f)
>   else
>   fdp1_try_fmt_capture(ctx, NULL, >fmt.pix_mp);
>  
> - dprintk(ctx->fdp1, "Try %s format: %4s (0x%08x) %ux%u field %u\n",
> + dprintk(ctx->fdp1, "Try %s format: %4.4s (0x%08x) %ux%u field %u\n",
>   V4L2_TYPE_IS_OUTPUT(f->type) ? "output" : "capture",
>   (char *)>fmt.pix_mp.pixelformat, f->fmt.pix_mp.pixelformat,
>   f->fmt.pix_mp.width, f->fmt.pix_mp.height, f->fmt.pix_mp.field);
> @@ -1671,7 +1671,7 @@ static int fdp1_s_fmt(struct file *file, void *priv, 
> struct v4l2_format *f)
>  
>   fdp1_set_format(ctx, >fmt.pix_mp, f->type);
>  
> - dprintk(ctx->fdp1, "Set %s format: %4s (0x%08x) %ux%u field %u\n",
> + dprintk(ctx->fdp1, "Set %s format: %4.4s (0x%08x) %ux%u field %u\n",
>       V4L2_TYPE_IS_OUTPUT(f->type) ? "output" : "capture",
>   (char *)>fmt.pix_mp.pixelformat, f->fmt.pix_mp.pixelformat,
>   f->fmt.pix_mp.width, f->fmt.pix_mp.height, f->fmt.pix_mp.field);
> 

-- 
Regards

Kieran Bingham


Re: [RFC PATCH 1/3] v4l: vsp1: Register pipe with output WPF

2017-03-03 Thread Kieran Bingham
Hi Laurent,

Thanks for the review,

On 03/03/17 01:57, Laurent Pinchart wrote:
> Hi Kieran,
> 
> Thank you for the patch.
> 
> On Wednesday 01 Mar 2017 13:12:54 Kieran Bingham wrote:
>> The DRM object does not register the pipe with the WPF object. This is
>> used internally throughout the driver as a means of accessing the pipe.
>> As such this breaks operations which require access to the pipe from WPF
>> interrupts.
>>
>> Register the pipe inside the WPF object after it has been declared as
>> the output.
>>
>> Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
>> ---
>>  drivers/media/platform/vsp1/vsp1_drm.c | 1 +
>>  1 file changed, 1 insertion(+)
>>
>> diff --git a/drivers/media/platform/vsp1/vsp1_drm.c
>> b/drivers/media/platform/vsp1/vsp1_drm.c index cd209dccff1b..8e2aa3f8e52f
>> 100644
>> --- a/drivers/media/platform/vsp1/vsp1_drm.c
>> +++ b/drivers/media/platform/vsp1/vsp1_drm.c
>> @@ -596,6 +596,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
>>  pipe->bru = >bru->entity;
>>  pipe->lif = >lif->entity;
>>  pipe->output = vsp1->wpf[0];
>> +pipe->output->pipe = pipe;
> 
> The vsp1_irq_handler() function calls vsp1_pipeline_frame_end() with wpf-
>> pipe, which is currently NULL. With this patch the function will get a non-
> NULL pipeline and will thus proceed to calling vsp1_dlm_irq_frame_end():
> 
> void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
> {
>   if (pipe == NULL)
>   return;
> 
>   vsp1_dlm_irq_frame_end(pipe->output->dlm);
> 
>   if (pipe->frame_end)
>   pipe->frame_end(pipe);
> 
>   pipe->sequence++;
> }
> 
> pipe->frame_end is NULL, pipe->sequence doesn't matter, but we now end up 
> calling vsp1_dlm_irq_frame_end(). This is a major change regarding display 
> list processing, yet it seems to have no effect at all.

I was a bit surprised at this bit. I had expected vsp1_dlm_irq_frame_end() to be
more critical, but ultimately - it's only job is to handle a race condition on
DL commits which we (presumably) don't hit. At least we don't hit in our testing
more than $(DL_QTY) times, or I believe the display would have hung.

In fact we would have panic'd on a NULL dereference with pipe->dl:
pipe->dl = vsp1_dl_list_get(pipe->output->dlm);

where I don't see any checks on pipe->dl != NULL in the current code paths.

> The following commit is to blame for skipping the call to 
> vsp1_dlm_irq_frame_end().
> 
> commit ff7e97c94d9f7f370fe3ce2a72e85361ca22a605
> Author: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>
> Date:   Tue Jan 19 19:16:36 2016 -0200
> 
> [media] v4l: vsp1: Store pipeline pointer in rwpf
> 
> I've added a few debug print statements to vsp1_dlm_irq_frame_end(), and it 
> looks like we only hit the if (dlm->queued) test or none of them at all. It 
> looks like we've been lucky that nothing broke.
> 
> Restoring the previous behaviour should be safe, but it would be worth it 
> inspecting the code very carefully to make sure the logic is still correct. 
> I'll do it tomorrow if you don't beat me to it.

As far as I can tell it still seems correct. If we had ever hit this race, I
believe we would have leaked the DL, (which is quite a limited resource to us),
which if anything just raises the importance of this fix.

> 
> In any case, how about adding a
> 
> Fixes: ff7e97c94d9f ("[media] v4l: vsp1: Store pipeline pointer in rwpf")

Absolutely.

This seems worthy of a stable backport...? (though not critical)

The breakage was introduced in 4.6...

Should I add a CC: sta...@kernel.org #4.6+

> line ?
> 
>>  return 0;
>>  }
> 

-- 
Regards

Kieran Bingham


[PATCH v2 0/3] RCAR-DU, VSP1: Prevent pre-emptive frame flips on VSP1-DRM pipelines

2017-03-03 Thread Kieran Bingham
The RCAR-DU utilises a running VSPD pipeline to perform processing
for the display pipeline.

Changes to this pipeline are performed with an atomic flush operation which
updates the state in the VSPD. Due to the way the running pipeline is
operated, any flush operation has an implicit latency of one frame interval.

This comes about as the display list is committed, but not updated until the
next VSP1 interrupt. At this point the frame is being processed, but is not
complete until the following VSP1 frame end interrupt.

To prevent reporting page flips early, we must track this timing through the
VSP1, and only allow the rcar-du object to report the page-flip completion
event after the VSP1 has processed.

This series ensures that tearing and flicker is prevented, without introducing 
the
performance impact mentioned in the previous series.

[PATCH 1/3] extends the VSP1 to allow a callback to be registered giving the
VSP1 the ability to notify completion events
[PATCH 2/3] checks for race conditions in the commits of the display list, and
in such event postpones the sending of the completion event
[PATCH 3/3] Utilises the callback extension to send page flips at the end of
VSP processing.

These patches have been tested by introducing artificial delays in the commit
code paths and verifying that no visual tearing or flickering occurs.

Manual start/stop testing has also been performed

Kieran Bingham (3):
  v4l: vsp1: extend VSP1 module API to allow DRM callbacks
  v4l: vsp1: Postpone page flip in event of display list race
  drm: rcar-du: Register a completion callback with VSP1

 drivers/gpu/drm/rcar-du/rcar_du_crtc.c  | 10 +++--
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h  |  2 ++-
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c   | 29 ++-
 drivers/media/platform/vsp1/vsp1_dl.c   |  9 ++--
 drivers/media/platform/vsp1/vsp1_dl.h   |  2 +-
 drivers/media/platform/vsp1/vsp1_drm.c  | 22 -
 drivers/media/platform/vsp1/vsp1_drm.h  | 10 +-
 drivers/media/platform/vsp1/vsp1_pipe.c |  6 -
 drivers/media/platform/vsp1/vsp1_pipe.h |  2 ++-
 include/media/vsp1.h|  3 +++-
 10 files changed, 89 insertions(+), 6 deletions(-)

base-commit: 55e78dfc82988a79773ccca67e121f9a88df81c2
-- 
git-series 0.9.1


[PATCH v2 3/3] drm: rcar-du: Register a completion callback with VSP1

2017-03-03 Thread Kieran Bingham
Currently we process page flip events on every display interrupt,
however this does not take into consideration the processing time needed
by the VSP1 utilised in the pipeline.

Register a callback with the VSP driver to obtain completion events, and
track them so that we only perform page flips when the full display
pipeline has completed for the frame.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

---
v2:
 - Commit message completely re-worded for patch re-work.
 - drm_crtc_handle_vblank() re-instated in event of rcrtc->pending
 - removed passing of unnecessary 'data' through callbacks
 - perform page flips from the VSP completion handler
 - add locking around pending flags

 drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 10 +++--
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  2 ++-
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c  | 29 +++-
 3 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c 
b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 7391dd95c733..b7ff00bb45de 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -299,7 +299,7 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc 
*rcrtc)
  * Page Flip
  */
 
-static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
+void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
 {
struct drm_pending_vblank_event *event;
struct drm_device *dev = rcrtc->crtc.dev;
@@ -328,7 +328,7 @@ static bool rcar_du_crtc_page_flip_pending(struct 
rcar_du_crtc *rcrtc)
bool pending;
 
spin_lock_irqsave(>event_lock, flags);
-   pending = rcrtc->event != NULL;
+   pending = (rcrtc->event != NULL) || (rcrtc->pending);
spin_unlock_irqrestore(>event_lock, flags);
 
return pending;
@@ -579,6 +579,12 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
 
if (status & DSSR_FRM) {
drm_crtc_handle_vblank(>crtc);
+
+   if (rcrtc->pending) {
+   trace_printk("VBlank loss due to VSP Overrun\n");
+   return IRQ_HANDLED;
+   }
+
rcar_du_crtc_finish_page_flip(rcrtc);
ret = IRQ_HANDLED;
}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h 
b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index a7194812997e..b73ec6de7af4 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -47,6 +47,7 @@ struct rcar_du_crtc {
 
struct drm_pending_vblank_event *event;
wait_queue_head_t flip_wait;
+   bool pending;
 
unsigned int outputs;
 
@@ -71,5 +72,6 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc);
 
 void rcar_du_crtc_route_output(struct drm_crtc *crtc,
   enum rcar_du_output output);
+void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc);
 
 #endif /* __RCAR_DU_CRTC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c 
b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index b0ff304ce3dc..1fcd311badb1 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -28,6 +28,22 @@
 #include "rcar_du_kms.h"
 #include "rcar_du_vsp.h"
 
+static void rcar_du_vsp_complete(void *private)
+{
+   struct rcar_du_crtc *crtc = (struct rcar_du_crtc *)private;
+   struct drm_device *dev = crtc->crtc.dev;
+   unsigned long flags;
+   bool pending;
+
+   spin_lock_irqsave(>event_lock, flags);
+   pending = crtc->pending;
+   crtc->pending = false;
+   spin_unlock_irqrestore(>event_lock, flags);
+
+   if (pending)
+   rcar_du_crtc_finish_page_flip(crtc);
+}
+
 void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
 {
const struct drm_display_mode *mode = >crtc.state->adjusted_mode;
@@ -35,6 +51,8 @@ void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
struct vsp1_du_lif_config cfg = {
.width = mode->hdisplay,
.height = mode->vdisplay,
+   .callback = rcar_du_vsp_complete,
+   .callback_data = crtc,
};
struct rcar_du_plane_state state = {
.state = {
@@ -85,6 +103,17 @@ void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc)
 
 void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc)
 {
+   struct drm_device *dev = crtc->crtc.dev;
+   unsigned long flags;
+   bool pending;
+
+   spin_lock_irqsave(>event_lock, flags);
+   pending = crtc->pending;
+   crtc->pending = true;
+   spin_unlock_irqrestore(>event_lock, flags);
+
+   WARN_ON(pending);
+
vsp1_du_atomic_flush(crtc->vsp->vsp);
 }
 
-- 
git-series 0.9.1


[PATCH v2 1/3] v4l: vsp1: extend VSP1 module API to allow DRM callbacks

2017-03-03 Thread Kieran Bingham
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.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@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()
   meaning of any NULL values
 - removed unnecessary 'private data' variables

 drivers/media/platform/vsp1/vsp1_drm.c | 20 
 drivers/media/platform/vsp1/vsp1_drm.h | 10 ++
 include/media/vsp1.h   |  3 +++
 3 files changed, 33 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c 
b/drivers/media/platform/vsp1/vsp1_drm.c
index 7dce55043379..85e5ebca82a5 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -36,6 +36,16 @@ 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_pending) {
+   drm->du_complete(drm->du_private);
+   drm->du_pending = false;
+   }
+}
+
 /* 
-
  * DU Driver API
  */
@@ -95,6 +105,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 +207,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(>output->entity.subdev.entity,
  >pipe);
if (ret < 0) {
@@ -504,6 +522,7 @@ void vsp1_du_atomic_flush(struct device *dev)
 
vsp1_dl_list_commit(pipe->dl);
pipe->dl = NULL;
+   vsp1->drm->du_pending = true;
 
/* Start or stop the pipeline if needed. */
if (!vsp1->drm->num_inputs && pipe->num_inputs) {
@@ -597,6 +616,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
pipe->lif = >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 9e28ab9254ba..3a53e9a60c73 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/vsp1/vsp1_drm.h
@@ -33,8 +33,18 @@ struct vsp1_drm {
struct v4l2_rect compose;
unsigned int zpos;
} inputs[VSP1_MAX_RPF];
+
+   /* Frame syncronisation */
+   void (*du_complete)(void *);
+   void *du_private;
+   bool du_pending;
 };
 
+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 bfc701f04f3f..f6629f19f209 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 *callback_data;
 };
 
 int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config 
*cfg);
-- 
git-series 0.9.1


[PATCH v2 2/3] v4l: vsp1: Postpone page flip in event of display list race

2017-03-03 Thread Kieran Bingham
If we try to commit the display list while an update is pending, we have
missed our opportunity. The display list manager will hold the commit
until the next interrupt.

In this event, we inform the vsp1 completion callback handler so that
the du will not perform a page flip out of turn.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c   |  9 +++--
 drivers/media/platform/vsp1/vsp1_dl.h   |  2 +-
 drivers/media/platform/vsp1/vsp1_drm.c  |  4 +++-
 drivers/media/platform/vsp1/vsp1_pipe.c |  6 +-
 drivers/media/platform/vsp1/vsp1_pipe.h |  2 ++
 5 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
b/drivers/media/platform/vsp1/vsp1_dl.c
index ad545aff4e35..f8e8c90f22bc 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -557,9 +557,10 @@ void vsp1_dlm_irq_display_start(struct vsp1_dl_manager 
*dlm)
spin_unlock(>lock);
 }
 
-void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
+int vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
 {
struct vsp1_device *vsp1 = dlm->vsp1;
+   int ret = 0;
 
spin_lock(>lock);
 
@@ -578,8 +579,10 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
 * before interrupt processing. The hardware hasn't taken the update
 * into account yet, we'll thus skip one frame and retry.
 */
-   if (vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD)
+   if (vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD) {
+   ret = -EBUSY;
goto done;
+   }
 
/* The device starts processing the queued display list right after the
 * frame end interrupt. The display list thus becomes active.
@@ -606,6 +609,8 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
 
 done:
spin_unlock(>lock);
+
+   return ret;
 }
 
 /* Hardware Setup */
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h 
b/drivers/media/platform/vsp1/vsp1_dl.h
index 7131aa3c5978..c772a1d92513 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -28,7 +28,7 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device 
*vsp1,
 void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm);
-void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm);
+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);
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c 
b/drivers/media/platform/vsp1/vsp1_drm.c
index 85e5ebca82a5..6f2dd42ca01b 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -40,10 +40,12 @@ 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_pending) {
+   if (drm->du_complete && drm->du_pending && !pipe->dl_postponed) {
drm->du_complete(drm->du_private);
drm->du_pending = false;
}
+
+   pipe->dl_postponed = false;
 }
 
 /* 
-
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c 
b/drivers/media/platform/vsp1/vsp1_pipe.c
index 280ba0804699..3c5aae8767dd 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -297,10 +297,14 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
 
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
+   int ret;
+
if (pipe == NULL)
return;
 
-   vsp1_dlm_irq_frame_end(pipe->output->dlm);
+   ret = vsp1_dlm_irq_frame_end(pipe->output->dlm);
+   if (ret)
+   pipe->dl_postponed = true;
 
if (pipe->frame_end)
pipe->frame_end(pipe);
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index ac4ad261..65cc8fb76662 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -77,6 +77,7 @@ enum vsp1_pipeline_state {
  * @uds_input: entity at the input of the UDS, if the UDS is present
  * @entities: list of entities in the pipeline
  * @dl: display list associated with the pipeline
+ * @dl_postponed: identifies if the dl commit was caught by a race condition
  * @div_size: The maximum allowed partition size for the pipeline
  * @partitions: The number of partitions used to process one frame
  * @current_partition: The partition number currently being configured
@@ -107,6 +108,7 @@ struct vsp1_pipeline {
struct list_head entit

Re: [PATCH 1/4] v4l: vsp1: Implement partition algorithm restrictions

2017-03-06 Thread Kieran Bingham
Hi Laurent, Morimoto-san,

On 06/03/17 15:16, Laurent Pinchart wrote:
> Hi Morimoto-san,
> 
> On Monday 06 Mar 2017 06:17:47 Kuninori Morimoto wrote:
>> Hi Laurent, Kieran
>>

 I asked it to HW team.
 Please wait
>>
>> I'm still waiting from HW team's response, but can you check
>> "32.3.7 Image partition for VSPI processing" on v0.53 datasheet ?
>> (v0.53 is for ES2.0, but this chapter should be same for ES1.x / ES2.0)
>> You may / may not find something from here
> 
> That's very detailed, good job of the documentation writers ! Please thank 
> them for me if you know who they are :-)
> 
> I'm sure we will find useful information there. Kieran, could you please have 
> a look when you'll be back at the end of this week, and list the points that 
> you think we don't address correctly yet ?
> 

No, I'm afraid I can not. :-D

I have
 R-Car-Gen3-rev0.51e.pdf
and
 R-Car-Gen3-rev0.52E.pdf

Neither of these files has a section
"32.3.7 Image partition for VSPI processing"

If I find a link to a new version of the datasheet in my inbox then I will
certainly consider changing my decision ;-)

--
Regards

Kieran


Re: [PATCH v3 2/3] v4l: vsp1: Extend VSP1 module API to allow DRM callbacks

2017-03-05 Thread Kieran Bingham
Hi Laurent,

On 05/03/17 21:58, Laurent Pinchart wrote:
> Hi Kieran,
> 
> Thank you for the patch.
> 
> On Sunday 05 Mar 2017 16:00:03 Kieran Bingham wrote:
>> 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.
>>
>> Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
>> ---
>>  drivers/media/platform/vsp1/vsp1_drm.c | 17 +
>>  drivers/media/platform/vsp1/vsp1_drm.h | 11 +++
>>  include/media/vsp1.h   | 13 +
>>  3 files changed, 41 insertions(+)
>>
>> diff --git a/drivers/media/platform/vsp1/vsp1_drm.c
>> b/drivers/media/platform/vsp1/vsp1_drm.c index 4ee437c7ff0c..d93bf7d3a39e
>> 100644
>> --- a/drivers/media/platform/vsp1/vsp1_drm.c
>> +++ b/drivers/media/platform/vsp1/vsp1_drm.c
>> @@ -37,6 +37,14 @@ 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);
>> +}
>> +
>>  /* 
>>   * DU Driver API
>>   */
>> @@ -96,6 +104,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);
>> @@ -200,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
> 
> s/framework/driver/
> 
>> + * completion events.
>> + */
>> +vsp1->drm->du_complete = cfg->callback;
>> +vsp1->drm->du_private = cfg->callback_data;
>> +
>>  ret = media_pipeline_start(>output->entity.subdev.entity,
>>>pipe);
>>  if (ret < 0) {
>> @@ -607,6 +623,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
>>  pipe->lif = >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 c8d2f88fc483..3de2095cb0ce
>> 100644
>> --- a/drivers/media/platform/vsp1/vsp1_drm.h
>> +++ b/drivers/media/platform/vsp1/vsp1_drm.h
>> @@ -23,6 +23,8 @@
>>   * @num_inputs: number of active pipeline inputs at the beginning of an
>> update
>>   * @inputs: source crop rectangle, destination compose rectangle and
>> z-order
>>   *  position for every input
>> + * @du_complete: frame completion callback for the DU driver (optional)
>> + * @du_private: data to be passed to the du_complete callback
>>   */
>>  struct vsp1_drm {
>>  struct vsp1_pipeline pipe;
>> @@ -33,8 +35,17 @@ struct vsp1_drm {
>>  struct v4l2_rect compose;
>>  unsigned int zpos;
>>  } inputs[VSP1_MAX_RPF];
>> +
>> +/* Frame syncronisation */
> 
> s/syncronisation/synchronisation/
> 
>> +void (*du_complete)(void *);
>> +void *du_private;
>>  };
>>
>> +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 bfc701f04f3f..d59d0adf560d 100644
>> --- a/include/media/vsp1.h
>> +++ b/include/media/vsp1.h
>> @@ -20,9 +20,22 @@ struct device;
>>
>>  int vsp1_du_init(struct device *dev);
>>
>> +/**
>> + * struct 

[PATCH v3 3/3] drm: rcar-du: Register a completion callback with VSP1

2017-03-05 Thread Kieran Bingham
Currently we process page flip events on every display interrupt,
however this does not take into consideration the processing time needed
by the VSP1 utilised in the pipeline.

Register a callback with the VSP driver to obtain completion events, and
track them so that we only perform page flips when the full display
pipeline has completed for the frame.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c |  8 ++--
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  1 +
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c  |  9 +
 3 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c 
b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 2aceb84fc15d..c1812e20 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -299,7 +299,7 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc 
*rcrtc)
  * Page Flip
  */
 
-static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
+void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
 {
struct drm_pending_vblank_event *event;
struct drm_device *dev = rcrtc->crtc.dev;
@@ -571,6 +571,7 @@ static const struct drm_crtc_funcs crtc_funcs = {
 static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
 {
struct rcar_du_crtc *rcrtc = arg;
+   struct rcar_du_device *rcdu = rcrtc->group->dev;
irqreturn_t ret = IRQ_NONE;
u32 status;
 
@@ -579,7 +580,10 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
 
if (status & DSSR_FRM) {
drm_crtc_handle_vblank(>crtc);
-   rcar_du_crtc_finish_page_flip(rcrtc);
+
+   if (rcdu->info->gen < 3)
+   rcar_du_crtc_finish_page_flip(rcrtc);
+
ret = IRQ_HANDLED;
}
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h 
b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index a7194812997e..ebdbff9d8e59 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -71,5 +71,6 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc);
 
 void rcar_du_crtc_route_output(struct drm_crtc *crtc,
   enum rcar_du_output output);
+void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc);
 
 #endif /* __RCAR_DU_CRTC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c 
b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index b0ff304ce3dc..cbb6f54c99ef 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -28,6 +28,13 @@
 #include "rcar_du_kms.h"
 #include "rcar_du_vsp.h"
 
+static void rcar_du_vsp_complete(void *private)
+{
+   struct rcar_du_crtc *crtc = (struct rcar_du_crtc *)private;
+
+   rcar_du_crtc_finish_page_flip(crtc);
+}
+
 void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
 {
const struct drm_display_mode *mode = >crtc.state->adjusted_mode;
@@ -35,6 +42,8 @@ void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
struct vsp1_du_lif_config cfg = {
.width = mode->hdisplay,
.height = mode->vdisplay,
+   .callback = rcar_du_vsp_complete,
+   .callback_data = crtc,
};
struct rcar_du_plane_state state = {
.state = {
-- 
git-series 0.9.1


[PATCH v3 2/3] v4l: vsp1: Extend VSP1 module API to allow DRM callbacks

2017-03-05 Thread Kieran Bingham
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.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drm.c | 17 +
 drivers/media/platform/vsp1/vsp1_drm.h | 11 +++
 include/media/vsp1.h   | 13 +
 3 files changed, 41 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c 
b/drivers/media/platform/vsp1/vsp1_drm.c
index 4ee437c7ff0c..d93bf7d3a39e 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -37,6 +37,14 @@ 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);
+}
+
 /* 
-
  * DU Driver API
  */
@@ -96,6 +104,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);
@@ -200,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(>output->entity.subdev.entity,
  >pipe);
if (ret < 0) {
@@ -607,6 +623,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
pipe->lif = >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 c8d2f88fc483..3de2095cb0ce 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/vsp1/vsp1_drm.h
@@ -23,6 +23,8 @@
  * @num_inputs: number of active pipeline inputs at the beginning of an update
  * @inputs: source crop rectangle, destination compose rectangle and z-order
  * position for every input
+ * @du_complete: frame completion callback for the DU driver (optional)
+ * @du_private: data to be passed to the du_complete callback
  */
 struct vsp1_drm {
struct vsp1_pipeline pipe;
@@ -33,8 +35,17 @@ struct vsp1_drm {
struct v4l2_rect compose;
unsigned int zpos;
} inputs[VSP1_MAX_RPF];
+
+   /* Frame syncronisation */
+   void (*du_complete)(void *);
+   void *du_private;
 };
 
+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 bfc701f04f3f..d59d0adf560d 100644
--- a/include/media/vsp1.h
+++ b/include/media/vsp1.h
@@ -20,9 +20,22 @@ struct device;
 
 int vsp1_du_init(struct device *dev);
 
+/**
+ * struct vsp1_du_lif_config - VSP LIF configuration
+ * @width: output frame width
+ * @height: output frame height
+ * @callback: frame completion callback function (optional)
+ * @callback_data: data to be passed to the frame completion callback
+ *
+ * When the optional callback is provided to the VSP1, the VSP1 must guarantee
+ * that one completion callback is performed after every vsp1_du_atomic_flush()
+ */
 struct vsp1_du_lif_config {
unsigned int width;
unsigned int height;
+
+   void (*callback)(void *);
+   void *callback_data;
 };
 
 int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config 
*cfg);
-- 
git-series 0.9.1


[PATCH v3 0/3] RCAR-DU, VSP1: Prevent pre-emptive frame flips on VSP1-DRM pipelines

2017-03-05 Thread Kieran Bingham
The RCAR-DU utilises a running VSPD pipeline to perform processing for the
display pipeline. This presents the opportunity for some race conditions to
affect the quality of the display output.

To prevent reporting page flips early, we must track this timing through the
VSP1, and only allow the rcar-du object to report the page-flip completion
event after the VSP1 has processed.

This series ensures that tearing and flicker is prevented, without introducing 
the
performance impact mentioned in the previous series.

[PATCH 1/3] handles potential race conditions in vsp1_dlm_irq_frame_end() and
prevents signalling the frame end in this event.
[PATCH 2/3] extends the VSP1 to allow a callback to be registered giving the
VSP1 the ability to notify completion events.
[PATCH 3/3] utilises the callback extension to send page flips at the end of
VSP processing for Gen3 platforms.

These patches have been tested by introducing artificial delays in the commit
code paths and verifying that no visual tearing or flickering occurs.

Extensive testing around the race window has been performed by dynamically
adapting the artificial delay between 10, and 17 seconds in 100uS increments
for periods of 5 seconds on each delay test. These tests have successfully run
for 3 hours.

Manual start/stop testing has also been performed.

Kieran Bingham (3):
  v4l: vsp1: Postpone frame end handling in event of display list race
  v4l: vsp1: Extend VSP1 module API to allow DRM callbacks
  drm: rcar-du: Register a completion callback with VSP1

 drivers/gpu/drm/rcar-du/rcar_du_crtc.c  |  8 ++--
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h  |  1 +
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c   |  9 +
 drivers/media/platform/vsp1/vsp1_dl.c   | 19 +--
 drivers/media/platform/vsp1/vsp1_dl.h   |  2 +-
 drivers/media/platform/vsp1/vsp1_drm.c  | 17 +
 drivers/media/platform/vsp1/vsp1_drm.h  | 11 +++
 drivers/media/platform/vsp1/vsp1_pipe.c | 13 -
 include/media/vsp1.h| 13 +
 9 files changed, 87 insertions(+), 6 deletions(-)

base-commit: cdb5795cbc4ddbe5082c25c52ebc1d811ac3849e
-- 
git-series 0.9.1


[PATCH v3 1/3] v4l: vsp1: Postpone frame end handling in event of display list race

2017-03-05 Thread Kieran Bingham
If we try to commit the display list while an update is pending, we have
missed our opportunity. The display list manager will hold the commit
until the next interrupt.

In this event, we skip the pipeline completion callback handler so that
the pipeline will not mistakenly report frame completion to the user.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c   | 19 +--
 drivers/media/platform/vsp1/vsp1_dl.h   |  2 +-
 drivers/media/platform/vsp1/vsp1_pipe.c | 13 -
 3 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
b/drivers/media/platform/vsp1/vsp1_dl.c
index b9e5027778ff..f449ca689554 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -562,9 +562,19 @@ void vsp1_dlm_irq_display_start(struct vsp1_dl_manager 
*dlm)
spin_unlock(>lock);
 }
 
-void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
+/**
+ * vsp1_dlm_irq_frame_end - Display list handler for the frame end interrupt
+ * @dlm: the display list manager
+ *
+ * Return true if the previous display list has completed at frame end, or 
false
+ * if it has been delayed by one frame because the display list commit raced
+ * with the frame end interrupt. The function always returns true in header 
mode
+ * as display list processing is then not continuous and races never occur.
+ */
+bool vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
 {
struct vsp1_device *vsp1 = dlm->vsp1;
+   bool completed = false;
 
spin_lock(>lock);
 
@@ -576,8 +586,10 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
 * perform any operation as there can't be any new display list queued
 * in that case.
 */
-   if (dlm->mode == VSP1_DL_MODE_HEADER)
+   if (dlm->mode == VSP1_DL_MODE_HEADER) {
+   completed = true;
goto done;
+   }
 
/*
 * The UPD bit set indicates that the commit operation raced with the
@@ -597,6 +609,7 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
if (dlm->queued) {
dlm->active = dlm->queued;
dlm->queued = NULL;
+   completed = true;
}
 
/*
@@ -619,6 +632,8 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
 
 done:
spin_unlock(>lock);
+
+   return completed;
 }
 
 /* Hardware Setup */
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h 
b/drivers/media/platform/vsp1/vsp1_dl.h
index 7131aa3c5978..6ec1380a10af 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -28,7 +28,7 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device 
*vsp1,
 void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm);
-void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm);
+bool 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);
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c 
b/drivers/media/platform/vsp1/vsp1_pipe.c
index 35364f594e19..d15327701ad8 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -304,10 +304,21 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
 
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
+   bool completed;
+
if (pipe == NULL)
return;
 
-   vsp1_dlm_irq_frame_end(pipe->output->dlm);
+   completed = vsp1_dlm_irq_frame_end(pipe->output->dlm);
+   if (!completed) {
+   /*
+* If the DL commit raced with the frame end interrupt, the
+* commit ends up being postponed by one frame. Return
+* immediately without calling the pipeline's frame end handler
+* or incrementing the sequence number.
+*/
+   return;
+   }
 
if (pipe->frame_end)
pipe->frame_end(pipe);
-- 
git-series 0.9.1


Re: [RFC PATCH 2/3] v4l: vsp1: extend VSP1 module API to allow DRM callback registration

2017-03-03 Thread Kieran Bingham
Hi Laurent,

On 03/03/17 02:11, Laurent Pinchart wrote:
> Hi Kieran,
> 
> Thank you for the patch.
> 
> On Wednesday 01 Mar 2017 13:12:55 Kieran Bingham wrote:
>> 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.
>>
>> To synchronise the page flip events for userspace, we move the required
>> event through the VSP to track the data flow. When the frame is
>> completed, the event can be returned back to the originator through the
>> registered callback.
>>
>> 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.
>>
>> Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
>> ---
>>  drivers/gpu/drm/rcar-du/rcar_du_vsp.c  |  2 +-
>>  drivers/media/platform/vsp1/vsp1_drm.c | 42 +--
>>  drivers/media/platform/vsp1/vsp1_drm.h | 12 -
>>  include/media/vsp1.h   |  6 +++-
>>  4 files changed, 58 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
>> b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c index b5bfbe50bd87..71e70e1e0881
>> 100644
>> --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
>> @@ -81,7 +81,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 8e2aa3f8e52f..743cbce48d0c
>> 100644
>> --- a/drivers/media/platform/vsp1/vsp1_drm.c
>> +++ b/drivers/media/platform/vsp1/vsp1_drm.c
 >> @@ -52,6 +52,40 @@ int vsp1_du_init(struct device *dev)
>>  EXPORT_SYMBOL_GPL(vsp1_du_init);
>>
>>  /**
>> + * vsp1_du_register_callback - Register VSP completion notifier callback
>> + *
>> + * Allow the DRM framework to register a callback with us to notify the end
>> of + * processing each frame. This allows synchronisation for page
>> flipping. + *
>> + * @dev: the VSP device
>> + * @callback: the callback function to notify the DU module
>> + * @private: private structure data to pass with the callback
>> + *
>> + */
>> +void vsp1_du_register_callback(struct device *dev,
>> +   void (*callback)(void *, void *),
>> +   void *private)
>> +{
>> +struct vsp1_device *vsp1 = dev_get_drvdata(dev);
>> +
>> +vsp1->drm->du_complete = callback;
>> +vsp1->drm->du_private = private;
>> +}
>> +EXPORT_SYMBOL_GPL(vsp1_du_register_callback);
> 
> As they're not supposed to change at runtime while the display is running, 
> how 
> about passing the callback and private data pointer to the 
> vsp1_du_setup_lif() 
> function ? Feel free to create a structure for all the parameters passed to 
> the function if you think we'll have too much (which would, as a side effect, 
> made updates to the API easier in the future as changes to the two subsystems 
> will be easier to decouple).

Sure, that's fine. I think a config structure makes sense here.

>> +static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe)
>> +{
>> +struct vsp1_drm *drm = to_vsp1_drm(pipe);
>> +
>> +if (drm->du_complete && drm->active_data)
>> +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;
>> +}
> 
> I would move this function to the "Interrupt Handling" section.

Ack.

>> +/**
>>   * vsp1_du_setup_lif - Setup the output part of the VSP pipeline
>>   * @dev: the VSP device
>>   * @width: output frame width in pixels
>> @@ -99,7 +133,8 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int
>> width, }
>>
>>  pipe->num_inputs = 0;
>> -
>> +pipe->frame_end = NULL;
> 
> You can drop this if ...
> 
>> +vsp1->drm->du_complete = NULL;
>>  vsp1_dlm_reset(pipe->output->dlm);
>>  vsp1_device_put(vsp1);
>>
>> @@

Re: [RFC PATCH 3/3] drm: rcar-du: Register a completion callback with VSP1

2017-03-03 Thread Kieran Bingham
Hi Laurent,

On 03/03/17 02:17, Laurent Pinchart wrote:
> Hi Kieran,
> 
> Thank you for the patch.
> 
> On Wednesday 01 Mar 2017 13:12:56 Kieran Bingham wrote:
>> Updating the state in a running VSP1 requires two interrupts from the
>> VSP. Initially, the updated state will be committed - but only after the
>> VSP1 has completed processing it's current frame will the new state be
>> taken into account. As such, the committed state will only be 'completed'
>> after an extra frame completion interrupt.
>>
>> Track this delay, by passing the frame flip event through the VSP
>> module; It will be returned only when the frame has completed and can be
>> returned to the caller.
> 
> I'll check the interrupt sequence logic tomorrow, it's a bit too late now. 
> Please see below for additional comments.

No worries

> 
>> Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
>> ---
>>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c |  8 +-
>>  drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  1 +-
>>  drivers/gpu/drm/rcar-du/rcar_du_vsp.c  | 34 ++-
>>  3 files changed, 41 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
>> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 7391dd95c733..0a824633a012
>> 100644
>> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
>> @@ -328,7 +328,7 @@ static bool rcar_du_crtc_page_flip_pending(struct
>> rcar_du_crtc *rcrtc) bool pending;
>>
>>  spin_lock_irqsave(>event_lock, flags);
>> -pending = rcrtc->event != NULL;
>> +pending = (rcrtc->event != NULL) || (rcrtc->pending != NULL);
>>  spin_unlock_irqrestore(>event_lock, flags);
>>
>>  return pending;
>> @@ -578,6 +578,12 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
>> rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
>>
>>  if (status & DSSR_FRM) {
>> +
>> +if (rcrtc->pending) {
>> +trace_printk("VBlank loss due to VSP Overrun\n");
>> +return IRQ_HANDLED;
>> +}
>> +
>>  drm_crtc_handle_vblank(>crtc);
>>  rcar_du_crtc_finish_page_flip(rcrtc);
>>  ret = IRQ_HANDLED;
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
>> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index a7194812997e..8374a858446a
>> 100644
>> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
>> @@ -46,6 +46,7 @@ struct rcar_du_crtc {
>>  bool started;
>>
>>  struct drm_pending_vblank_event *event;
>> +struct drm_pending_vblank_event *pending;
>>  wait_queue_head_t flip_wait;
>>
>>  unsigned int outputs;
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
>> b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c index 71e70e1e0881..408375aff1a0
>> 100644
>> --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
>> @@ -28,6 +28,26 @@
>>  #include "rcar_du_kms.h"
>>  #include "rcar_du_vsp.h"
>>
>> +static void rcar_du_vsp_complete(void *private, void *data)
>> +{
>> +struct rcar_du_crtc *crtc = (struct rcar_du_crtc *)private;
>> +struct drm_device *dev = crtc->crtc.dev;
>> +struct drm_pending_vblank_event *event;
>> +bool match;
>> +unsigned long flags;
>> +
>> +spin_lock_irqsave(>event_lock, flags);
>> +event = crtc->event;
>> +crtc->event = data;
>> +match = (crtc->event == crtc->pending);
>> +crtc->pending = NULL;
>> +spin_unlock_irqrestore(>event_lock, flags);
>> +
>> +/* Safety checks */
>> +WARN(event, "Event lost by VSP completion callback\n");
>> +WARN(!match, "Stored pending event, does not match completion\n");
> 
> I understand you want to be safe, and I assume these have never been 
> triggered 
> in your tests. I'd rather replace them by a mechanism that doesn't require 
> passing the event to the VSP driver, and that wouldn't require adding a 
> pending field to the rcar_du_crtc structure. 

Ok - understandable, I started this way - but hit problems, which I think were
unrelated. Anyway, I switched to 'moving' the event so that I could be sure
rcar_du_crtc_finish_page_flip() couldn't have an event to send.

I can switch back to keeping it's 'ownership' in rcar-du.

> Wouldn't adding a WARN_ON(rcrtc-
>> event) in 

[RFC PATCH 3/3] drm: rcar-du: Register a completion callback with VSP1

2017-03-01 Thread Kieran Bingham
Updating the state in a running VSP1 requires two interrupts from the
VSP. Initially, the updated state will be committed - but only after the
VSP1 has completed processing it's current frame will the new state be
taken into account. As such, the committed state will only be 'completed'
after an extra frame completion interrupt.

Track this delay, by passing the frame flip event through the VSP
module; It will be returned only when the frame has completed and can be
returned to the caller.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c |  8 +-
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  1 +-
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c  | 34 ++-
 3 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c 
b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 7391dd95c733..0a824633a012 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -328,7 +328,7 @@ static bool rcar_du_crtc_page_flip_pending(struct 
rcar_du_crtc *rcrtc)
bool pending;
 
spin_lock_irqsave(>event_lock, flags);
-   pending = rcrtc->event != NULL;
+   pending = (rcrtc->event != NULL) || (rcrtc->pending != NULL);
spin_unlock_irqrestore(>event_lock, flags);
 
return pending;
@@ -578,6 +578,12 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
 
if (status & DSSR_FRM) {
+
+   if (rcrtc->pending) {
+   trace_printk("VBlank loss due to VSP Overrun\n");
+   return IRQ_HANDLED;
+   }
+
drm_crtc_handle_vblank(>crtc);
rcar_du_crtc_finish_page_flip(rcrtc);
ret = IRQ_HANDLED;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h 
b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index a7194812997e..8374a858446a 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -46,6 +46,7 @@ struct rcar_du_crtc {
bool started;
 
struct drm_pending_vblank_event *event;
+   struct drm_pending_vblank_event *pending;
wait_queue_head_t flip_wait;
 
unsigned int outputs;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c 
b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index 71e70e1e0881..408375aff1a0 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -28,6 +28,26 @@
 #include "rcar_du_kms.h"
 #include "rcar_du_vsp.h"
 
+static void rcar_du_vsp_complete(void *private, void *data)
+{
+   struct rcar_du_crtc *crtc = (struct rcar_du_crtc *)private;
+   struct drm_device *dev = crtc->crtc.dev;
+   struct drm_pending_vblank_event *event;
+   bool match;
+   unsigned long flags;
+
+   spin_lock_irqsave(>event_lock, flags);
+   event = crtc->event;
+   crtc->event = data;
+   match = (crtc->event == crtc->pending);
+   crtc->pending = NULL;
+   spin_unlock_irqrestore(>event_lock, flags);
+
+   /* Safety checks */
+   WARN(event, "Event lost by VSP completion callback\n");
+   WARN(!match, "Stored pending event, does not match completion\n");
+}
+
 void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
 {
const struct drm_display_mode *mode = >crtc.state->adjusted_mode;
@@ -66,6 +86,8 @@ void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
 */
crtc->group->need_restart = true;
 
+   vsp1_du_register_callback(crtc->vsp->vsp, rcar_du_vsp_complete, crtc);
+
vsp1_du_setup_lif(crtc->vsp->vsp, mode->hdisplay, mode->vdisplay);
 }
 
@@ -81,7 +103,17 @@ 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, NULL);
+   struct drm_device *dev = crtc->crtc.dev;
+   struct drm_pending_vblank_event *event;
+   unsigned long flags;
+
+   /* Move the event to the VSP, track it locally as 'pending' */
+   spin_lock_irqsave(>event_lock, flags);
+   event = crtc->pending = crtc->event;
+   crtc->event = NULL;
+   spin_unlock_irqrestore(>event_lock, flags);
+
+   vsp1_du_atomic_flush(crtc->vsp->vsp, event);
 }
 
 /* Keep the two tables in sync. */
-- 
git-series 0.9.1


[PATCH 2/2] rcar-vin: group: use correct of_node

2017-04-24 Thread Kieran Bingham
From: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

The unbind function dereferences the subdev->dev node to obtain the
of_node. In error paths, the subdev->dev can be set to NULL, whilst the
correct reference to the of_node is available as subdev->of_node.

Correct the dereferencing, and move the variable outside of the loop as
it is constant against the subdev, and not initialised per CSI, for both
the bind and unbind functions

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/rcar-vin/rcar-core.c | 7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/rcar-vin/rcar-core.c 
b/drivers/media/platform/rcar-vin/rcar-core.c
index 48557628e76d..a530dc388b95 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -469,7 +469,7 @@ static int rvin_digital_notify_bound(struct 
v4l2_async_notifier *notifier,
 
v4l2_set_subdev_hostdata(subdev, vin);
 
-   if (vin->digital.asd.match.of.node == subdev->dev->of_node) {
+   if (vin->digital.asd.match.of.node == subdev->of_node) {
/* Find surce and sink pad of remote subdevice */
 
ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE);
@@ -738,12 +738,11 @@ static void rvin_group_notify_unbind(struct 
v4l2_async_notifier *notifier,
 struct v4l2_async_subdev *asd)
 {
struct rvin_dev *vin = notifier_to_vin(notifier);
+   struct device_node *del = subdev->of_node;
unsigned int i;
 
mutex_lock(>group->lock);
for (i = 0; i < RVIN_CSI_MAX; i++) {
-   struct device_node *del = subdev->dev->of_node;
-
if (vin->group->bridge[i].asd.match.of.node == del) {
vin_dbg(vin, "Unbind bridge %s\n", subdev->name);
vin->group->bridge[i].subdev = NULL;
@@ -768,13 +767,13 @@ static int rvin_group_notify_bound(struct 
v4l2_async_notifier *notifier,
   struct v4l2_async_subdev *asd)
 {
struct rvin_dev *vin = notifier_to_vin(notifier);
+   struct device_node *new = subdev->of_node;
unsigned int i;
 
v4l2_set_subdev_hostdata(subdev, vin);
 
mutex_lock(>group->lock);
for (i = 0; i < RVIN_CSI_MAX; i++) {
-   struct device_node *new = subdev->dev->of_node;
 
if (vin->group->bridge[i].asd.match.of.node == new) {
vin_dbg(vin, "Bound bridge %s\n", subdev->name);
-- 
2.7.4



[PATCH 1/2] rcar-vin: Verify pads on linkage

2017-04-24 Thread Kieran Bingham
From: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

The current code determines the pad from the identifiers in the DTB.
This is accepted without bounds in the driver.

Invalid port/reg addresses defined in the DTB will cause a kernel panic
when dereferencing non-existing pads.

Protect the linkage with a check that the pad numbers are valid.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/rcar-vin/rcar-core.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/drivers/media/platform/rcar-vin/rcar-core.c 
b/drivers/media/platform/rcar-vin/rcar-core.c
index 893018963847..48557628e76d 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -613,6 +613,18 @@ static int rvin_group_add_link(struct rvin_dev *vin,
struct media_pad *source_pad, *sink_pad;
int ret = 0;
 
+   if (source_idx >= source->num_pads) {
+   vin_err(vin, "Source pad idx %d is greater than pad count %d\n",
+   source_idx, source->num_pads);
+   return -EINVAL;
+   }
+
+   if (sink_idx >= sink->num_pads) {
+   vin_err(vin, "Sink pad idx %d is greater than pad count %d\n",
+   source_idx, source->num_pads);
+   return -EINVAL;
+   }
+
source_pad = >pads[source_idx];
sink_pad = >pads[sink_idx];
 
-- 
2.7.4



Re: [PATCH v2 11/14] v4l: vsp1: Add support for header display lists in continuous mode

2017-08-02 Thread Kieran Bingham
On 01/08/17 19:47, Laurent Pinchart wrote:
> Hi Kieran,
> 
> On Tuesday 01 Aug 2017 18:35:48 Kieran Bingham wrote:
>> On 26/06/17 19:12, Laurent Pinchart wrote:
>>> The VSP supports both header and headerless display lists. The latter is
>>> easier to use when the VSP feeds data directly to the DU in continuous
>>> mode, and the driver thus uses headerless display lists for DU operation
>>> and header display lists otherwise.
>>>
>>> Headerless display lists are only available on WPF.0. This has never
>>> been an issue so far, as only WPF.0 is connected to the DU. However, on
>>> H3 ES2.0, the VSP-DL instance has both WPF.0 and WPF.1 connected to the
>>> DU. We thus can't use headerless display lists unconditionally for DU
>>> operation.
>>
>> Would it be crazy to suggest we drop headerless display lists?
>>
>> If we must support header display lists in continuous mode - Rather than
>> having 2 cases for continuous modes to support (having to support
>> headerless, on WPF.0, and header on WPF.1) if we just use your header loop
>> trick - would that simplify our code maintenance?
>>
>> (We can always remove headerless support later if you agree, this is more of
>> an idea at the moment)
> 
> I had the exact same thought, but I believe we should wait a few kernel 
> releases to see if the next code is stable before removing the old one. I 
> have 
> a debug patch that forces usage of header display lists unconditionally, and 
> I'll try to develop a few additional stress-tests for that.

Sounds like a good plan.

--
Kieran


[PATCH] media: i2c: adv748x: Store the pixel rate ctrl on CSI objects

2017-08-03 Thread Kieran Bingham
From: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

The current implementation has to search the list of controls for the
pixel rate control, each time it is set.  This can be optimised easily
by storing the ctrl pointer in the CSI/TX object, and referencing that
directly.

While at it, fix up a missing blank line also highlighted in review
comments.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
Small enhancement and fixup as suggested by Sakari, after driver acceptance.

Niklas, with my current 8 Camera set up - I can't fully test this change.
Could you give it a spin if you get chance please?

 drivers/media/i2c/adv748x/adv748x-afe.c  |  1 +
 drivers/media/i2c/adv748x/adv748x-csi2.c | 15 +++
 drivers/media/i2c/adv748x/adv748x.h  |  1 +
 3 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c 
b/drivers/media/i2c/adv748x/adv748x-afe.c
index b33ccfc08708..134d981d69d3 100644
--- a/drivers/media/i2c/adv748x/adv748x-afe.c
+++ b/drivers/media/i2c/adv748x/adv748x-afe.c
@@ -262,6 +262,7 @@ static int adv748x_afe_g_input_status(struct v4l2_subdev 
*sd, u32 *status)
ret = adv748x_afe_status(afe, status, NULL);
 
mutex_unlock(>mutex);
+
return ret;
 }
 
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c 
b/drivers/media/i2c/adv748x/adv748x-csi2.c
index b4fee7f52d6a..609d960c0749 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -223,13 +223,12 @@ static const struct v4l2_subdev_ops adv748x_csi2_ops = {
 
 int adv748x_csi2_set_pixelrate(struct v4l2_subdev *sd, s64 rate)
 {
-   struct v4l2_ctrl *ctrl;
+   struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
 
-   ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
-   if (!ctrl)
+   if (!tx->pixel_rate)
return -EINVAL;
 
-   return v4l2_ctrl_s_ctrl_int64(ctrl, rate);
+   return v4l2_ctrl_s_ctrl_int64(tx->pixel_rate, rate);
 }
 
 static int adv748x_csi2_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -248,12 +247,12 @@ static const struct v4l2_ctrl_ops adv748x_csi2_ctrl_ops = 
{
 
 static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx)
 {
-   struct v4l2_ctrl *ctrl;
-
v4l2_ctrl_handler_init(>ctrl_hdl, 1);
 
-   ctrl = v4l2_ctrl_new_std(>ctrl_hdl, _csi2_ctrl_ops,
-V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
+   tx->pixel_rate = v4l2_ctrl_new_std(>ctrl_hdl,
+  _csi2_ctrl_ops,
+  V4L2_CID_PIXEL_RATE, 1, INT_MAX,
+  1, 1);
 
tx->sd.ctrl_handler = >ctrl_hdl;
if (tx->ctrl_hdl.error) {
diff --git a/drivers/media/i2c/adv748x/adv748x.h 
b/drivers/media/i2c/adv748x/adv748x.h
index cc4151b5b31e..6789e2f3bc8c 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -97,6 +97,7 @@ struct adv748x_csi2 {
 
struct media_pad pads[ADV748X_CSI2_NR_PADS];
struct v4l2_ctrl_handler ctrl_hdl;
+   struct v4l2_ctrl *pixel_rate;
struct v4l2_subdev sd;
 };
 
-- 
2.7.4



Re: [GIT PULL FOR renesas-drivers] Display List Optimizations

2017-08-16 Thread Kieran Bingham
Hi Geert,

>>
>> This series is based upon a merge of my previous pa-improvements/v4 and
>> airlied-drm/drm-next to base on top of all pending VSP1 changes.
> 
> OK, so I'll drop your vsp1/pa-improvements/v2.

That sounds reasonable :D

>>   git://git.kernel.org/pub/scm/linux/kernel/git/kbingham/rcar.git 
>> tags/vsp1/tlb-optimise-v2
>>
>> for you to fetch changes up to fa078611769415d7adbad208f1299d05bee3bda8:
>>
>>   v4l: vsp1: Reduce display list body size (2017-08-14 15:58:38 +0100)
> 
> Thank you, merges cleanly into today's linux-next.

Great thanks!

--
Kieran


[PATCH v2 5/8] v4l: vsp1: Refactor display list configure operations

2017-08-14 Thread Kieran Bingham
The entities provide a single .configure operation which configures the
object into the target display list, based on the vsp1_entity_params
selection.

This restricts us to a single function prototype for both static
configuration (the pre-stream INIT stage) and the dynamic runtime stages
for both each frame - and each partition therein.

Split the configure function into two parts, '.prepare()' and
'.configure()', merging both the VSP1_ENTITY_PARAMS_RUNTIME and
VSP1_ENTITY_PARAMS_PARTITION stages into a single call through the
.configure(). The configuration for individual partitions is handled by
passing the partition number to the configure call, and processing any
runtime stage actions on the first partition only.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c|  12 +-
 drivers/media/platform/vsp1/vsp1_clu.c|  43 +--
 drivers/media/platform/vsp1/vsp1_drm.c|  11 +-
 drivers/media/platform/vsp1/vsp1_entity.c |  15 +-
 drivers/media/platform/vsp1/vsp1_entity.h |  27 +--
 drivers/media/platform/vsp1/vsp1_hgo.c|  12 +-
 drivers/media/platform/vsp1/vsp1_hgt.c|  12 +-
 drivers/media/platform/vsp1/vsp1_hsit.c   |  12 +-
 drivers/media/platform/vsp1/vsp1_lif.c|  12 +-
 drivers/media/platform/vsp1/vsp1_lut.c|  24 +-
 drivers/media/platform/vsp1/vsp1_rpf.c| 162 ++---
 drivers/media/platform/vsp1/vsp1_sru.c|  12 +-
 drivers/media/platform/vsp1/vsp1_uds.c|  55 ++--
 drivers/media/platform/vsp1/vsp1_video.c  |  24 +--
 drivers/media/platform/vsp1/vsp1_wpf.c| 297 ---
 15 files changed, 359 insertions(+), 371 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c 
b/drivers/media/platform/vsp1/vsp1_bru.c
index e8fd2ae3b3eb..b9ff96f76b3e 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -285,19 +285,15 @@ static const struct v4l2_subdev_ops bru_ops = {
  * VSP1 Entity Operations
  */
 
-static void bru_configure(struct vsp1_entity *entity,
- struct vsp1_pipeline *pipe,
- struct vsp1_dl_list *dl,
- enum vsp1_entity_params params)
+static void bru_prepare(struct vsp1_entity *entity,
+   struct vsp1_pipeline *pipe,
+   struct vsp1_dl_list *dl)
 {
struct vsp1_bru *bru = to_bru(>subdev);
struct v4l2_mbus_framefmt *format;
unsigned int flags;
unsigned int i;
 
-   if (params != VSP1_ENTITY_PARAMS_INIT)
-   return;
-
format = vsp1_entity_get_pad_format(>entity, bru->entity.config,
bru->entity.source_pad);
 
@@ -404,7 +400,7 @@ static void bru_configure(struct vsp1_entity *entity,
 }
 
 static const struct vsp1_entity_operations bru_entity_ops = {
-   .configure = bru_configure,
+   .prepare = bru_prepare,
 };
 
 /* 
-
diff --git a/drivers/media/platform/vsp1/vsp1_clu.c 
b/drivers/media/platform/vsp1/vsp1_clu.c
index 175717018e11..5f65ce3ad97f 100644
--- a/drivers/media/platform/vsp1/vsp1_clu.c
+++ b/drivers/media/platform/vsp1/vsp1_clu.c
@@ -213,37 +213,37 @@ static const struct v4l2_subdev_ops clu_ops = {
 /* 
-
  * VSP1 Entity Operations
  */
+static void clu_prepare(struct vsp1_entity *entity,
+   struct vsp1_pipeline *pipe,
+   struct vsp1_dl_list *dl)
+{
+   struct vsp1_clu *clu = to_clu(>subdev);
+
+   /*
+* The format can't be changed during streaming, only verify it
+* at setup time and store the information internally for future
+* runtime configuration calls.
+*/
+   struct v4l2_mbus_framefmt *format;
+
+   format = vsp1_entity_get_pad_format(>entity,
+   clu->entity.config,
+   CLU_PAD_SINK);
+   clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32;
+}
 
 static void clu_configure(struct vsp1_entity *entity,
  struct vsp1_pipeline *pipe,
  struct vsp1_dl_list *dl,
- enum vsp1_entity_params params)
+ unsigned int partition)
 {
struct vsp1_clu *clu = to_clu(>subdev);
struct vsp1_dl_body *dlb;
unsigned long flags;
u32 ctrl = VI6_CLU_CTRL_AAI | VI6_CLU_CTRL_MVS | VI6_CLU_CTRL_EN;
 
-   switch (params) {
-   case VSP1_ENTITY_PARAMS_INIT: {
-   /*
-* The format can't be changed during streaming, only verify it
-* at setup time and store the information internally for future
-* runtime configuration calls.
-*/
-

[PATCH v2 8/8] v4l: vsp1: Reduce display list body size

2017-08-14 Thread Kieran Bingham
The display list originally allocated a body of 256 entries to store all
of the register lists required for each frame.

This has now been separated into fragments for constant stream setup, and
runtime updates.

Empirical testing shows that the body0 now uses a maximum of 41
registers for each frame, for both DRM and Video API pipelines thus a
rounded 64 entries provides a suitable allocation.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
b/drivers/media/platform/vsp1/vsp1_dl.c
index 176a258146ac..b3f5eb2f9a4f 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -21,7 +21,7 @@
 #include "vsp1.h"
 #include "vsp1_dl.h"
 
-#define VSP1_DL_NUM_ENTRIES256
+#define VSP1_DL_NUM_ENTRIES64
 
 #define VSP1_DLH_INT_ENABLE(1 << 1)
 #define VSP1_DLH_AUTO_START(1 << 0)
-- 
git-series 0.9.1


[PATCH v2 4/8] v4l: vsp1: Use reference counting for fragments

2017-08-14 Thread Kieran Bingham
Extend the display list body with a reference count, allowing bodies to
be kept as long as a reference is maintained. This provides the ability
to keep a cached copy of bodies which will not change, so that they can
be re-applied to multiple display lists.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

---
This could be squashed into the fragment update code, but it's not a
straightforward squash as the refcounts will affect both:
  v4l: vsp1: Provide a fragment pool
and
  v4l: vsp1: Convert display lists to use new fragment pool
therefore, I have kept this separate to prevent breaking bisectability
of the vsp-tests.
---
 drivers/media/platform/vsp1/vsp1_clu.c |  7 ++-
 drivers/media/platform/vsp1/vsp1_dl.c  | 15 ++-
 drivers/media/platform/vsp1/vsp1_lut.c |  7 ++-
 3 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_clu.c 
b/drivers/media/platform/vsp1/vsp1_clu.c
index 52c523625e2f..175717018e11 100644
--- a/drivers/media/platform/vsp1/vsp1_clu.c
+++ b/drivers/media/platform/vsp1/vsp1_clu.c
@@ -257,8 +257,13 @@ static void clu_configure(struct vsp1_entity *entity,
clu->clu = NULL;
spin_unlock_irqrestore(>lock, flags);
 
-   if (dlb)
+   if (dlb) {
vsp1_dl_list_add_fragment(dl, dlb);
+
+   /* release our local reference */
+   vsp1_dl_fragment_put(dlb);
+   }
+
break;
}
 }
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
b/drivers/media/platform/vsp1/vsp1_dl.c
index 6ffdc3549283..37feda248946 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -58,6 +59,8 @@ struct vsp1_dl_body {
struct list_head list;
struct list_head free;
 
+   refcount_t refcnt;
+
struct vsp1_dl_fragment_pool *pool;
struct vsp1_device *vsp1;
 
@@ -230,6 +233,7 @@ struct vsp1_dl_body *vsp1_dl_fragment_get(struct 
vsp1_dl_fragment_pool *pool)
if (!list_empty(>free)) {
dlb = list_first_entry(>free, struct vsp1_dl_body, free);
list_del(>free);
+   refcount_set(>refcnt, 1);
}
 
spin_unlock_irqrestore(>lock, flags);
@@ -244,6 +248,9 @@ void vsp1_dl_fragment_put(struct vsp1_dl_body *dlb)
if (!dlb)
return;
 
+   if (!refcount_dec_and_test(>refcnt))
+   return;
+
dlb->num_entries = 0;
 
spin_lock_irqsave(>pool->lock, flags);
@@ -428,7 +435,11 @@ void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, 
u32 data)
  * list, in the order in which fragments are added.
  *
  * Adding a fragment to a display list passes ownership of the fragment to the
- * list. The caller must not touch the fragment after this call.
+ * list. The caller must not modify the fragment after this call, but can 
retain
+ * a reference to it for future use if necessary, to add to subsequent lists.
+ *
+ * The reference count of the body is incremented by this attachment, and thus
+ * the caller should release it's reference if does not want to cache the body.
  *
  * Fragments are only usable for display lists in header mode. Attempt to
  * add a fragment to a header-less display list will return an error.
@@ -440,6 +451,8 @@ int vsp1_dl_list_add_fragment(struct vsp1_dl_list *dl,
if (dl->dlm->mode != VSP1_DL_MODE_HEADER)
return -EINVAL;
 
+   refcount_inc(>refcnt);
+
list_add_tail(>list, >fragments);
return 0;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c 
b/drivers/media/platform/vsp1/vsp1_lut.c
index 57482e057e54..388bd89ade0b 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -213,8 +213,13 @@ static void lut_configure(struct vsp1_entity *entity,
lut->lut = NULL;
spin_unlock_irqrestore(>lock, flags);
 
-   if (dlb)
+   if (dlb) {
vsp1_dl_list_add_fragment(dl, dlb);
+
+   /* release our local reference */
+   vsp1_dl_fragment_put(dlb);
+   }
+
break;
}
 }
-- 
git-series 0.9.1


[PATCH v2 6/8] v4l: vsp1: Adapt entities to configure into a body

2017-08-14 Thread Kieran Bingham
Currently the entities store their configurations into a display list.
Adapt this such that the code can be configured into a body fragment
directly, allowing greater flexibility and control of the content.

All users of vsp1_dl_list_write() are removed in this process, thus it
too is removed.

A helper, vsp1_dl_list_body() is provided to access the internal body0
from the display list.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c| 22 ++--
 drivers/media/platform/vsp1/vsp1_clu.c| 22 ++--
 drivers/media/platform/vsp1/vsp1_dl.c | 12 ++-
 drivers/media/platform/vsp1/vsp1_dl.h |  2 +-
 drivers/media/platform/vsp1/vsp1_drm.c| 14 +---
 drivers/media/platform/vsp1/vsp1_entity.c | 16 -
 drivers/media/platform/vsp1/vsp1_entity.h | 12 ---
 drivers/media/platform/vsp1/vsp1_hgo.c| 16 -
 drivers/media/platform/vsp1/vsp1_hgt.c| 18 +-
 drivers/media/platform/vsp1/vsp1_hsit.c   | 10 +++---
 drivers/media/platform/vsp1/vsp1_lif.c| 13 +++
 drivers/media/platform/vsp1/vsp1_lut.c| 21 ++--
 drivers/media/platform/vsp1/vsp1_pipe.c   |  4 +-
 drivers/media/platform/vsp1/vsp1_pipe.h   |  3 +-
 drivers/media/platform/vsp1/vsp1_rpf.c| 43 +++-
 drivers/media/platform/vsp1/vsp1_sru.c| 14 
 drivers/media/platform/vsp1/vsp1_uds.c| 24 +++--
 drivers/media/platform/vsp1/vsp1_uds.h|  2 +-
 drivers/media/platform/vsp1/vsp1_video.c  | 11 --
 drivers/media/platform/vsp1/vsp1_wpf.c| 42 ---
 20 files changed, 168 insertions(+), 153 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c 
b/drivers/media/platform/vsp1/vsp1_bru.c
index b9ff96f76b3e..652b42e3ec2d 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -30,10 +30,10 @@
  * Device Access
  */
 
-static inline void vsp1_bru_write(struct vsp1_bru *bru, struct vsp1_dl_list 
*dl,
- u32 reg, u32 data)
+static inline void vsp1_bru_write(struct vsp1_bru *bru,
+ struct vsp1_dl_body *dlb, u32 reg, u32 data)
 {
-   vsp1_dl_list_write(dl, bru->base + reg, data);
+   vsp1_dl_fragment_write(dlb, bru->base + reg, data);
 }
 
 /* 
-
@@ -287,7 +287,7 @@ static const struct v4l2_subdev_ops bru_ops = {
 
 static void bru_prepare(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
-   struct vsp1_dl_list *dl)
+   struct vsp1_dl_body *dlb)
 {
struct vsp1_bru *bru = to_bru(>subdev);
struct v4l2_mbus_framefmt *format;
@@ -309,7 +309,7 @@ static void bru_prepare(struct vsp1_entity *entity,
 * format at the pipeline output is premultiplied.
 */
flags = pipe->output ? pipe->output->format.flags : 0;
-   vsp1_bru_write(bru, dl, VI6_BRU_INCTRL,
+   vsp1_bru_write(bru, dlb, VI6_BRU_INCTRL,
   flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
   0 : VI6_BRU_INCTRL_NRM);
 
@@ -317,12 +317,12 @@ static void bru_prepare(struct vsp1_entity *entity,
 * Set the background position to cover the whole output image and
 * configure its color.
 */
-   vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_SIZE,
+   vsp1_bru_write(bru, dlb, VI6_BRU_VIRRPF_SIZE,
   (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
   (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
-   vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_LOC, 0);
+   vsp1_bru_write(bru, dlb, VI6_BRU_VIRRPF_LOC, 0);
 
-   vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_COL, bru->bgcolor |
+   vsp1_bru_write(bru, dlb, VI6_BRU_VIRRPF_COL, bru->bgcolor |
   (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
 
/*
@@ -332,7 +332,7 @@ static void bru_prepare(struct vsp1_entity *entity,
 * unit.
 */
if (entity->type == VSP1_ENTITY_BRU)
-   vsp1_bru_write(bru, dl, VI6_BRU_ROP,
+   vsp1_bru_write(bru, dlb, VI6_BRU_ROP,
   VI6_BRU_ROP_DSTSEL_BRUIN(1) |
   VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
   VI6_BRU_ROP_AROP(VI6_ROP_NOP));
@@ -374,7 +374,7 @@ static void bru_prepare(struct vsp1_entity *entity,
if (!(entity->type == VSP1_ENTITY_BRU && i == 1))
ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
 
-   vsp1_bru_write(bru, dl, VI6_BRU_CTRL(i), ctrl);
+   vsp1_bru_write(bru, dlb, VI6_BRU_CTRL(i), ctrl);
 
/*
 * Harcode the blending formula to
@@ -389,7 +389,7 @@ static void bru_prepare(str

[PATCH v2 7/8] v4l: vsp1: Move video configuration to a cached dlb

2017-08-14 Thread Kieran Bingham
We are now able to configure a pipeline directly into a local display
list body. Take advantage of this fact, and create a cacheable body to
store the configuration of the pipeline in the video object.

vsp1_video_pipeline_run() is now the last user of the pipe->dl object.
Convert this function to use the cached video->config body and obtain a
local display list reference.

Attach the video->config body to the display list when needed before
committing to hardware.

The pipe object is marked as un-configured when entering a suspend. This
ensures that upon resume, where the hardware is reset - our cached
configuration will be re-attached to the next committed DL.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---

Our video DL usage now looks like the below output:

dl->body0 contains our disposable runtime configuration. Max 41.
dl_child->body0 is our partition specific configuration. Max 12.
dl->fragments shows our constant configuration and LUTs.

  These two are LUT/CLU:
 * dl->fragments[x]->num_entries 256 / max 256
 * dl->fragments[x]->num_entries 4914 / max 4914

Which shows that our 'constant' configuration cache is currently
utilised to a maximum of 64 entries.

trace-cmd report | \
grep max | sed 's/.*vsp1_dl_list_commit://g' | sort | uniq;

  dl->body0->num_entries 13 / max 128
  dl->body0->num_entries 14 / max 128
  dl->body0->num_entries 16 / max 128
  dl->body0->num_entries 20 / max 128
  dl->body0->num_entries 27 / max 128
  dl->body0->num_entries 34 / max 128
  dl->body0->num_entries 41 / max 128
  dl_child->body0->num_entries 10 / max 128
  dl_child->body0->num_entries 12 / max 128
  dl->fragments[x]->num_entries 15 / max 128
  dl->fragments[x]->num_entries 16 / max 128
  dl->fragments[x]->num_entries 17 / max 128
  dl->fragments[x]->num_entries 18 / max 128
  dl->fragments[x]->num_entries 20 / max 128
  dl->fragments[x]->num_entries 21 / max 128
  dl->fragments[x]->num_entries 256 / max 256
  dl->fragments[x]->num_entries 31 / max 128
  dl->fragments[x]->num_entries 32 / max 128
  dl->fragments[x]->num_entries 39 / max 128
  dl->fragments[x]->num_entries 40 / max 128
  dl->fragments[x]->num_entries 47 / max 128
  dl->fragments[x]->num_entries 48 / max 128
  dl->fragments[x]->num_entries 4914 / max 4914
  dl->fragments[x]->num_entries 55 / max 128
  dl->fragments[x]->num_entries 56 / max 128
  dl->fragments[x]->num_entries 63 / max 128
  dl->fragments[x]->num_entries 64 / max 128
---
 drivers/media/platform/vsp1/vsp1_pipe.c  |  4 +-
 drivers/media/platform/vsp1/vsp1_pipe.h  |  4 +-
 drivers/media/platform/vsp1/vsp1_video.c | 67 -
 drivers/media/platform/vsp1/vsp1_video.h |  2 +-
 4 files changed, 51 insertions(+), 26 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c 
b/drivers/media/platform/vsp1/vsp1_pipe.c
index 5012643583b6..7d1f7ba43060 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -249,6 +249,7 @@ void vsp1_pipeline_run(struct vsp1_pipeline *pipe)
vsp1_write(vsp1, VI6_CMD(pipe->output->entity.index),
   VI6_CMD_STRCMD);
pipe->state = VSP1_PIPELINE_RUNNING;
+   pipe->configured = true;
}
 
pipe->buffers_ready = 0;
@@ -430,6 +431,9 @@ void vsp1_pipelines_suspend(struct vsp1_device *vsp1)
spin_lock_irqsave(>irqlock, flags);
if (pipe->state == VSP1_PIPELINE_RUNNING)
pipe->state = VSP1_PIPELINE_STOPPING;
+
+   /* After a suspend, the hardware will be reset */
+   pipe->configured = false;
spin_unlock_irqrestore(>irqlock, flags);
}
 
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index 90d29492b9b9..e7ad6211b4d0 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -90,6 +90,7 @@ struct vsp1_partition {
  * @irqlock: protects the pipeline state
  * @state: current state
  * @wq: wait queue to wait for state change completion
+ * @configured: flag determining if the hardware has run since reset
  * @frame_end: frame end interrupt handler
  * @lock: protects the pipeline use count and stream count
  * @kref: pipeline reference count
@@ -117,6 +118,7 @@ struct vsp1_pipeline {
spinlock_t irqlock;
enum vsp1_pipeline_state state;
wait_queue_head_t wq;
+   bool configured;
 
void (*frame_end)(struct vsp1_pipeline *pipe, bool completed);
 
@@ -143,8 +145,6 @@ struct vsp1_pipeline {
 */
struct list_head entities;
 
-   struct vsp1_dl_list *dl;
-
unsigned int partitions;
struct vsp1_partitio

[PATCH v2 0/8] vsp1: TLB optimisation and DL caching

2017-08-14 Thread Kieran Bingham
Each display list currently allocates an area of DMA memory to store register
settings for the VSP1 to process. Each of these allocations adds pressure to
the IPMMU TLB entries.

We can reduce the pressure by pre-allocating larger areas and dividing the area
across multiple bodies represented as a pool.

With this reconfiguration of bodies, we can adapt the configuration code to
separate out constant hardware configuration and cache it for re-use.

Patch 1 adds protection to ensure that the display list body does not overflow
and will allow us to reduce the size of the body allocations in the future (it
has already helped me catch an overflow during the development of this series,
so I thought it was a worth while addition)

Patch 2 implements the fragment pool object and provides function helpers to
interact with the pool

Patch 3 converts the existing allocations to use the new fragment pool.

>From patch 4 to 7, we then refactor the display list handling code to separate
out the two stages of stream setup and frame configuration and then configure
directly into display list bodies. This allows us to cache the constant stream
configuration in a reusable display list body which also repairs suspend/resume
cycles for the video pipelines.

Finally in patch 8, the size of the internal display list body is reduced down
to 64 entries, as the maximum used is now 41 slots. The cached video pipeline
stream configuration appears to use a maximum of 64 entries, but to allow for
expansion this is set to 128 for now to prevent unexpected overflows.

Kieran Bingham (8):
  v4l: vsp1: Protect fragments against overflow
  v4l: vsp1: Provide a fragment pool
  v4l: vsp1: Convert display lists to use new fragment pool
  v4l: vsp1: Use reference counting for fragments
  v4l: vsp1: Refactor display list configure operations
  v4l: vsp1: Adapt entities to configure into a body
  v4l: vsp1: Move video configuration to a cached dlb
  v4l: vsp1: Reduce display list body size

 drivers/media/platform/vsp1/vsp1_bru.c|  32 +--
 drivers/media/platform/vsp1/vsp1_clu.c|  86 +++---
 drivers/media/platform/vsp1/vsp1_clu.h|   1 +-
 drivers/media/platform/vsp1/vsp1_dl.c | 331 ---
 drivers/media/platform/vsp1/vsp1_dl.h |  13 +-
 drivers/media/platform/vsp1/vsp1_drm.c|  21 +-
 drivers/media/platform/vsp1/vsp1_entity.c |  23 +-
 drivers/media/platform/vsp1/vsp1_entity.h |  31 +--
 drivers/media/platform/vsp1/vsp1_hgo.c|  26 +--
 drivers/media/platform/vsp1/vsp1_hgt.c|  28 +--
 drivers/media/platform/vsp1/vsp1_hsit.c   |  20 +-
 drivers/media/platform/vsp1/vsp1_lif.c|  23 +--
 drivers/media/platform/vsp1/vsp1_lut.c|  65 +++--
 drivers/media/platform/vsp1/vsp1_lut.h|   1 +-
 drivers/media/platform/vsp1/vsp1_pipe.c   |   8 +-
 drivers/media/platform/vsp1/vsp1_pipe.h   |   7 +-
 drivers/media/platform/vsp1/vsp1_rpf.c| 179 ++--
 drivers/media/platform/vsp1/vsp1_sru.c|  24 +--
 drivers/media/platform/vsp1/vsp1_uds.c|  73 ++---
 drivers/media/platform/vsp1/vsp1_uds.h|   2 +-
 drivers/media/platform/vsp1/vsp1_video.c  |  82 +++---
 drivers/media/platform/vsp1/vsp1_video.h  |   2 +-
 drivers/media/platform/vsp1/vsp1_wpf.c| 325 ---
 23 files changed, 753 insertions(+), 650 deletions(-)

base-commit: f44bd631453bf7dcbe57f79b924db3a6dd038bff
-- 
git-series 0.9.1


[PATCH v2 2/8] v4l: vsp1: Provide a fragment pool

2017-08-14 Thread Kieran Bingham
Each display list allocates a body to store register values in a dma
accessible buffer from a dma_alloc_wc() allocation. Each of these
results in an entry in the TLB, and a large number of display list
allocations adds pressure to this resource.

Reduce TLB pressure on the IPMMUs by allocating multiple display list
bodies in a single allocation, and providing these to the display list
through a 'fragment pool'. A pool can be allocated by the display list
manager or entities which require their own body allocations.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

---
v2:
 - assign dlb->dma correctly
---
 drivers/media/platform/vsp1/vsp1_dl.c | 129 +++-
 drivers/media/platform/vsp1/vsp1_dl.h |   8 ++-
 2 files changed, 137 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
b/drivers/media/platform/vsp1/vsp1_dl.c
index cb4625ae13c2..aab9dd6ec0eb 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -45,6 +45,8 @@ struct vsp1_dl_entry {
 /**
  * struct vsp1_dl_body - Display list body
  * @list: entry in the display list list of bodies
+ * @free: entry in the pool free body list
+ * @pool: pool to which this body belongs
  * @vsp1: the VSP1 device
  * @entries: array of entries
  * @dma: DMA address of the entries
@@ -54,6 +56,9 @@ struct vsp1_dl_entry {
  */
 struct vsp1_dl_body {
struct list_head list;
+   struct list_head free;
+
+   struct vsp1_dl_fragment_pool *pool;
struct vsp1_device *vsp1;
 
struct vsp1_dl_entry *entries;
@@ -65,6 +70,30 @@ struct vsp1_dl_body {
 };
 
 /**
+ * struct vsp1_dl_fragment_pool - display list body/fragment pool
+ * @dma: DMA address of the entries
+ * @size: size of the full DMA memory pool in bytes
+ * @mem: CPU memory pointer for the pool
+ * @bodies: Array of DLB structures for the pool
+ * @free: List of free DLB entries
+ * @lock: Protects the pool and free list
+ * @vsp1: the VSP1 device
+ */
+struct vsp1_dl_fragment_pool {
+   /* DMA allocation */
+   dma_addr_t dma;
+   size_t size;
+   void *mem;
+
+   /* Body management */
+   struct vsp1_dl_body *bodies;
+   struct list_head free;
+   spinlock_t lock;
+
+   struct vsp1_device *vsp1;
+};
+
+/**
  * struct vsp1_dl_list - Display list
  * @list: entry in the display list manager lists
  * @dlm: the display list manager
@@ -104,6 +133,7 @@ enum vsp1_dl_mode {
  * @active: list currently being processed (loaded) by hardware
  * @queued: list queued to the hardware (written to the DL registers)
  * @pending: list waiting to be queued to the hardware
+ * @pool: fragment pool for the display list bodies
  * @gc_work: fragments garbage collector work struct
  * @gc_fragments: array of display list fragments waiting to be freed
  */
@@ -119,6 +149,8 @@ struct vsp1_dl_manager {
struct vsp1_dl_list *queued;
struct vsp1_dl_list *pending;
 
+   struct vsp1_dl_fragment_pool *pool;
+
struct work_struct gc_work;
struct list_head gc_fragments;
 };
@@ -128,6 +160,103 @@ struct vsp1_dl_manager {
  */
 
 /*
+ * Fragment pool's reduce the pressure on the iommu TLB by allocating a single
+ * large area of DMA memory and allocating it as a pool of fragment bodies
+ */
+struct vsp1_dl_fragment_pool *
+vsp1_dl_fragment_pool_alloc(struct vsp1_device *vsp1, unsigned int qty,
+   unsigned int num_entries, size_t extra_size)
+{
+   struct vsp1_dl_fragment_pool *pool;
+   size_t dlb_size;
+   unsigned int i;
+
+   pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+   if (!pool)
+   return NULL;
+
+   pool->vsp1 = vsp1;
+
+   dlb_size = num_entries * sizeof(struct vsp1_dl_entry) + extra_size;
+   pool->size = dlb_size * qty;
+
+   pool->bodies = kcalloc(qty, sizeof(*pool->bodies), GFP_KERNEL);
+   if (!pool->bodies) {
+   kfree(pool);
+   return NULL;
+   }
+
+   pool->mem = dma_alloc_wc(vsp1->bus_master, pool->size, >dma,
+   GFP_KERNEL);
+   if (!pool->mem) {
+   kfree(pool->bodies);
+   kfree(pool);
+   return NULL;
+   }
+
+   spin_lock_init(>lock);
+   INIT_LIST_HEAD(>free);
+
+   for (i = 0; i < qty; ++i) {
+   struct vsp1_dl_body *dlb = >bodies[i];
+
+   dlb->pool = pool;
+   dlb->max_entries = num_entries;
+
+   dlb->dma = pool->dma + i * dlb_size;
+   dlb->entries = pool->mem + i * dlb_size;
+
+   list_add_tail(>free, >free);
+   }
+
+   return pool;
+}
+
+void vsp1_dl_fragment_pool_free(struct vsp1_dl_fragment_pool *pool)
+{
+   if (!pool)
+   return;
+
+   if (pool->mem)
+   dma_free_wc(pool->vsp1->bus_master, pool->size, pool->m

[PATCH v2 3/8] v4l: vsp1: Convert display lists to use new fragment pool

2017-08-14 Thread Kieran Bingham
Adapt the dl->body0 object to use an object from the fragment pool.
This greatly reduces the pressure on the TLB for IPMMU use cases, as
all of the lists use a single allocation for the main body.

The CLU and LUT objects pre-allocate a pool containing two bodies,
allowing a userspace update before the hardware has committed a previous
set of tables.

Fragments are no longer 'freed' in interrupt context, but instead
released back to their respective pools.  This allows us to remove the
garbage collector in the DLM.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

---
v2:
 - Use dl->body0->max_entries to determine header offset, instead of the
   global constant VSP1_DL_NUM_ENTRIES which is incorrect.
 - squash updates for LUT, CLU, and fragment cleanup into single patch.
   (Not fully bisectable when separated)
---
 drivers/media/platform/vsp1/vsp1_clu.c |  22 ++-
 drivers/media/platform/vsp1/vsp1_clu.h |   1 +-
 drivers/media/platform/vsp1/vsp1_dl.c  | 223 +-
 drivers/media/platform/vsp1/vsp1_dl.h  |   3 +-
 drivers/media/platform/vsp1/vsp1_lut.c |  23 ++-
 drivers/media/platform/vsp1/vsp1_lut.h |   1 +-
 6 files changed, 90 insertions(+), 183 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_clu.c 
b/drivers/media/platform/vsp1/vsp1_clu.c
index f2fb26e5ab4e..52c523625e2f 100644
--- a/drivers/media/platform/vsp1/vsp1_clu.c
+++ b/drivers/media/platform/vsp1/vsp1_clu.c
@@ -23,6 +23,8 @@
 #define CLU_MIN_SIZE   4U
 #define CLU_MAX_SIZE   8190U
 
+#define CLU_SIZE   (17 * 17 * 17)
+
 /* 
-
  * Device Access
  */
@@ -47,19 +49,19 @@ static int clu_set_table(struct vsp1_clu *clu, struct 
v4l2_ctrl *ctrl)
struct vsp1_dl_body *dlb;
unsigned int i;
 
-   dlb = vsp1_dl_fragment_alloc(clu->entity.vsp1, 1 + 17 * 17 * 17);
+   dlb = vsp1_dl_fragment_get(clu->pool);
if (!dlb)
return -ENOMEM;
 
vsp1_dl_fragment_write(dlb, VI6_CLU_ADDR, 0);
-   for (i = 0; i < 17 * 17 * 17; ++i)
+   for (i = 0; i < CLU_SIZE; ++i)
vsp1_dl_fragment_write(dlb, VI6_CLU_DATA, ctrl->p_new.p_u32[i]);
 
spin_lock_irq(>lock);
swap(clu->clu, dlb);
spin_unlock_irq(>lock);
 
-   vsp1_dl_fragment_free(dlb);
+   vsp1_dl_fragment_put(dlb);
return 0;
 }
 
@@ -261,8 +263,16 @@ static void clu_configure(struct vsp1_entity *entity,
}
 }
 
+static void clu_destroy(struct vsp1_entity *entity)
+{
+   struct vsp1_clu *clu = to_clu(>subdev);
+
+   vsp1_dl_fragment_pool_free(clu->pool);
+}
+
 static const struct vsp1_entity_operations clu_entity_ops = {
.configure = clu_configure,
+   .destroy = clu_destroy,
 };
 
 /* 
-
@@ -288,6 +298,12 @@ struct vsp1_clu *vsp1_clu_create(struct vsp1_device *vsp1)
if (ret < 0)
return ERR_PTR(ret);
 
+   /* Allocate a fragment pool */
+   clu->pool = vsp1_dl_fragment_pool_alloc(clu->entity.vsp1, 2,
+   CLU_SIZE + 1, 0);
+   if (!clu->pool)
+   return ERR_PTR(-ENOMEM);
+
/* Initialize the control handler. */
v4l2_ctrl_handler_init(>ctrls, 2);
v4l2_ctrl_new_custom(>ctrls, _table_control, NULL);
diff --git a/drivers/media/platform/vsp1/vsp1_clu.h 
b/drivers/media/platform/vsp1/vsp1_clu.h
index 036e0a2f1a42..601ffb558e30 100644
--- a/drivers/media/platform/vsp1/vsp1_clu.h
+++ b/drivers/media/platform/vsp1/vsp1_clu.h
@@ -36,6 +36,7 @@ struct vsp1_clu {
spinlock_t lock;
unsigned int mode;
struct vsp1_dl_body *clu;
+   struct vsp1_dl_fragment_pool *pool;
 };
 
 static inline struct vsp1_clu *to_clu(struct v4l2_subdev *subdev)
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
b/drivers/media/platform/vsp1/vsp1_dl.c
index aab9dd6ec0eb..6ffdc3549283 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -110,7 +110,7 @@ struct vsp1_dl_list {
struct vsp1_dl_header *header;
dma_addr_t dma;
 
-   struct vsp1_dl_body body0;
+   struct vsp1_dl_body *body0;
struct list_head fragments;
 
bool has_chain;
@@ -134,8 +134,6 @@ enum vsp1_dl_mode {
  * @queued: list queued to the hardware (written to the DL registers)
  * @pending: list waiting to be queued to the hardware
  * @pool: fragment pool for the display list bodies
- * @gc_work: fragments garbage collector work struct
- * @gc_fragments: array of display list fragments waiting to be freed
  */
 struct vsp1_dl_manager {
unsigned int index;
@@ -150,9 +148,6 @@ struct vsp1_dl_manager {
struct vsp1_dl_list *pending;
 
struct vsp1_dl_fragment_pool *pool;

[PATCH v2 1/8] v4l: vsp1: Protect fragments against overflow

2017-08-14 Thread Kieran Bingham
The fragment write function relies on the code never asking it to
write more than the entries available in the list.

Currently with each list body containing 256 entries, this is fine,
but we can reduce this number greatly saving memory.

In preparation of this - add a level of protection to catch any
buffer overflows.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
b/drivers/media/platform/vsp1/vsp1_dl.c
index 8b5cbb6b7a70..cb4625ae13c2 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -50,6 +50,7 @@ struct vsp1_dl_entry {
  * @dma: DMA address of the entries
  * @size: size of the DMA memory in bytes
  * @num_entries: number of stored entries
+ * @max_entries: number of entries available
  */
 struct vsp1_dl_body {
struct list_head list;
@@ -60,6 +61,7 @@ struct vsp1_dl_body {
size_t size;
 
unsigned int num_entries;
+   unsigned int max_entries;
 };
 
 /**
@@ -138,6 +140,7 @@ static int vsp1_dl_body_init(struct vsp1_device *vsp1,
 
dlb->vsp1 = vsp1;
dlb->size = size;
+   dlb->max_entries = num_entries;
 
dlb->entries = dma_alloc_wc(vsp1->bus_master, dlb->size, >dma,
GFP_KERNEL);
@@ -220,6 +223,11 @@ void vsp1_dl_fragment_free(struct vsp1_dl_body *dlb)
  */
 void vsp1_dl_fragment_write(struct vsp1_dl_body *dlb, u32 reg, u32 data)
 {
+   if (unlikely(dlb->num_entries >= dlb->max_entries)) {
+   WARN_ONCE(true, "DLB size exceeded (max %u)", dlb->max_entries);
+   return;
+   }
+
dlb->entries[dlb->num_entries].addr = reg;
dlb->entries[dlb->num_entries].data = data;
dlb->num_entries++;
-- 
git-series 0.9.1


[GIT PULL FOR renesas-drivers] Display List Optimizations

2017-08-14 Thread Kieran Bingham
From: Kieran Bingham <kieran.bing...@ideasonboard.com>

Hi Geert,

Please consider pulling the following changes into renesas-drivers.

This series is based upon a merge of my previous pa-improvements/v4 and
airlied-drm/drm-next to base on top of all pending VSP1 changes.


The following changes since commit f44bd631453bf7dcbe57f79b924db3a6dd038bff:

  Merge remote-tracking branch 'airlied-drm/drm-next' into vsp1/next 
(2017-08-08 19:51:06 +0100)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/kbingham/rcar.git 
tags/vsp1/tlb-optimise-v2

for you to fetch changes up to fa078611769415d7adbad208f1299d05bee3bda8:

  v4l: vsp1: Reduce display list body size (2017-08-14 15:58:38 +0100)

----
Kieran Bingham (8):
  v4l: vsp1: Protect fragments against overflow
  v4l: vsp1: Provide a fragment pool
  v4l: vsp1: Convert display lists to use new fragment pool
  v4l: vsp1: Use reference counting for fragments
  v4l: vsp1: Refactor display list configure operations
  v4l: vsp1: Adapt entities to configure into a body
  v4l: vsp1: Move video configuration to a cached dlb
  v4l: vsp1: Reduce display list body size

 drivers/media/platform/vsp1/vsp1_bru.c|  32 ++-
 drivers/media/platform/vsp1/vsp1_clu.c|  86 +---
 drivers/media/platform/vsp1/vsp1_clu.h|   1 +
 drivers/media/platform/vsp1/vsp1_dl.c | 331 --
 drivers/media/platform/vsp1/vsp1_dl.h |  13 +-
 drivers/media/platform/vsp1/vsp1_drm.c|  21 +-
 drivers/media/platform/vsp1/vsp1_entity.c |  23 ++-
 drivers/media/platform/vsp1/vsp1_entity.h |  31 ++-
 drivers/media/platform/vsp1/vsp1_hgo.c|  26 +--
 drivers/media/platform/vsp1/vsp1_hgt.c|  28 ++-
 drivers/media/platform/vsp1/vsp1_hsit.c   |  20 +-
 drivers/media/platform/vsp1/vsp1_lif.c|  23 +--
 drivers/media/platform/vsp1/vsp1_lut.c|  65 --
 drivers/media/platform/vsp1/vsp1_lut.h|   1 +
 drivers/media/platform/vsp1/vsp1_pipe.c   |   8 +-
 drivers/media/platform/vsp1/vsp1_pipe.h   |   7 +-
 drivers/media/platform/vsp1/vsp1_rpf.c| 179 
 drivers/media/platform/vsp1/vsp1_sru.c|  24 +--
 drivers/media/platform/vsp1/vsp1_uds.c|  73 ---
 drivers/media/platform/vsp1/vsp1_uds.h|   2 +-
 drivers/media/platform/vsp1/vsp1_video.c  |  82 
 drivers/media/platform/vsp1/vsp1_video.h  |   2 +
 drivers/media/platform/vsp1/vsp1_wpf.c| 325 +++--
 23 files changed, 753 insertions(+), 650 deletions(-)


Re: [PATCH v2 1/8] v4l: vsp1: Protect fragments against overflow

2017-08-17 Thread Kieran Bingham
Hi Laurent,

Thanks for your review,

On 16/08/17 22:53, Laurent Pinchart wrote:
> Hi Kieran,
> 
> Thank you for the patch.

> How about
> 
>   if (WARN_ONCE(dlb->num_entries >= dlb->max_entries,
> "DLB size exceeded (max %u)", dlb->max_entries))
>   return;
> 
> (WARN_ONCE contains the unlikely() already)
> 
> I'm not fussed either way,

That does seem cleaner. Updated ready for any repost.

Thanks
--
Kieran


Re: [PATCH v2 08/14] v4l: vsp1: Add support for new VSP2-BS, VSP2-DL and VSP2-D instances

2017-07-13 Thread Kieran Bingham
Hi Laurent,

On 26/06/17 19:12, Laurent Pinchart wrote:
> New Gen3 SoCs come with two new VSP2 variants names VSP2-BS and VSP2-DL,
> as well as a new VSP2-D variant on V3M and V3H SoCs. Add new entries for
> them in the VSP device info table.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>

Code in the patch looks OK - but I can't see where the difference between the
horizontal widths are supported between VSPD H3/VC

I see this in the datasheet: (32.1.1.6 in this particular part)

Direct connection to display module
— Supporting 4096 pixels in horizontal direction [R-Car H3/R-Car M3-W/ R-Car 
M3-N]
— Supporting 2048 pixels in horizontal direction [R-Car V3M/R-Car V3H/R-Car
D3/R-Car E3]

Do we have this information encoded anywhere? or are they just talking about
maximum performance capability there?

Also some features that are implied as supported aren't mentioned - but that's
not a blocker to adding in the initial devices at all.

Therefore:

Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/media/platform/vsp1/vsp1_drv.c  | 24 
>  drivers/media/platform/vsp1/vsp1_regs.h | 15 +--
>  2 files changed, 37 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/vsp1/vsp1_drv.c 
> b/drivers/media/platform/vsp1/vsp1_drv.c
> index 6a9aeb71aedf..c4f2ac61f7d2 100644
> --- a/drivers/media/platform/vsp1/vsp1_drv.c
> +++ b/drivers/media/platform/vsp1/vsp1_drv.c
> @@ -710,6 +710,14 @@ static const struct vsp1_device_info vsp1_device_infos[] 
> = {
>   .num_bru_inputs = 5,
>   .uapi = true,
>   }, {
> + .version = VI6_IP_VERSION_MODEL_VSPBS_GEN3,
> + .model = "VSP2-BS",
> + .gen = 3,
> + .features = VSP1_HAS_BRS,

32.1.1.5 implies:

| VSP1_HAS_WPF_VFLIP

But Figure 32.5 implies that it doesn't ...

Figure 32.5 also implies that | VSP1_HAS_CLU is there too on both RPF0, and RPF1

> + .rpf_count = 2,
> + .wpf_count = 1,
> + .uapi = true,
> + }, {
>   .version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
>   .model = "VSP2-D",
>   .gen = 3,
> @@ -717,6 +725,22 @@ static const struct vsp1_device_info vsp1_device_infos[] 
> = {
>   .rpf_count = 5,
>   .wpf_count = 2,
>   .num_bru_inputs = 5,
> + }, {
> + .version = VI6_IP_VERSION_MODEL_VSPD_V3,
> + .model = "VSP2-D",
> + .gen = 3,
> + .features = VSP1_HAS_BRS | VSP1_HAS_BRU | VSP1_HAS_LIF,
> + .rpf_count = 5,
> + .wpf_count = 1,
> + .num_bru_inputs = 5,
> + }, {
> + .version = VI6_IP_VERSION_MODEL_VSPDL_GEN3,
> + .model = "VSP2-DL",
> + .gen = 3,
> + .features = VSP1_HAS_BRS | VSP1_HAS_BRU | VSP1_HAS_LIF,

Hrm. 32.1.1.7 says:
— Vertical flipping in case of output to memory.
So thats some sort of a conditional : | VSP1_HAS_WPF_VFLIP

So looking at this and the settings of the existing models, I guess it looks
like we don't support flip if we have an LIF output (as that would then be
unsupported)

> + .rpf_count = 5,
> + .wpf_count = 2,
> + .num_bru_inputs = 5,
>   },
>  };
>  
> diff --git a/drivers/media/platform/vsp1/vsp1_regs.h 
> b/drivers/media/platform/vsp1/vsp1_regs.h
> index 744217e020b9..ab439a60a100 100644
> --- a/drivers/media/platform/vsp1/vsp1_regs.h
> +++ b/drivers/media/platform/vsp1/vsp1_regs.h
> @@ -699,9 +699,20 @@
>  #define VI6_IP_VERSION_MODEL_VSPBD_GEN3  (0x15 << 8)
>  #define VI6_IP_VERSION_MODEL_VSPBC_GEN3  (0x16 << 8)
>  #define VI6_IP_VERSION_MODEL_VSPD_GEN3   (0x17 << 8)
> +#define VI6_IP_VERSION_MODEL_VSPD_V3 (0x18 << 8)
> +#define VI6_IP_VERSION_MODEL_VSPDL_GEN3  (0x19 << 8)
> +#define VI6_IP_VERSION_MODEL_VSPBS_GEN3  (0x1a << 8)
>  #define VI6_IP_VERSION_SOC_MASK  (0xff << 0)
> -#define VI6_IP_VERSION_SOC_H (0x01 << 0)
> -#define VI6_IP_VERSION_SOC_M (0x02 << 0)
> +#define VI6_IP_VERSION_SOC_H2(0x01 << 0)
> +#define VI6_IP_VERSION_SOC_V2H   (0x01 << 0)
> +#define VI6_IP_VERSION_SOC_V3M   (0x01 << 0)
> +#define VI6_IP_VERSION_SOC_M2(0x02 << 0)
> +#define VI6_IP_VERSION_SOC_M3W   (0x02 << 0)
> +#define VI6_IP_VERSION_SOC_V3H   (0x02 << 0)
> +#define VI6_IP_VERSION_SOC_H3(0x03 << 0)
> +#define VI6_IP_VERSION_SOC_D3(0x04 << 0)
> +#define VI6_IP_VERSION_SOC_M3N   (0x04 << 0)
> +#define VI6_IP_VERSION_SOC_E3(0x04 << 0)
>  
>  /* 
> -
>   * RPF CLUT Registers
> 


Re: [PATCH v2 02/14] v4l: vsp1: Don't recycle active list at display start

2017-07-13 Thread Kieran Bingham
Hi Laurent,

On 26/06/17 19:12, Laurent Pinchart wrote:
> When the display start interrupt occurs, we know that the hardware has
> finished loading the active display list. The driver then proceeds to
> recycle the list, assuming it won't be needed anymore.
> 
> This assumption holds true for headerless display lists, as the VSP
> doesn't reload the list for the next frame if it hasn't changed.
> However, this isn't true anymore for header display lists, as they are
> loaded at every frame start regardless of whether they have been
> updated.
> 
> To prepare for header display lists usage in display pipelines, we need
> to postpone recycling the list until it gets replaced by a new one
> through a page flip. The driver already does so in the frame end
> interrupt handler, so all we need is to skip list recycling in the
> display start interrupt handler.
> 
> While the active list can be recycled at display start for headerless
> display lists, there's no real harm in postponing that to the frame end
> interrupt handler in all cases. This simplifies interrupt handling as we
> don't need to process the display start interrupt anymore.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>

Ok, I had skipped this one as I was concerned about its effects in relation to
11/14 but I see how that's working now.

Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/media/platform/vsp1/vsp1_dl.c  | 16 
>  drivers/media/platform/vsp1/vsp1_dl.h  |  1 -
>  drivers/media/platform/vsp1/vsp1_drm.c | 12 
>  drivers/media/platform/vsp1/vsp1_drm.h |  2 --
>  drivers/media/platform/vsp1/vsp1_drv.c |  8 
>  5 files changed, 4 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
> b/drivers/media/platform/vsp1/vsp1_dl.c
> index dc47e236c780..bb92be4fe0f0 100644
> --- a/drivers/media/platform/vsp1/vsp1_dl.c
> +++ b/drivers/media/platform/vsp1/vsp1_dl.c
> @@ -547,22 +547,6 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
>   * Display List Manager
>   */
>  
> -/* Interrupt Handling */
> -void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm)
> -{
> - spin_lock(>lock);
> -
> - /*
> -  * The display start interrupt signals the end of the display list
> -  * processing by the device. The active display list, if any, won't be
> -  * accessed anymore and can be reused.
> -  */
> - __vsp1_dl_list_put(dlm->active);
> - dlm->active = NULL;
> -
> - spin_unlock(>lock);
> -}
> -
>  /**
>   * vsp1_dlm_irq_frame_end - Display list handler for the frame end interrupt
>   * @dlm: the display list manager
> diff --git a/drivers/media/platform/vsp1/vsp1_dl.h 
> b/drivers/media/platform/vsp1/vsp1_dl.h
> index 6ec1380a10af..ee3508172f0a 100644
> --- a/drivers/media/platform/vsp1/vsp1_dl.h
> +++ b/drivers/media/platform/vsp1/vsp1_dl.h
> @@ -27,7 +27,6 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device 
> *vsp1,
>   unsigned int prealloc);
>  void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm);
>  void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
> -void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm);
>  bool vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm);
>  
>  struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm);
> diff --git a/drivers/media/platform/vsp1/vsp1_drm.c 
> b/drivers/media/platform/vsp1/vsp1_drm.c
> index 9377aafa8996..bc3fd9bc7126 100644
> --- a/drivers/media/platform/vsp1/vsp1_drm.c
> +++ b/drivers/media/platform/vsp1/vsp1_drm.c
> @@ -32,11 +32,6 @@
>   * Interrupt Handling
>   */
>  
> -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);
> @@ -224,6 +219,10 @@ int vsp1_du_setup_lif(struct device *dev, const struct 
> vsp1_du_lif_config *cfg)
>   return ret;
>   }
>  
> + /* Disable the display interrupts. */
> + vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
> + vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0);
> +
>   dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__);
>  
>   return 0;
> @@ -529,13 +528,10 @@ void vsp1_du_atomic_flush(struct device *dev)
>  
>   /* Start or stop the pipeline if needed. */
>   if (!vsp1->drm->num_inputs && pipe->num_inputs) {
> - vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
> - vsp1_write(vsp1, VI6_DISP_IRQ_ENB, VI6_DISP_

Re: [PATCH v2 09/14] v4l: vsp1: Add support for multiple LIF instances

2017-07-13 Thread Kieran Bingham
Hi Laurent,

On 26/06/17 19:12, Laurent Pinchart wrote:
> The VSP2-DL instance (present in the H3 ES2.0 and M3-N SoCs) has two LIF
> instances. Adapt the driver infrastructure to support multiple LIFs.
> Support for multiple display pipelines will be added separately.
> 
> The change to the entity routing table removes the ability to connect
> the LIF output to the HGO or HGT histogram generators. This feature is
> only available on Gen2 hardware, isn't supported by the rest of the
> driver, and has no known use case, so this isn't an issue.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>
This looks good.

Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/media/platform/vsp1/vsp1.h|  5 ++--
>  drivers/media/platform/vsp1/vsp1_drm.c|  8 ++---
>  drivers/media/platform/vsp1/vsp1_drv.c| 49 
> +++
>  drivers/media/platform/vsp1/vsp1_entity.c |  3 +-
>  drivers/media/platform/vsp1/vsp1_lif.c|  5 ++--
>  drivers/media/platform/vsp1/vsp1_lif.h|  2 +-
>  drivers/media/platform/vsp1/vsp1_regs.h   |  4 ++-
>  7 files changed, 46 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/media/platform/vsp1/vsp1.h 
> b/drivers/media/platform/vsp1/vsp1.h
> index 73858a0ed35c..78ef838416b3 100644
> --- a/drivers/media/platform/vsp1/vsp1.h
> +++ b/drivers/media/platform/vsp1/vsp1.h
> @@ -41,11 +41,11 @@ struct vsp1_rwpf;
>  struct vsp1_sru;
>  struct vsp1_uds;
>  
> +#define VSP1_MAX_LIF 2
>  #define VSP1_MAX_RPF 5
>  #define VSP1_MAX_UDS 3
>  #define VSP1_MAX_WPF 4
>  
> -#define VSP1_HAS_LIF (1 << 0)

I guess I can re-use this 'bit' for the Writeback prototype which used to be
BIT(9) (which is now the BRS)


>  #define VSP1_HAS_LUT (1 << 1)
>  #define VSP1_HAS_SRU (1 << 2)
>  #define VSP1_HAS_BRU (1 << 3)
> @@ -61,6 +61,7 @@ struct vsp1_device_info {
>   const char *model;
>   unsigned int gen;
>   unsigned int features;
> + unsigned int lif_count;
>   unsigned int rpf_count;
>   unsigned int uds_count;
>   unsigned int wpf_count;
> @@ -84,7 +85,7 @@ struct vsp1_device {
>   struct vsp1_hgt *hgt;
>   struct vsp1_hsit *hsi;
>   struct vsp1_hsit *hst;
> - struct vsp1_lif *lif;
> + struct vsp1_lif *lif[VSP1_MAX_LIF];
>   struct vsp1_lut *lut;
>   struct vsp1_rwpf *rpf[VSP1_MAX_RPF];
>   struct vsp1_sru *sru;
> diff --git a/drivers/media/platform/vsp1/vsp1_drm.c 
> b/drivers/media/platform/vsp1/vsp1_drm.c
> index daaafe7885fa..4e1b893e8f51 100644
> --- a/drivers/media/platform/vsp1/vsp1_drm.c
> +++ b/drivers/media/platform/vsp1/vsp1_drm.c
> @@ -181,7 +181,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int 
> pipe_index,
>   format.format.code);
>  
>   format.pad = LIF_PAD_SINK;
> - ret = v4l2_subdev_call(>lif->entity.subdev, pad, set_fmt, NULL,
> + ret = v4l2_subdev_call(>lif[0]->entity.subdev, pad, set_fmt, NULL,
>  );
>   if (ret < 0)
>   return ret;
> @@ -599,15 +599,15 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
>  
>   vsp1->bru->entity.sink = >wpf[0]->entity;
>   vsp1->bru->entity.sink_pad = 0;
> - vsp1->wpf[0]->entity.sink = >lif->entity;
> + vsp1->wpf[0]->entity.sink = >lif[0]->entity;
>   vsp1->wpf[0]->entity.sink_pad = 0;
>  
>   list_add_tail(>bru->entity.list_pipe, >entities);
>   list_add_tail(>wpf[0]->entity.list_pipe, >entities);
> - list_add_tail(>lif->entity.list_pipe, >entities);
> + list_add_tail(>lif[0]->entity.list_pipe, >entities);
>  
>   pipe->bru = >bru->entity;
> - pipe->lif = >lif->entity;
> + pipe->lif = >lif[0]->entity;
>   pipe->output = vsp1->wpf[0];
>   pipe->output->pipe = pipe;
>   pipe->frame_end = vsp1_du_pipeline_frame_end;
> diff --git a/drivers/media/platform/vsp1/vsp1_drv.c 
> b/drivers/media/platform/vsp1/vsp1_drv.c
> index c4f2ac61f7d2..e875982f02ae 100644
> --- a/drivers/media/platform/vsp1/vsp1_drv.c
> +++ b/drivers/media/platform/vsp1/vsp1_drv.c
> @@ -168,10 +168,13 @@ static int vsp1_uapi_create_links(struct vsp1_device 
> *vsp1)
>   return ret;
>   }
>  
> - if (vsp1->lif) {
> - ret = media_create_pad_link(>wpf[0]->entity.subdev.entity,
> + for (i = 0; i < vsp1->info->lif_count; ++i) {
> + if (!vsp1->lif[i])
> +   

Re: [PATCH v2 1/3] drm: rcar-du: Use the VBK interrupt for vblank events

2017-07-12 Thread Kieran Bingham
Hi Laurent,

On 11/07/17 23:29, Laurent Pinchart wrote:
> When implementing support for interlaced modes, the driver switched from
> reporting vblank events on the vertical blanking (VBK) interrupt to the
> frame end interrupt (FRM). This incorrectly divided the reported refresh
> rate by two. Fix it by moving back to the VBK interrupt.
> 
> Fixes: 906eff7fcada ("drm: rcar-du: Implement support for interlaced modes")
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>

Of course, this looks much more correct than the patch I submitted :-)

Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c 
> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index 98cf446391dc..17fd1cd5212c 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -698,7 +698,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
>   status = rcar_du_crtc_read(rcrtc, DSSR);
>   rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
>  
> - if (status & DSSR_FRM) {
> + if (status & DSSR_VBK) {
>   drm_crtc_handle_vblank(>crtc);
>  
>   if (rcdu->info->gen < 3)
> 


Re: [PATCH v2 06/14] v4l: vsp1: Add pipe index argument to the VSP-DU API

2017-07-13 Thread Kieran Bingham
On 26/06/17 19:12, Laurent Pinchart wrote:
> In the H3 ES2.0 SoC the VSP2-DL instance has two connections to DU
> channels that need to be configured independently. Extend the VSP-DU API
> with a pipeline index to identify which pipeline the caller wants to
> operate on.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>

A bit of comment merge between this and the next patch but it's minor and not
worth the effort to change that ... so I'll happily ignore it if you do :)

Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/gpu/drm/rcar-du/rcar_du_vsp.c  | 12 ++--
>  drivers/media/platform/vsp1/vsp1_drm.c | 32 ++--
>  include/media/vsp1.h   | 10 ++
>  3 files changed, 34 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c 
> b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
> index f870445ebc8d..d46dce054442 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
> @@ -81,22 +81,22 @@ void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
>*/
>   crtc->group->need_restart = true;
>  
> - vsp1_du_setup_lif(crtc->vsp->vsp, );
> + vsp1_du_setup_lif(crtc->vsp->vsp, 0, );
>  }
>  
>  void rcar_du_vsp_disable(struct rcar_du_crtc *crtc)
>  {
> - vsp1_du_setup_lif(crtc->vsp->vsp, NULL);
> + vsp1_du_setup_lif(crtc->vsp->vsp, 0, NULL);
>  }
>  
>  void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc)
>  {
> - vsp1_du_atomic_begin(crtc->vsp->vsp);
> + vsp1_du_atomic_begin(crtc->vsp->vsp, 0);
>  }
>  
>  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, 0);
>  }
>  
>  /* Keep the two tables in sync. */
> @@ -192,7 +192,7 @@ static void rcar_du_vsp_plane_setup(struct 
> rcar_du_vsp_plane *plane)
>   }
>   }
>  
> - vsp1_du_atomic_update(plane->vsp->vsp, plane->index, );
> + vsp1_du_atomic_update(plane->vsp->vsp, 0, plane->index, );
>  }
>  
>  static int rcar_du_vsp_plane_prepare_fb(struct drm_plane *plane,
> @@ -292,7 +292,7 @@ static void rcar_du_vsp_plane_atomic_update(struct 
> drm_plane *plane,
>   if (plane->state->crtc)
>   rcar_du_vsp_plane_setup(rplane);
>   else
> - vsp1_du_atomic_update(rplane->vsp->vsp, rplane->index, NULL);
> + vsp1_du_atomic_update(rplane->vsp->vsp, 0, rplane->index, NULL);
>  }
>  
>  static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = {
> diff --git a/drivers/media/platform/vsp1/vsp1_drm.c 
> b/drivers/media/platform/vsp1/vsp1_drm.c
> index c72d021ff820..daaafe7885fa 100644
> --- a/drivers/media/platform/vsp1/vsp1_drm.c
> +++ b/drivers/media/platform/vsp1/vsp1_drm.c
> @@ -58,21 +58,26 @@ EXPORT_SYMBOL_GPL(vsp1_du_init);
>  /**
>   * 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 BRU source pad, the WPF0 sink
> - * and source pads, and the LIF sink pad.
> + * and @cfg.height. This sets up formats on the blend unit (BRU or BRS) 
> source
> + * pad, the WPF sink and source pads, and the LIF sink pad.
>   *
> - * As the media bus code on the BRU source pad is conditioned by the
> - * configuration of the BRU sink 0 pad, we also set up the formats on all BRU
> + * 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 BRU configuration is set to a 
> well
> - * defined state.
> + * vsp1_du_setup_rpf(). This ensures that the blend unit configuration is 
> set to
> + * a well defined state.

I presume those comment updates for the BRU/ blend-unit configuration are
actually for the next patch - but I don't think it matters here - and isn't
worth the effort to move the hunks.

It all reads OK.


>   *
>   * Return 0 on success or a negative error code on failure.
>   */
> -int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config 
>

Re: [PATCH v2 07/14] v4l: vsp1: Add support for the BRS entity

2017-07-13 Thread Kieran Bingham
On 26/06/17 19:12, Laurent Pinchart wrote:
> The Blend/ROP Sub Unit (BRS) is a stripped-down version of the BRU found
> in several VSP2 instances. Compared to a regular BRU, it supports two
> inputs only, and thus has no ROP unit.
> 
> Add support for the BRS by modeling it as a new entity type, but reuse

s/modeling/modelling/


> the vsp1_bru object underneath. Chaining the BRU and BRS entities seems
> to be supported by the hardware but isn't implemented yet as it isn't
> the primary use case for the BRS.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>

Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/media/platform/vsp1/vsp1.h|  2 +
>  drivers/media/platform/vsp1/vsp1_bru.c| 45 ++
>  drivers/media/platform/vsp1/vsp1_bru.h|  4 +-
>  drivers/media/platform/vsp1/vsp1_drv.c| 19 +-
>  drivers/media/platform/vsp1/vsp1_entity.c | 13 ++-
>  drivers/media/platform/vsp1/vsp1_entity.h |  1 +
>  drivers/media/platform/vsp1/vsp1_pipe.c   |  7 ++--
>  drivers/media/platform/vsp1/vsp1_regs.h   | 26 +
>  drivers/media/platform/vsp1/vsp1_video.c  | 63 
> ---
>  drivers/media/platform/vsp1/vsp1_wpf.c|  4 +-
>  10 files changed, 130 insertions(+), 54 deletions(-)
> 
> diff --git a/drivers/media/platform/vsp1/vsp1.h 
> b/drivers/media/platform/vsp1/vsp1.h
> index 847963b6e9eb..73858a0ed35c 100644
> --- a/drivers/media/platform/vsp1/vsp1.h
> +++ b/drivers/media/platform/vsp1/vsp1.h
> @@ -54,6 +54,7 @@ struct vsp1_uds;
>  #define VSP1_HAS_WPF_HFLIP   (1 << 6)
>  #define VSP1_HAS_HGO (1 << 7)
>  #define VSP1_HAS_HGT (1 << 8)
> +#define VSP1_HAS_BRS (1 << 9)
>  
>  struct vsp1_device_info {
>   u32 version;
> @@ -76,6 +77,7 @@ struct vsp1_device {
>   struct rcar_fcp_device *fcp;
>   struct device *bus_master;
>  
> + struct vsp1_bru *brs;
>   struct vsp1_bru *bru;
>   struct vsp1_clu *clu;
>   struct vsp1_hgo *hgo;
> diff --git a/drivers/media/platform/vsp1/vsp1_bru.c 
> b/drivers/media/platform/vsp1/vsp1_bru.c
> index 85362c5ef57a..e8fd2ae3b3eb 100644
> --- a/drivers/media/platform/vsp1/vsp1_bru.c
> +++ b/drivers/media/platform/vsp1/vsp1_bru.c
> @@ -33,7 +33,7 @@
>  static inline void vsp1_bru_write(struct vsp1_bru *bru, struct vsp1_dl_list 
> *dl,
> u32 reg, u32 data)
>  {
> - vsp1_dl_list_write(dl, reg, data);
> + vsp1_dl_list_write(dl, bru->base + reg, data);
>  }
>  
>  /* 
> -
> @@ -332,11 +332,14 @@ static void bru_configure(struct vsp1_entity *entity,
>   /*
>* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
>* unit with a NOP operation to make BRU input 1 available as the
> -  * Blend/ROP unit B SRC input.
> +  * Blend/ROP unit B SRC input. Only needed for BRU, the BRS has no ROP
> +  * unit.
>*/
> - vsp1_bru_write(bru, dl, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
> -VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
> -VI6_BRU_ROP_AROP(VI6_ROP_NOP));
> + if (entity->type == VSP1_ENTITY_BRU)
> + vsp1_bru_write(bru, dl, VI6_BRU_ROP,
> +VI6_BRU_ROP_DSTSEL_BRUIN(1) |
> +VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
> +VI6_BRU_ROP_AROP(VI6_ROP_NOP));
>  
>   for (i = 0; i < bru->entity.source_pad; ++i) {
>   bool premultiplied = false;
> @@ -366,12 +369,13 @@ static void bru_configure(struct vsp1_entity *entity,
>   ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;
>  
>   /*
> -  * Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
> -  * D in that order. The Blend/ROP unit B SRC is hardwired to the
> -  * ROP unit output, the corresponding register bits must be set
> -  * to 0.
> +  * Route inputs 0 to 3 as SRC inputs to Blend/ROP units A to D
> +  * in that order. In the BRU the Blend/ROP unit B SRC is
> +  * hardwired to the ROP unit output, the corresponding register
> +  * bits must be set to 0. The BRS has no ROP unit and doesn't
> +  * need any special processing.
>*/
> - if (i != 1)
> + if (!(entity->type == VSP1_ENTITY_BRU && i == 1))

If we're using this module for both BRU and BRS, would an is_bru(entity) and
is_brs(entity) be cleaner here ?

Not required - just thinking outlo

Re: [PATCH] drm: rcar-du: Setup planes before enabling CRTC to avoid flicker

2017-07-13 Thread Kieran Bingham
On 13/07/17 16:51, Kieran Bingham wrote:
> Hi Laurent,
> 
> I've just seen Maxime's latest series "[PATCH 0/4] drm/sun4i: Fix a register
> access bug" and it relates directly to a comment I had in this patch:
> 
> On 12/07/17 17:35, Kieran Bingham wrote:
>> Hi Laurent,
>>
>> On 28/06/17 19:50, Laurent Pinchart wrote:
>>> Commit 52055bafa1ff ("drm: rcar-du: Move plane commit code from CRTC
>>> start to CRTC resume") changed the order of the plane commit and CRTC
>>> enable operations to accommodate the runtime PM requirements. However,
>>> this introduced corruption in the first displayed frame, as the CRTC is
>>> now enabled without any plane configured. On Gen2 hardware the first
>>> frame will be black and likely unnoticed, but on Gen3 hardware we end up
>>> starting the display before the VSP compositor, which is more
>>> noticeable.
>>>
>>> To fix this, revert the order of the commit operations back, and handle
>>> runtime PM requirements in the CRTC .atomic_begin() and .atomic_enable()
>>> helper operation handlers.
>>>
>>> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>
>>
>> I only have code reduction or comment suggestions below - so either with or
>> without those changes, feel free to add my:
>>
>> Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
>>
>>> ---
>>>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 66 
>>> --
>>>  drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  4 +--
>>>  drivers/gpu/drm/rcar-du/rcar_du_kms.c  |  2 +-
>>>  3 files changed, 43 insertions(+), 29 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c 
>>> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
>>> index 6b5219ef0ad2..76cdb88b2b8e 100644
>>> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
>>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
>>> @@ -448,14 +448,8 @@ static void rcar_du_crtc_wait_page_flip(struct 
>>> rcar_du_crtc *rcrtc)
>>>   * Start/Stop and Suspend/Resume
>>>   */
>>>  
>>> -static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
>>> +static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc)
>>>  {
>>> -   struct drm_crtc *crtc = >crtc;
>>> -   bool interlaced;
>>> -
>>> -   if (rcrtc->started)
>>> -   return;
>>> -
>>> /* Set display off and background to black */
>>> rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
>>> rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
>>> @@ -467,6 +461,18 @@ static void rcar_du_crtc_start(struct rcar_du_crtc 
>>> *rcrtc)
>>> /* Start with all planes disabled. */
>>> rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
>>>  
>>> +   /* Enable the VSP compositor. */
>>> +   if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
>>> +   rcar_du_vsp_enable(rcrtc);
>>> +
>>> +   /* Turn vertical blanking interrupt reporting on. */
>>> +   drm_crtc_vblank_on(>crtc);
>>> +}
>>> +
>>> +static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
>>> +{
>>> +   bool interlaced;
>>> +
>>> /* Select master sync mode. This enables display operation in master
>>
>> Are we close enough here to fix this multiline comment style ?
>> (Not worth doing unless the patch is respun for other reasons ...)
>>
>> Actually - there are a lot in this file, so it would be better to do them 
>> all in
>> one hit/patch at a point of least conflicts ...
>>
>>
>>>  * sync mode (with the HSYNC and VSYNC signals configured as outputs and
>>>  * actively driven).
>>> @@ -477,24 +483,12 @@ static void rcar_du_crtc_start(struct rcar_du_crtc 
>>> *rcrtc)
>>>  DSYSR_TVM_MASTER);
>>>  
>>> rcar_du_group_start_stop(rcrtc->group, true);
>>> -
>>> -   /* Enable the VSP compositor. */
>>> -   if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
>>> -   rcar_du_vsp_enable(rcrtc);
>>> -
>>> -   /* Turn vertical blanking interrupt reporting back on. */
>>> -   drm_crtc_vblank_on(crtc);
>>> -
>>> -   rcrtc->started = true;
>>>  }
>>>  
>>>  static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
>>>

Re: [PATCH v2 08/14] v4l: vsp1: Add support for new VSP2-BS, VSP2-DL and VSP2-D instances

2017-07-14 Thread Kieran Bingham
On 14/07/17 00:31, Laurent Pinchart wrote:
> Hi Kieran,
> 
> On Thursday 13 Jul 2017 18:49:19 Kieran Bingham wrote:
>> On 26/06/17 19:12, Laurent Pinchart wrote:
>>> New Gen3 SoCs come with two new VSP2 variants names VSP2-BS and VSP2-DL,
>>> as well as a new VSP2-D variant on V3M and V3H SoCs. Add new entries for
>>> them in the VSP device info table.
>>>
>>> Signed-off-by: Laurent Pinchart
>>> <laurent.pinchart+rene...@ideasonboard.com>
>>
>> Code in the patch looks OK - but I can't see where the difference between
>> the horizontal widths are supported between VSPD H3/VC
>>
>> I see this in the datasheet: (32.1.1.6 in this particular part)
>>
>> Direct connection to display module
>> — Supporting 4096 pixels in horizontal direction [R-Car H3/R-Car M3-W/ R-Car
>> M3-N]
>> — Supporting 2048 pixels in horizontal direction [R-Car V3M/R-Car V3H/R-Car
>> D3/R-Car E3]
>>
>> Do we have this information encoded anywhere? or are they just talking about
>> maximum performance capability there?
> 
> No, we don't. It's a limit that we should have. I think we should fix that in 
> a separate patch, as the 4096 pixels limit isn't implemented either.

I'm not so worried about these limits (unless they cause the hardware to hang),
but I think they should be encoded somewhere, and I would certainly count that
as a separate patch.

Of course (excluding pipelines using BRU/BRS) the partition algorithm could
provide the capability to support image processing beyond limitations of the
pipeline maximum size...

But this can't cater for throughput limitations of bandwidth so there will be a
limit to how big an image we really want to support ...

Non realtime processing of large megapixel images might be relevant though - but
still not a use case to worry about here.

>> Also some features that are implied as supported aren't mentioned - but
>> that's not a blocker to adding in the initial devices at all.
>>
>> Therefore:
>>
>> Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
>>
>>> ---
>>>
>>>  drivers/media/platform/vsp1/vsp1_drv.c  | 24 
>>>  drivers/media/platform/vsp1/vsp1_regs.h | 15 +--
>>>  2 files changed, 37 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/media/platform/vsp1/vsp1_drv.c
>>> b/drivers/media/platform/vsp1/vsp1_drv.c index 6a9aeb71aedf..c4f2ac61f7d2
>>> 100644
>>> --- a/drivers/media/platform/vsp1/vsp1_drv.c
>>> +++ b/drivers/media/platform/vsp1/vsp1_drv.c
>>> @@ -710,6 +710,14 @@ static const struct vsp1_device_info
>>> vsp1_device_infos[] = {> 
>>> .num_bru_inputs = 5,
>>> .uapi = true,
>>> }, {
>>> +   .version = VI6_IP_VERSION_MODEL_VSPBS_GEN3,
>>> +   .model = "VSP2-BS",
>>> +   .gen = 3,
>>> +   .features = VSP1_HAS_BRS,
>>
>> 32.1.1.5 implies:
>> | VSP1_HAS_WPF_VFLIP
>>
>> But Figure 32.5 implies that it doesn't ...
> 
> The figures only tell whether the full combination of rotation and H/V flip 
> is 
> available. I think you're right, I'll add VSP1_HAS_WPF_VFLIP.
> 
>> Figure 32.5 also implies that | VSP1_HAS_CLU is there too on both RPF0, and
>> RPF1
> 
> Note that CLUT != CLU. I know it's confusing :-)

Oh ! :-S ... /me goes back to the datasheet ...

> 
>>> +   .rpf_count = 2,
>>> +   .wpf_count = 1,
>>> +   .uapi = true,
>>> +   }, {
>>> .version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
>>> .model = "VSP2-D",
>>> .gen = 3,
>>> @@ -717,6 +725,22 @@ static const struct vsp1_device_info
>>> vsp1_device_infos[] = {> 
>>> .rpf_count = 5,
>>> .wpf_count = 2,
>>> .num_bru_inputs = 5,
>>> +   }, {
>>> +   .version = VI6_IP_VERSION_MODEL_VSPD_V3,
>>> +   .model = "VSP2-D",
>>> +   .gen = 3,
>>> +   .features = VSP1_HAS_BRS | VSP1_HAS_BRU | VSP1_HAS_LIF,
>>> +   .rpf_count = 5,
>>> +   .wpf_count = 1,
>>> +   .num_bru_inputs = 5,
>>> +   }, {
>>> +   .version = VI6_IP_VERSION_MODEL_VSPDL_GEN3,
>>> +   .model = "VSP2-DL",
>>> +   .gen = 3,
>>> +   .features = VSP1_HAS_BRS | VSP1_HAS_BRU | VSP1_HAS_LIF,
>>
>> Hrm. 32.1.1.7 says:
>> — Vertical flipping in case of outp

[PULL REQUEST: Renesas Drivers] vsp1/pa-improvements (v2)

2017-07-17 Thread Kieran Bingham
Hi Geert,

Please consider the following for integration in Renesas Drivers

This branch (based on a vanilla v4.13-rc1) has been tested successfully on a
Salvator-X (ES 1.0) and Salvator-XS (ES 2.0) (with 5 iterations of the tests
each)


The following changes since commit 5771a8c08880cdca3bfb4a3fc6d309d6bba20877:

  Linux v4.13-rc1 (2017-07-15 15:22:10 -0700)

are available in the git repository at:

  g...@gitolite.kernel.org:pub/scm/linux/kernel/git/kbingham/rcar.git 
vsp1/pa-improvements/v2

for you to fetch changes up to 0bc6b19d31e26b4ee0b5cddff249a9b9493a5d7f:

  v4l: vsp1: Allow entities to participate in the partition algorithm 
(2017-07-17 09:53:18 +0100)


Kieran Bingham (6):
  v4l: vsp1: Move vsp1_video_pipeline_setup_partitions() function
  v4l: vsp1: Calculate partition sizes at stream start.
  v4l: vsp1: Remove redundant context variables
  v4l: vsp1: Move partition rectangles to struct and operate directly
  v4l: vsp1: Provide UDS register updates
  v4l: vsp1: Allow entities to participate in the partition algorithm

 drivers/media/platform/vsp1/vsp1_entity.h |   8 ++
 drivers/media/platform/vsp1/vsp1_pipe.c   |  22 
 drivers/media/platform/vsp1/vsp1_pipe.h   |  48 -
 drivers/media/platform/vsp1/vsp1_regs.h   |  14 +++
 drivers/media/platform/vsp1/vsp1_rpf.c|  31 +++---
 drivers/media/platform/vsp1/vsp1_sru.c|  30 ++
 drivers/media/platform/vsp1/vsp1_uds.c|  43 +++-
 drivers/media/platform/vsp1/vsp1_video.c  | 163 +-
 drivers/media/platform/vsp1/vsp1_wpf.c|  33 --
 9 files changed, 289 insertions(+), 103 deletions(-)


Re: [PATCH] drm: rcar-du: Setup planes before enabling CRTC to avoid flicker

2017-07-17 Thread Kieran Bingham
Hi Maxime,

On 17/07/17 07:32, Maxime Ripard wrote:
> On Thu, Jul 13, 2017 at 05:25:08PM +0100, Kieran Bingham wrote:
>>>>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c 
>>>>> b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
>>>>> index 82b978a5dae6..c2f382feca07 100644
>>>>> --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
>>>>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
>>>>> @@ -255,9 +255,9 @@ static void rcar_du_atomic_commit_tail(struct 
>>>>> drm_atomic_state *old_state)
>>>>>  
>>>>>   /* Apply the atomic update. */
>>>>>   drm_atomic_helper_commit_modeset_disables(dev, old_state);
>>>>> - drm_atomic_helper_commit_modeset_enables(dev, old_state);
>>>>>   drm_atomic_helper_commit_planes(dev, old_state,
>>>>>   DRM_PLANE_COMMIT_ACTIVE_ONLY);
>>>>
>>>> Except for DRM_PLANE_COMMIT_ACTIVE_ONLY, this function now looks very much 
>>>> like
>>>> the default drm_atomic_helper_commit_tail() code.
>>>>
>>>> Reading around other uses /variants of commit_tail() style functions in 
>>>> other
>>>> drivers has left me confused as to how the ordering affects things here.
>>>>
>>>> Could be worth adding a comment at least to describe why we can't use the
>>>> default helper...
>>>
>>> Or better still ... Use Maxime's new :
>>>
>>> [PATCH 1/4] drm/atomic: implement drm_atomic_helper_commit_tail for 
>>> runtime_pm users
>>
>> Never mind - I've just looked again, and seen that this new helper function 
>> is
>> the ordering previous to *this* patch, and therefore isn't the same.
>>
>> However - it's worth noting that Maxime's patch converts this function to the
>> new helper - which contradicts this patch's motivations.
> 
> So I guess I should drop the renesas modifications in my serie then?

Yes, Please.

I think we have a few extra modifications in this function as well which will
take it further away from a default implementation.

Regards

Kieran

> 
> Maxime
> 


Re: [PATCH v2 2/3] drm: rcar-du: Fix planes to CRTC assignment when using the VSP

2017-07-12 Thread Kieran Bingham
Hi Laurent,

Thanks for the patch

Only a minor nit on one comment, but aside from that,

On 11/07/17 23:29, Laurent Pinchart wrote:
> The DU can compose the output of a VSP with other planes on Gen2
> hardware, and of two VSPs on Gen3 hardware. Neither of these features
> are supported by the driver, and the current implementation always
> assigns planes to CRTCs the same way.
> 
> Simplify the implementation by configuring plane assignment when setting
> up DU groups, instead of recomputing it for every atomic plane update.
> This allows skipping the wait for vertical blanking when stopping a
> CRTC, as there's no need to reconfigure plane assignment at that point.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>

Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c  | 31 ---
>  drivers/gpu/drm/rcar-du/rcar_du_group.c | 12 
>  drivers/gpu/drm/rcar-du/rcar_du_kms.c   | 28 +---
>  drivers/gpu/drm/rcar-du/rcar_du_plane.c | 10 +-
>  drivers/gpu/drm/rcar-du/rcar_du_vsp.c   |  9 -
>  5 files changed, 46 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c 
> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index 17fd1cd5212c..413ab032afed 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -315,6 +315,10 @@ static void rcar_du_crtc_update_planes(struct 
> rcar_du_crtc *rcrtc)
>   unsigned int i;
>   u32 dspr = 0;
>  
> + /* Plane assignment is fixed when using the VSP. */
> + if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE))
> + return;
> +
>   for (i = 0; i < rcrtc->group->num_planes; ++i) {
>   struct rcar_du_plane *plane = >group->planes[i];
>   unsigned int j;
> @@ -351,17 +355,6 @@ static void rcar_du_crtc_update_planes(struct 
> rcar_du_crtc *rcrtc)
>   }
>   }
>  
> - /* If VSP+DU integration is enabled the plane assignment is fixed. */
> - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) {
> - if (rcdu->info->gen < 3) {
> - dspr = (rcrtc->index % 2) + 1;
> - hwplanes = 1 << (rcrtc->index % 2);
> - } else {
> - dspr = (rcrtc->index % 2) ? 3 : 1;
> - hwplanes = 1 << ((rcrtc->index % 2) ? 2 : 0);
> - }
> - }
> -
>   /*
>* Update the planes to display timing and dot clock generator
>* associations.
> @@ -462,8 +455,13 @@ static void rcar_du_crtc_setup(struct rcar_du_crtc 
> *rcrtc)
>   rcar_du_crtc_set_display_timing(rcrtc);
>   rcar_du_group_set_routing(rcrtc->group);
>  
> - /* Start with all planes disabled. */
> - rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
> + /*
> +  * Start with all planes disabled, except when using the VSP in which
> +  * case the fixed plane assignment must not be modified.
> +  */
> + if (!rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
> + rcar_du_group_write(rcrtc->group,
> + rcrtc->index % 2 ? DS2PR : DS1PR, 0);
>  
>   /* Enable the VSP compositor. */
>   if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
> @@ -505,8 +503,11 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
>* are stopped in one operation as we now wait for one vblank per CRTC.
>* Whether this can be improved needs to be researched.
>*/
> - rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
> - drm_crtc_wait_one_vblank(crtc);
> + if (!rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) {
> + rcar_du_group_write(rcrtc->group,
> + rcrtc->index % 2 ? DS2PR : DS1PR, 0);
> + drm_crtc_wait_one_vblank(crtc);
> + }
>  
>   /*
>* Disable vertical blanking interrupt reporting. We first need to wait
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c 
> b/drivers/gpu/drm/rcar-du/rcar_du_group.c
> index 00d5f470d377..d26b647207b8 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
> @@ -126,6 +126,18 @@ static void rcar_du_group_setup(struct rcar_du_group 
> *rgrp)
>   if (rcdu->info->gen >= 3)
>   rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10);
>  
> + if (rcar_du_ha

Re: [PATCH 2/2] drm: rcar-du: Add HDMI outputs to R8A7796 device description

2017-07-12 Thread Kieran Bingham
Hi Laurent,

This looks good to me.

Table 35.1 (in the DU datasheet) certainly shows that there is only an HDMI-IF0
on the M3, but it's amusing that (and I was confused by the fact that) my
r8a7796 board (Salvator-X) still has the HDMI1 populated. Of course I presume
this is populated to keep the boards the same but is not connected in the chip.

Anyway, that's irrelevant to this patch so ...

On 21/06/17 10:04, Laurent Pinchart wrote:
> Update the device description with the HDMI output.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>

Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c | 10 --
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c 
> b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> index d6a0255181cc..fc0ae0947b8f 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> @@ -180,19 +180,25 @@ static const struct rcar_du_device_info 
> rcar_du_r8a7796_info = {
> | RCAR_DU_FEATURE_VSP1_SOURCE,
>   .num_crtcs = 3,
>   .routes = {
> - /* R8A7796 has one RGB output, one LVDS output and one
> -  * (currently unsupported) HDMI output.
> + /*
> +  * R8A7796 has one RGB output, one LVDS output and one HDMI
> +  * output.
>*/
>   [RCAR_DU_OUTPUT_DPAD0] = {
>   .possible_crtcs = BIT(2),
>   .port = 0,
>   },
> + [RCAR_DU_OUTPUT_HDMI0] = {
> + .possible_crtcs = BIT(1),
> + .port = 1,
> + },
>   [RCAR_DU_OUTPUT_LVDS0] = {
>   .possible_crtcs = BIT(0),
>   .port = 2,
>   },
>   },
>   .num_lvds = 1,
> + .dpll_ch =  BIT(1),
>  };
>  
>  static const struct of_device_id rcar_du_of_table[] = {
> 


Re: [PATCH 2/2] drm: rcar-du: Add HDMI outputs to R8A7796 device description

2017-07-12 Thread Kieran Bingham
Hi Geert,

> Indeed.
> 
> BTW, the M3-W version also has unconnected USB3 and SATA connectors.

Thanks for the heads up :) - I've just put a post it note over those, +HDMI1-OUT
(or rather the text on the top lid) to prevent any confusion for me down the 
line.

--
Kieran


Re: [PATCH] drm: rcar-du: Setup planes before enabling CRTC to avoid flicker

2017-07-12 Thread Kieran Bingham
Hi Laurent,

On 28/06/17 19:50, Laurent Pinchart wrote:
> Commit 52055bafa1ff ("drm: rcar-du: Move plane commit code from CRTC
> start to CRTC resume") changed the order of the plane commit and CRTC
> enable operations to accommodate the runtime PM requirements. However,
> this introduced corruption in the first displayed frame, as the CRTC is
> now enabled without any plane configured. On Gen2 hardware the first
> frame will be black and likely unnoticed, but on Gen3 hardware we end up
> starting the display before the VSP compositor, which is more
> noticeable.
> 
> To fix this, revert the order of the commit operations back, and handle
> runtime PM requirements in the CRTC .atomic_begin() and .atomic_enable()
> helper operation handlers.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>

I only have code reduction or comment suggestions below - so either with or
without those changes, feel free to add my:

Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 66 
> --
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  4 +--
>  drivers/gpu/drm/rcar-du/rcar_du_kms.c  |  2 +-
>  3 files changed, 43 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c 
> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index 6b5219ef0ad2..76cdb88b2b8e 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -448,14 +448,8 @@ static void rcar_du_crtc_wait_page_flip(struct 
> rcar_du_crtc *rcrtc)
>   * Start/Stop and Suspend/Resume
>   */
>  
> -static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
> +static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc)
>  {
> - struct drm_crtc *crtc = >crtc;
> - bool interlaced;
> -
> - if (rcrtc->started)
> - return;
> -
>   /* Set display off and background to black */
>   rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
>   rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
> @@ -467,6 +461,18 @@ static void rcar_du_crtc_start(struct rcar_du_crtc 
> *rcrtc)
>   /* Start with all planes disabled. */
>   rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
>  
> + /* Enable the VSP compositor. */
> + if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
> + rcar_du_vsp_enable(rcrtc);
> +
> + /* Turn vertical blanking interrupt reporting on. */
> + drm_crtc_vblank_on(>crtc);
> +}
> +
> +static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
> +{
> + bool interlaced;
> +
>   /* Select master sync mode. This enables display operation in master

Are we close enough here to fix this multiline comment style ?
(Not worth doing unless the patch is respun for other reasons ...)

Actually - there are a lot in this file, so it would be better to do them all in
one hit/patch at a point of least conflicts ...


>* sync mode (with the HSYNC and VSYNC signals configured as outputs and
>* actively driven).
> @@ -477,24 +483,12 @@ static void rcar_du_crtc_start(struct rcar_du_crtc 
> *rcrtc)
>DSYSR_TVM_MASTER);
>  
>   rcar_du_group_start_stop(rcrtc->group, true);
> -
> - /* Enable the VSP compositor. */
> - if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
> - rcar_du_vsp_enable(rcrtc);
> -
> - /* Turn vertical blanking interrupt reporting back on. */
> - drm_crtc_vblank_on(crtc);
> -
> - rcrtc->started = true;
>  }
>  
>  static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
>  {
>   struct drm_crtc *crtc = >crtc;
>  
> - if (!rcrtc->started)
> - return;
> -
>   /* Disable all planes and wait for the change to take effect. This is
>* required as the DSnPR registers are updated on vblank, and no vblank
>* will occur once the CRTC is stopped. Disabling planes when starting
> @@ -525,8 +519,6 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
>   rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH);
>  
>   rcar_du_group_start_stop(rcrtc->group, false);
> -
> - rcrtc->started = false;
>  }
>  
>  void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc)
> @@ -546,12 +538,10 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
>   return;
>  
>   rcar_du_crtc_get(rcrtc);
> - rcar_du_crtc_start(rcrtc);
> + rcar_du_crtc_setup(rcrtc);

Every call to _setup is immediately prefixed by a call to _get()

Could the _get() 

Re: [PATCH] drm: rcar-du: Fix comments to comply with the kernel coding style

2017-07-13 Thread Kieran Bingham
Hi Laurent,

Thanks for this - I think that's a better way forward in this instance now that
a few of the locations have been touched, rather than leaving the driver in a
mixed state.

On 12/07/17 18:00, Laurent Pinchart wrote:
> To avoid mixing comment styles when new comments complying with the
> kernel coding style are introduced, fix all multiline comments in one
> go.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>
Acked-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c| 24 --
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c | 21 ++--
>  drivers/gpu/drm/rcar-du/rcar_du_group.c   | 18 -
>  drivers/gpu/drm/rcar-du/rcar_du_kms.c | 18 -
>  drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c | 12 ++---
>  drivers/gpu/drm/rcar-du/rcar_du_plane.c   | 42 
> ---
>  drivers/gpu/drm/rcar-du/rcar_du_plane.h   |  3 ++-
>  drivers/gpu/drm/rcar-du/rcar_du_vsp.c |  6 +++--
>  8 files changed, 96 insertions(+), 48 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c 
> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index f131fc68cc46..a04802f7b2f1 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -168,7 +168,8 @@ static void rcar_du_crtc_set_display_timing(struct 
> rcar_du_crtc *rcrtc)
>   u32 escr;
>   u32 div;
>  
> - /* Compute the clock divisor and select the internal or external dot
> + /*
> +  * Compute the clock divisor and select the internal or external dot
>* clock based on the requested frequency.
>*/
>   clk = clk_get_rate(rcrtc->clock);
> @@ -261,12 +262,14 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
>   struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
>   struct rcar_du_device *rcdu = rcrtc->group->dev;
>  
> - /* Store the route from the CRTC output to the DU output. The DU will be
> + /*
> +  * Store the route from the CRTC output to the DU output. The DU will be
>* configured when starting the CRTC.
>*/
>   rcrtc->outputs |= BIT(output);
>  
> - /* Store RGB routing to DPAD0, the hardware will be configured when
> + /*
> +  * Store RGB routing to DPAD0, the hardware will be configured when
>* starting the CRTC.
>*/
>   if (output == RCAR_DU_OUTPUT_DPAD0)
> @@ -342,7 +345,8 @@ static void rcar_du_crtc_update_planes(struct 
> rcar_du_crtc *rcrtc)
>   }
>   }
>  
> - /* Update the planes to display timing and dot clock generator
> + /*
> +  * Update the planes to display timing and dot clock generator
>* associations.
>*
>* Updating the DPTSR register requires restarting the CRTC group,
> @@ -450,7 +454,8 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
>   /* Start with all planes disabled. */
>   rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
>  
> - /* Select master sync mode. This enables display operation in master
> + /*
> +  * Select master sync mode. This enables display operation in master
>* sync mode (with the HSYNC and VSYNC signals configured as outputs and
>* actively driven).
>*/
> @@ -478,7 +483,8 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
>   if (!rcrtc->started)
>   return;
>  
> - /* Disable all planes and wait for the change to take effect. This is
> + /*
> +  * Disable all planes and wait for the change to take effect. This is
>* required as the DSnPR registers are updated on vblank, and no vblank
>* will occur once the CRTC is stopped. Disabling planes when starting
>* the CRTC thus wouldn't be enough as it would start scanning out
> @@ -491,7 +497,8 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
>   rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
>   drm_crtc_wait_one_vblank(crtc);
>  
> - /* Disable vertical blanking interrupt reporting. We first need to wait
> + /*
> +  * Disable vertical blanking interrupt reporting. We first need to wait
>* for page flip completion before stopping the CRTC as userspace
>* expects page flips to eventually complete.
>*/
> @@ -502,7 +509,8 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
>   if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
>   rcar_du_vsp_disable(rcrtc);
>  
> - /* Select switch sync mode. This stops display oper

[PATCH v2 5/6] v4l: vsp1: Provide UDS register updates

2017-07-14 Thread Kieran Bingham
Provide register definitions required for UDS phase and partition
algorithm support.

These registers are applicable to Gen3 hardware only.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_regs.h | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_regs.h 
b/drivers/media/platform/vsp1/vsp1_regs.h
index 58d0bea963a6..26c4ffad2f46 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -396,6 +396,7 @@
 #define VI6_UDS_CTRL_NE_RCR(1 << 18)
 #define VI6_UDS_CTRL_NE_GY (1 << 17)
 #define VI6_UDS_CTRL_NE_BCB(1 << 16)
+#define VI6_UDS_CTRL_AMDSLH(1 << 2)
 #define VI6_UDS_CTRL_TDIPC (1 << 1)
 
 #define VI6_UDS_SCALE  0x2304
@@ -428,11 +429,24 @@
 #define VI6_UDS_PASS_BWIDTH_V_MASK (0x7f << 0)
 #define VI6_UDS_PASS_BWIDTH_V_SHIFT0
 
+#define VI6_UDS_HPHASE 0x2314
+#define VI6_UDS_HPHASE_HSTP_MASK   (0xfff << 16)
+#define VI6_UDS_HPHASE_HSTP_SHIFT  16
+#define VI6_UDS_HPHASE_HEDP_MASK   (0xfff << 0)
+#define VI6_UDS_HPHASE_HEDP_SHIFT  0
+
 #define VI6_UDS_IPC0x2318
 #define VI6_UDS_IPC_FIELD  (1 << 27)
 #define VI6_UDS_IPC_VEDP_MASK  (0xfff << 0)
 #define VI6_UDS_IPC_VEDP_SHIFT 0
 
+#define VI6_UDS_HSZCLIP0x231c
+#define VI6_UDS_HSZCLIP_HCEN   (1 << 28)
+#define VI6_UDS_HSZCLIP_HCL_OFST_MASK  (0xff << 16)
+#define VI6_UDS_HSZCLIP_HCL_OFST_SHIFT 16
+#define VI6_UDS_HSZCLIP_HCL_SIZE_MASK  (0x1fff << 0)
+#define VI6_UDS_HSZCLIP_HCL_SIZE_SHIFT 0
+
 #define VI6_UDS_CLIP_SIZE  0x2324
 #define VI6_UDS_CLIP_SIZE_HSIZE_MASK   (0x1fff << 16)
 #define VI6_UDS_CLIP_SIZE_HSIZE_SHIFT  16
-- 
git-series 0.9.1


[PATCH v2 4/6] v4l: vsp1: Move partition rectangles to struct and operate directly

2017-07-14 Thread Kieran Bingham
As we develop the partition algorithm, we need to store more information
per partition to describe the phase and other parameters.

To keep this data together, further abstract the existing v4l2_rect
into a partition specific structure

When generating the partition windows, operate directly on the partition
struct rather than copying and duplicating the processed data

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_pipe.h  | 12 +-
 drivers/media/platform/vsp1/vsp1_rpf.c   |  4 +-
 drivers/media/platform/vsp1/vsp1_uds.c   |  8 ++--
 drivers/media/platform/vsp1/vsp1_video.c | 50 +
 drivers/media/platform/vsp1/vsp1_wpf.c   | 14 +++
 5 files changed, 50 insertions(+), 38 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index f440d0891bea..44506a315b5d 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -58,6 +58,14 @@ enum vsp1_pipeline_state {
 };
 
 /*
+ * struct vsp1_partition - A description of each partition slice performed by 
HW
+ * @dest: The position and dimension of this partition in the destination image
+ */
+struct vsp1_partition {
+   struct v4l2_rect dest;
+};
+
+/*
  * struct vsp1_pipeline - A VSP1 hardware pipeline
  * @pipe: the media pipeline
  * @irqlock: protects the pipeline state
@@ -114,8 +122,8 @@ struct vsp1_pipeline {
struct vsp1_dl_list *dl;
 
unsigned int partitions;
-   struct v4l2_rect partition;
-   struct v4l2_rect *part_table;
+   struct vsp1_partition *partition;
+   struct vsp1_partition *part_table;
 };
 
 void vsp1_pipeline_reset(struct vsp1_pipeline *pipe);
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c 
b/drivers/media/platform/vsp1/vsp1_rpf.c
index 8feddd59cf8d..48b3e89c0e87 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -108,9 +108,9 @@ static void rpf_configure(struct vsp1_entity *entity,
output = vsp1_entity_get_pad_format(wpf, wpf->config,
RWPF_PAD_SINK);
 
-   crop.width = pipe->partition.width * input_width
+   crop.width = pipe->partition->dest.width * input_width
   / output->width;
-   crop.left += pipe->partition.left * input_width
+   crop.left += pipe->partition->dest.left * input_width
   / output->width;
}
 
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c 
b/drivers/media/platform/vsp1/vsp1_uds.c
index 4226403ad235..ea37ff5aee57 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -272,11 +272,13 @@ static void uds_configure(struct vsp1_entity *entity,
bool multitap;
 
if (params == VSP1_ENTITY_PARAMS_PARTITION) {
-   const struct v4l2_rect *clip = >partition;
+   struct vsp1_partition *partition = pipe->partition;
 
vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE,
-  (clip->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
-  (clip->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
+  (partition->dest.width
+   << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
+  (partition->dest.height
+   << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
return;
}
 
diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index dd94968d0044..42e5608d1ddf 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -185,17 +185,17 @@ static int __vsp1_video_try_format(struct vsp1_video 
*video,
 /**
  * vsp1_video_partition - Calculate the active partition output window
  *
+ * @partition: The active partition data
  * @div_size: pre-determined maximum partition division size
  * @index: partition index
  *
- * Returns a v4l2_rect describing the partition window.
+ * Generates the output partitioning positions.
  */
-static struct v4l2_rect vsp1_video_partition(struct vsp1_pipeline *pipe,
-unsigned int div_size,
-unsigned int index)
+static void vsp1_video_partition(struct vsp1_pipeline *pipe,
+struct vsp1_partition *partition,
+unsigned int div_size, unsigned int index)
 {
const struct v4l2_mbus_framefmt *format;
-   struct v4l2_rect partition;
unsigned int modulus;
 
   

[PATCH v2 3/6] v4l: vsp1: Remove redundant context variables

2017-07-14 Thread Kieran Bingham
The vsp1_pipe object context variables for div_size and
current_partition allowed state to be maintained through processing the
partitions during processing.

Now that the partition tables are calculated during stream on, there is
no requirement to store these variables in the pipe object.

Utilise local variables for the processing as required.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>

---
v2:
 - s/current_partition/partition/
 - s/partition_number/partition/
---
 drivers/media/platform/vsp1/vsp1_pipe.h  |  4 
 drivers/media/platform/vsp1/vsp1_video.c | 22 +++---
 2 files changed, 7 insertions(+), 19 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index d345cc6d0d69..f440d0891bea 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -80,10 +80,8 @@ enum vsp1_pipeline_state {
  * @uds_input: entity at the input of the UDS, if the UDS is present
  * @entities: list of entities in the pipeline
  * @dl: display list associated with the pipeline
- * @div_size: The maximum allowed partition size for the pipeline
  * @partitions: The number of partitions used to process one frame
  * @partition: The current partition for configuration to process
- * @current_partition: The partition number currently being configured
  * @part_table: The pre-calculated partitions used by the pipeline
  */
 struct vsp1_pipeline {
@@ -115,10 +113,8 @@ struct vsp1_pipeline {
 
struct vsp1_dl_list *dl;
 
-   unsigned int div_size;
unsigned int partitions;
struct v4l2_rect partition;
-   unsigned int current_partition;
struct v4l2_rect *part_table;
 };
 
diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index 4155c06e9b42..dd94968d0044 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -280,7 +280,6 @@ static int vsp1_video_pipeline_setup_partitions(struct 
vsp1_pipeline *pipe)
if (pipe->part_table == NULL)
return -ENOMEM;
 
-   pipe->div_size = div_size;
pipe->partitions = 1;
pipe->part_table[0] = vsp1_video_partition(pipe, div_size, 0);
return 0;
@@ -296,7 +295,6 @@ static int vsp1_video_pipeline_setup_partitions(struct 
vsp1_pipeline *pipe)
}
}
 
-   pipe->div_size = div_size;
pipe->partitions = DIV_ROUND_UP(format->width, div_size);
 
pipe->part_table = kcalloc(pipe->partitions, sizeof(*pipe->part_table),
@@ -385,11 +383,12 @@ static void vsp1_video_frame_end(struct vsp1_pipeline 
*pipe,
 }
 
 static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe,
- struct vsp1_dl_list *dl)
+ struct vsp1_dl_list *dl,
+ unsigned int partition)
 {
struct vsp1_entity *entity;
 
-   pipe->partition = pipe->part_table[pipe->current_partition];
+   pipe->partition = pipe->part_table[partition];
 
list_for_each_entry(entity, >entities, list_pipe) {
if (entity->ops->configure)
@@ -402,6 +401,7 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline 
*pipe)
 {
struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
struct vsp1_entity *entity;
+   unsigned int partition;
 
if (!pipe->dl)
pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
@@ -418,20 +418,12 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline 
*pipe)
}
 
/* Run the first partition */
-   pipe->current_partition = 0;
-   vsp1_video_pipeline_run_partition(pipe, pipe->dl);
+   vsp1_video_pipeline_run_partition(pipe, pipe->dl, 0);
 
/* Process consecutive partitions as necessary */
-   for (pipe->current_partition = 1;
-pipe->current_partition < pipe->partitions;
-pipe->current_partition++) {
+   for (partition = 1; partition < pipe->partitions; partition++) {
struct vsp1_dl_list *dl;
 
-   /*
-* Partition configuration operations will utilise
-* the pipe->current_partition variable to determine
-* the work they should complete.
-*/
dl = vsp1_dl_list_get(pipe->output->dlm);
 
/*
@@ -444,7 +436,7 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline 
*pipe)
break;
}
 
-   vsp1_video_pipeline_run_partition(pipe, dl);
+   vsp1_video_pipeline_run_partition(pipe, dl, partition);
vsp1_dl_list_add_chain(pipe->dl, dl);
}
 
-- 
git-series 0.9.1


[PATCH v2 6/6] v4l: vsp1: Allow entities to participate in the partition algorithm

2017-07-14 Thread Kieran Bingham
The configuration of the pipeline and entities directly affects the
inputs required to each entity for the partition algorithm. Thus it
makes sense to involve those entities in the decision making process.

Extend the entity ops API to provide an optional '.partition' operation.
This allows entities that effect the partition window to adapt the
window based on their configuration.

Entities implementing this operation must return their required input
parameters, which will be passed up the pipeline. This creates a process
whereby each entity describes what is required to satisfy the required
output to its predecessor in the pipeline.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

---
v2:
 - vsp1_partition_rect renamed as vsp1_partition_window
 - destination vsp1_partition_window made const to prevent change
 - (currently) unused 'offset' removed.
 - partition functions made static
---
 drivers/media/platform/vsp1/vsp1_entity.h |  8 +-
 drivers/media/platform/vsp1/vsp1_pipe.c   | 22 ++-
 drivers/media/platform/vsp1/vsp1_pipe.h   | 35 --
 drivers/media/platform/vsp1/vsp1_rpf.c| 31 +--
 drivers/media/platform/vsp1/vsp1_sru.c| 30 ++-
 drivers/media/platform/vsp1/vsp1_uds.c| 39 ++--
 drivers/media/platform/vsp1/vsp1_video.c  | 30 ++
 drivers/media/platform/vsp1/vsp1_wpf.c| 33 ++--
 8 files changed, 188 insertions(+), 40 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_entity.h 
b/drivers/media/platform/vsp1/vsp1_entity.h
index 11f8363fa6b0..7475b504ca3b 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -21,6 +21,7 @@
 struct vsp1_device;
 struct vsp1_dl_list;
 struct vsp1_pipeline;
+struct vsp1_partition;
 
 enum vsp1_entity_type {
VSP1_ENTITY_BRS,
@@ -82,12 +83,19 @@ struct vsp1_route {
  * selection rectangles, ...)
  * @max_width: Return the max supported width of data that the entity can
  * process in a single operation.
+ * @partition: Process the partition construction based on this entity's
+ * configuration.
  */
 struct vsp1_entity_operations {
void (*destroy)(struct vsp1_entity *);
void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *,
  struct vsp1_dl_list *, enum vsp1_entity_params);
unsigned int (*max_width)(struct vsp1_entity *, struct vsp1_pipeline *);
+   struct vsp1_partition_window *(*partition)(struct vsp1_entity *,
+   struct vsp1_pipeline *,
+   struct vsp1_partition *,
+   unsigned int,
+   const struct vsp1_partition_window *);
 };
 
 struct vsp1_entity {
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c 
b/drivers/media/platform/vsp1/vsp1_pipe.c
index 4f4b732df84b..8e16f901ab80 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -383,6 +383,28 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline 
*pipe,
vsp1_uds_set_alpha(pipe->uds, dl, alpha);
 }
 
+/*
+ * Propagate the partition calculations through the pipeline
+ *
+ * Work backwards through the pipe, allowing each entity to update the 
partition
+ * parameters based on its configuration, and the entity connected to its
+ * source. Each entity must produce the partition required for the previous
+ * entity in the pipeline.
+ */
+void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
+  struct vsp1_partition *partition,
+  unsigned int index,
+  struct vsp1_partition_window *rect)
+{
+   struct vsp1_entity *entity;
+
+   list_for_each_entry_reverse(entity, >entities, list_pipe) {
+   if (entity->ops->partition)
+   rect = entity->ops->partition(entity, pipe, partition,
+ index, rect);
+   }
+}
+
 void vsp1_pipelines_suspend(struct vsp1_device *vsp1)
 {
unsigned long flags;
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index 44506a315b5d..d5858a308ec0 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -58,11 +58,32 @@ enum vsp1_pipeline_state {
 };
 
 /*
+ * struct vsp1_partition_window
+ *
+ * replicates struct v4l2_rect, but allows us to extend on the needs of each
+ * partition.
+ */
+struct vsp1_partition_window {
+   __s32   left;
+   __s32   top;
+   __u32   width;
+   __u32   height;
+};
+
+/*
  * struct vsp1_partition - A description of each partition slice performed by 
HW
- * @dest: The position and dimension of this partition 

[PATCH v2 2/6] v4l: vsp1: Calculate partition sizes at stream start.

2017-07-14 Thread Kieran Bingham
Previously the active window and partition sizes for each partition were
calculated for each partition every frame. This data is constant and
only needs to be calculated once at the start of the stream.

Extend the vsp1_pipe object to dynamically store the number of partitions
required and pre-calculate the partition sizes into this table.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>

---
v2:
 - Partition table allocated dynamically as required.
 - loop uses unsigned int
 - rebase on top of suspend-resume fix commits
---
 drivers/media/platform/vsp1/vsp1_pipe.h  |  3 ++-
 drivers/media/platform/vsp1/vsp1_video.c | 32 +
 2 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h 
b/drivers/media/platform/vsp1/vsp1_pipe.h
index c5d01a365370..d345cc6d0d69 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -82,7 +82,9 @@ enum vsp1_pipeline_state {
  * @dl: display list associated with the pipeline
  * @div_size: The maximum allowed partition size for the pipeline
  * @partitions: The number of partitions used to process one frame
+ * @partition: The current partition for configuration to process
  * @current_partition: The partition number currently being configured
+ * @part_table: The pre-calculated partitions used by the pipeline
  */
 struct vsp1_pipeline {
struct media_pipeline pipe;
@@ -117,6 +119,7 @@ struct vsp1_pipeline {
unsigned int partitions;
struct v4l2_rect partition;
unsigned int current_partition;
+   struct v4l2_rect *part_table;
 };
 
 void vsp1_pipeline_reset(struct vsp1_pipeline *pipe);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index 03e139f40dcf..4155c06e9b42 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -256,12 +256,13 @@ static struct v4l2_rect vsp1_video_partition(struct 
vsp1_pipeline *pipe,
return partition;
 }
 
-static void vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
+static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
 {
struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
const struct v4l2_mbus_framefmt *format;
struct vsp1_entity *entity;
unsigned int div_size;
+   unsigned int i;
 
/*
 * Partitions are computed on the size before rotation, use the format
@@ -274,9 +275,15 @@ static void vsp1_video_pipeline_setup_partitions(struct 
vsp1_pipeline *pipe)
 
/* Gen2 hardware doesn't require image partitioning. */
if (vsp1->info->gen == 2) {
+   pipe->part_table = kcalloc(1, sizeof(*pipe->part_table),
+  GFP_ATOMIC);
+   if (pipe->part_table == NULL)
+   return -ENOMEM;
+
pipe->div_size = div_size;
pipe->partitions = 1;
-   return;
+   pipe->part_table[0] = vsp1_video_partition(pipe, div_size, 0);
+   return 0;
}
 
list_for_each_entry(entity, >entities, list_pipe) {
@@ -291,6 +298,16 @@ static void vsp1_video_pipeline_setup_partitions(struct 
vsp1_pipeline *pipe)
 
pipe->div_size = div_size;
pipe->partitions = DIV_ROUND_UP(format->width, div_size);
+
+   pipe->part_table = kcalloc(pipe->partitions, sizeof(*pipe->part_table),
+  GFP_ATOMIC);
+   if (pipe->part_table == NULL)
+   return -ENOMEM;
+
+   for (i = 0; i < pipe->partitions; i++)
+   pipe->part_table[i] = vsp1_video_partition(pipe, div_size, i);
+
+   return 0;
 }
 /* 
-
  * Pipeline Management
@@ -372,8 +389,7 @@ static void vsp1_video_pipeline_run_partition(struct 
vsp1_pipeline *pipe,
 {
struct vsp1_entity *entity;
 
-   pipe->partition = vsp1_video_partition(pipe, pipe->div_size,
-  pipe->current_partition);
+   pipe->partition = pipe->part_table[pipe->current_partition];
 
list_for_each_entry(entity, >entities, list_pipe) {
if (entity->ops->configure)
@@ -801,9 +817,12 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
 static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
 {
struct vsp1_entity *entity;
+   int ret;
 
/* Determine this pipelines sizes for image partitioning support. */
-   vsp1_video_pipeline_setup_partitions(pipe);
+   ret = vsp1_video_pipeline_setup_partitions(pipe);
+   if (ret)
+   return ret;
 
/* Prepare the display list. */
pip

[PATCH v2 0/6] vsp1 partition algorithm improvements

2017-07-14 Thread Kieran Bingham
Some updates and initial improvements for the VSP1 partition algorithm that
remove redundant processing and variables, reducing the processing done in
interrupt context slightly.

Patches 1, 2 and 3 clean up the calculation of the partition windows such that
they are only calculated once at streamon.

Patch 4 improves the allocations with a new vsp1_partition object to track each
window state.

Patches 5, and 6 then go on to enhance the partition algorithm by allowing each
entity to calculate the requirements for it's pipeline predecessor to
successfully generate the requested output window. This system allows the
entity objects to specify what they need to fulfil the output for the next
entity in the pipeline.

v2:
 - Rebased to v4.12-rc1
 - Partition tables dynamically allocated
 - review fixups

Kieran Bingham (6):
  v4l: vsp1: Move vsp1_video_pipeline_setup_partitions() function
  v4l: vsp1: Calculate partition sizes at stream start.
  v4l: vsp1: Remove redundant context variables
  v4l: vsp1: Move partition rectangles to struct and operate directly
  v4l: vsp1: Provide UDS register updates
  v4l: vsp1: Allow entities to participate in the partition algorithm

 drivers/media/platform/vsp1/vsp1_entity.h |   8 +-
 drivers/media/platform/vsp1/vsp1_pipe.c   |  22 +++-
 drivers/media/platform/vsp1/vsp1_pipe.h   |  48 ++-
 drivers/media/platform/vsp1/vsp1_regs.h   |  14 ++-
 drivers/media/platform/vsp1/vsp1_rpf.c|  31 ++--
 drivers/media/platform/vsp1/vsp1_sru.c|  30 -
 drivers/media/platform/vsp1/vsp1_uds.c|  43 +-
 drivers/media/platform/vsp1/vsp1_video.c  | 163 ---
 drivers/media/platform/vsp1/vsp1_wpf.c|  33 +++--
 9 files changed, 289 insertions(+), 103 deletions(-)

base-commit: 70e60837e669f6fbc8bba30db9a2244d347643bc
-- 
git-series 0.9.1


[PATCH v2 1/6] v4l: vsp1: Move vsp1_video_pipeline_setup_partitions() function

2017-07-14 Thread Kieran Bingham
Separate the code change from the function move so that code changes can
be clearly identified. This commit has no functional change.

The partition algorithm functions will be changed, and
vsp1_video_pipeline_setup_partitions() will call vsp1_video_partition().
To prepare for that, move the function without any code change.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 73 -
 1 file changed, 36 insertions(+), 37 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c 
b/drivers/media/platform/vsp1/vsp1_video.c
index e9f5dcb8fae5..03e139f40dcf 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -182,43 +182,6 @@ static int __vsp1_video_try_format(struct vsp1_video 
*video,
  * VSP1 Partition Algorithm support
  */
 
-static void vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
-{
-   struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
-   const struct v4l2_mbus_framefmt *format;
-   struct vsp1_entity *entity;
-   unsigned int div_size;
-
-   /*
-* Partitions are computed on the size before rotation, use the format
-* at the WPF sink.
-*/
-   format = vsp1_entity_get_pad_format(>output->entity,
-   pipe->output->entity.config,
-   RWPF_PAD_SINK);
-   div_size = format->width;
-
-   /* Gen2 hardware doesn't require image partitioning. */
-   if (vsp1->info->gen == 2) {
-   pipe->div_size = div_size;
-   pipe->partitions = 1;
-   return;
-   }
-
-   list_for_each_entry(entity, >entities, list_pipe) {
-   unsigned int entity_max = VSP1_VIDEO_MAX_WIDTH;
-
-   if (entity->ops->max_width) {
-   entity_max = entity->ops->max_width(entity, pipe);
-   if (entity_max)
-   div_size = min(div_size, entity_max);
-   }
-   }
-
-   pipe->div_size = div_size;
-   pipe->partitions = DIV_ROUND_UP(format->width, div_size);
-}
-
 /**
  * vsp1_video_partition - Calculate the active partition output window
  *
@@ -293,6 +256,42 @@ static struct v4l2_rect vsp1_video_partition(struct 
vsp1_pipeline *pipe,
return partition;
 }
 
+static void vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
+{
+   struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+   const struct v4l2_mbus_framefmt *format;
+   struct vsp1_entity *entity;
+   unsigned int div_size;
+
+   /*
+* Partitions are computed on the size before rotation, use the format
+* at the WPF sink.
+*/
+   format = vsp1_entity_get_pad_format(>output->entity,
+   pipe->output->entity.config,
+   RWPF_PAD_SINK);
+   div_size = format->width;
+
+   /* Gen2 hardware doesn't require image partitioning. */
+   if (vsp1->info->gen == 2) {
+   pipe->div_size = div_size;
+   pipe->partitions = 1;
+   return;
+   }
+
+   list_for_each_entry(entity, >entities, list_pipe) {
+   unsigned int entity_max = VSP1_VIDEO_MAX_WIDTH;
+
+   if (entity->ops->max_width) {
+   entity_max = entity->ops->max_width(entity, pipe);
+   if (entity_max)
+   div_size = min(div_size, entity_max);
+   }
+   }
+
+   pipe->div_size = div_size;
+   pipe->partitions = DIV_ROUND_UP(format->width, div_size);
+}
 /* 
-
  * Pipeline Management
  */
-- 
git-series 0.9.1


[PATCH 6/6] v4l: vsp1: Remove old fragment management

2017-07-14 Thread Kieran Bingham
Fragments are no longer 'freed' in interrupt context, but instead released back
to their respective pools.

This allows us to remove the garbage collector in the DLM.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c | 151 ++-
 1 file changed, 14 insertions(+), 137 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
b/drivers/media/platform/vsp1/vsp1_dl.c
index 95f2303d37b9..07349fc94372 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -146,9 +146,6 @@ struct vsp1_dl_manager {
struct vsp1_dl_list *pending;
 
struct vsp1_dl_fragment_pool *pool;
-
-   struct work_struct gc_work;
-   struct list_head gc_fragments;
 };
 
 /* 
-
@@ -252,90 +249,6 @@ void vsp1_dl_fragment_put(struct vsp1_dl_body *dlb)
spin_unlock_irqrestore(>pool->lock, flags);
 }
 
-/*
- * Initialize a display list body object and allocate DMA memory for the body
- * data. The display list body object is expected to have been initialized to
- * 0 when allocated.
- */
-static int vsp1_dl_body_init(struct vsp1_device *vsp1,
-struct vsp1_dl_body *dlb, unsigned int num_entries,
-size_t extra_size)
-{
-   size_t size = num_entries * sizeof(*dlb->entries) + extra_size;
-
-   dlb->vsp1 = vsp1;
-   dlb->size = size;
-   dlb->max_entries = num_entries;
-
-   dlb->entries = dma_alloc_wc(vsp1->bus_master, dlb->size, >dma,
-   GFP_KERNEL);
-   if (!dlb->entries)
-   return -ENOMEM;
-
-   return 0;
-}
-
-/*
- * Cleanup a display list body and free allocated DMA memory allocated.
- */
-static void vsp1_dl_body_cleanup(struct vsp1_dl_body *dlb)
-{
-   dma_free_wc(dlb->vsp1->bus_master, dlb->size, dlb->entries, dlb->dma);
-}
-
-/**
- * vsp1_dl_fragment_alloc - Allocate a display list fragment
- * @vsp1: The VSP1 device
- * @num_entries: The maximum number of entries that the fragment can contain
- *
- * Allocate a display list fragment with enough memory to contain the requested
- * number of entries.
- *
- * Return a pointer to a fragment on success or NULL if memory can't be
- * allocated.
- */
-struct vsp1_dl_body *vsp1_dl_fragment_alloc(struct vsp1_device *vsp1,
-   unsigned int num_entries)
-{
-   struct vsp1_dl_body *dlb;
-   int ret;
-
-   dlb = kzalloc(sizeof(*dlb), GFP_KERNEL);
-   if (!dlb)
-   return NULL;
-
-   ret = vsp1_dl_body_init(vsp1, dlb, num_entries, 0);
-   if (ret < 0) {
-   kfree(dlb);
-   return NULL;
-   }
-
-   return dlb;
-}
-
-/**
- * vsp1_dl_fragment_free - Free a display list fragment
- * @dlb: The fragment
- *
- * Free the given display list fragment and the associated DMA memory.
- *
- * Fragments must only be freed explicitly if they are not added to a display
- * list, as the display list will take ownership of them and free them
- * otherwise. Manual free typically happens at cleanup time for fragments that
- * have been allocated but not used.
- *
- * Passing a NULL pointer to this function is safe, in that case no operation
- * will be performed.
- */
-void vsp1_dl_fragment_free(struct vsp1_dl_body *dlb)
-{
-   if (!dlb)
-   return;
-
-   vsp1_dl_body_cleanup(dlb);
-   kfree(dlb);
-}
-
 /**
  * vsp1_dl_fragment_write - Write a register to a display list fragment
  * @dlb: The fragment
@@ -392,10 +305,21 @@ static struct vsp1_dl_list *vsp1_dl_list_alloc(struct 
vsp1_dl_manager *dlm,
return dl;
 }
 
+static void vsp1_dl_list_fragments_free(struct vsp1_dl_list *dl)
+{
+   struct vsp1_dl_body *dlb, *tmp;
+
+   list_for_each_entry_safe(dlb, tmp, >fragments, list) {
+   list_del(>list);
+   vsp1_dl_fragment_put(dlb);
+   }
+}
+
 static void vsp1_dl_list_free(struct vsp1_dl_list *dl)
 {
vsp1_dl_fragment_put(dl->body0);
-   list_splice_init(>fragments, >dlm->gc_fragments);
+   vsp1_dl_list_fragments_free(dl);
+
kfree(dl);
 }
 
@@ -449,17 +373,9 @@ static void __vsp1_dl_list_put(struct vsp1_dl_list *dl)
 
dl->has_chain = false;
 
-   /*
-* We can't free fragments here as DMA memory can only be freed in
-* interruptible context. Move all fragments to the display list
-* manager's list of fragments to be freed, they will be
-* garbage-collected by the work queue.
-*/
-   if (!list_empty(>fragments)) {
-   list_splice_init(>fragments, >dlm->gc_fragments);
-   schedule_work(>dlm->gc_work);
-   }
+   vsp1_dl_list_fragments_free(dl);
 
+   /* body0 is reused */
d

[PATCH 2/6] v4l: vsp1: Provide a fragment pool

2017-07-14 Thread Kieran Bingham
Each display list allocates a body to store register values in a dma
accessible buffer from a dma_alloc_wc() allocation. Each of these
results in an entry in the TLB, and a large number of display list
allocations adds pressure to this resource.

Reduce TLB pressure on the IPMMUs by allocating multiple display list
bodies in a single allocation, and providing these to the display list
through a 'fragment pool'. A pool can be allocated by the display list
manager or entities which require their own body allocations.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c | 124 +++-
 drivers/media/platform/vsp1/vsp1_dl.h |   8 ++-
 2 files changed, 132 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
b/drivers/media/platform/vsp1/vsp1_dl.c
index 1311e7cf2733..8b1118c2e8f5 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -45,6 +45,7 @@ struct vsp1_dl_entry {
 /**
  * struct vsp1_dl_body - Display list body
  * @list: entry in the display list list of bodies
+ * @pool: entry in the pool list for free/used dlbs
  * @vsp1: the VSP1 device
  * @entries: array of entries
  * @dma: DMA address of the entries
@@ -53,6 +54,9 @@ struct vsp1_dl_entry {
  */
 struct vsp1_dl_body {
struct list_head list;
+   struct list_head free;
+
+   struct vsp1_dl_fragment_pool *pool;
struct vsp1_device *vsp1;
 
struct vsp1_dl_entry *entries;
@@ -64,6 +68,29 @@ struct vsp1_dl_body {
 };
 
 /**
+ * struct vsp1_dl_fragment_pool - display list body/fragment pool
+ * @dma: DMA address of the entries
+ * @size: size of the full DMA memory pool in bytes
+ * @mem: CPU memory pointer for the pool
+ * @bodies: Array of DLB structures for the pool
+ * @free: List of free DLB entries
+ * @used: List of active DLB entries
+ */
+struct vsp1_dl_fragment_pool {
+   /* DMA allocation */
+   dma_addr_t dma;
+   size_t size;
+   void *mem;
+
+   /* Body management */
+   struct vsp1_dl_body *bodies;
+   struct list_head free;
+   spinlock_t lock;
+
+   struct vsp1_device *vsp1;
+};
+
+/**
  * struct vsp1_dl_list - Display list
  * @list: entry in the display list manager lists
  * @dlm: the display list manager
@@ -118,6 +145,8 @@ struct vsp1_dl_manager {
struct vsp1_dl_list *queued;
struct vsp1_dl_list *pending;
 
+   struct vsp1_dl_fragment_pool *pool;
+
struct work_struct gc_work;
struct list_head gc_fragments;
 };
@@ -127,6 +156,101 @@ struct vsp1_dl_manager {
  */
 
 /*
+ * Fragment pool's reduce the pressure on the iommu TLB by allocating a single
+ * large area of DMA memory and allocating it as a pool of fragment bodies
+ */
+struct vsp1_dl_fragment_pool *
+vsp1_dl_fragment_pool_alloc(struct vsp1_device *vsp1, unsigned int qty,
+   unsigned int num_entries, size_t extra_size)
+{
+   struct vsp1_dl_fragment_pool *pool;
+   size_t dlb_size;
+   unsigned int i;
+
+   pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+   if (!pool)
+   return NULL;
+
+   pool->vsp1 = vsp1;
+
+   dlb_size = num_entries * sizeof(struct vsp1_dl_entry) + extra_size;
+   pool->size = dlb_size * qty;
+
+   pool->bodies = kcalloc(qty, sizeof(*pool->bodies), GFP_KERNEL);
+   if (!pool->bodies) {
+   kfree(pool);
+   return NULL;
+   }
+
+   pool->mem = dma_alloc_wc(vsp1->bus_master, pool->size, >dma,
+   GFP_KERNEL);
+   if (!pool->mem) {
+   kfree(pool->bodies);
+   kfree(pool);
+   return NULL;
+   }
+
+   spin_lock_init(>lock);
+   INIT_LIST_HEAD(>free);
+
+   for (i = 0; i < qty; ++i) {
+   struct vsp1_dl_body *dlb = >bodies[i];
+
+   dlb->pool = pool;
+   dlb->max_entries = num_entries;
+   dlb->entries = pool->mem + i * dlb_size;
+
+   list_add_tail(>free, >free);
+   }
+
+   return pool;
+}
+
+void vsp1_dl_fragment_pool_free(struct vsp1_dl_fragment_pool *pool)
+{
+   if (!pool)
+   return;
+
+   if (pool->mem)
+   dma_free_wc(pool->vsp1->bus_master, pool->size, pool->mem,
+   pool->dma);
+
+   kfree(pool->bodies);
+   kfree(pool);
+}
+
+struct vsp1_dl_body *vsp1_dl_fragment_get(struct vsp1_dl_fragment_pool *pool)
+{
+   struct vsp1_dl_body *dlb = NULL;
+   unsigned long flags;
+
+   spin_lock_irqsave(>lock, flags);
+
+   if (!list_empty(>free)) {
+   dlb = list_first_entry(>free, struct vsp1_dl_body, free);
+   list_del(>free);
+   }
+
+   spin_unlock_irqrestore(>lock, flags);
+
+   return dlb;
+}
+
+void vsp1_dl_fragment_put(struct vsp

[PATCH 3/6] v4l: vsp1: Convert display lists to use new fragment pool

2017-07-14 Thread Kieran Bingham
Adapt the dl->body0 object to use an object from the fragment pool.
This greatly reduces the pressure on the TLB for IPMMU use cases, as
all of the lists use a single allocation for the main body

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c | 68 +++-
 1 file changed, 37 insertions(+), 31 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
b/drivers/media/platform/vsp1/vsp1_dl.c
index 8b1118c2e8f5..95f2303d37b9 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -107,7 +107,7 @@ struct vsp1_dl_list {
struct vsp1_dl_header *header;
dma_addr_t dma;
 
-   struct vsp1_dl_body body0;
+   struct vsp1_dl_body *body0;
struct list_head fragments;
 
bool has_chain;
@@ -198,6 +198,8 @@ vsp1_dl_fragment_pool_alloc(struct vsp1_device *vsp1, 
unsigned int qty,
 
dlb->pool = pool;
dlb->max_entries = num_entries;
+
+   dlb->dma = pool->dma + i * dlb_size;
dlb->entries = pool->mem + i * dlb_size;
 
list_add_tail(>free, >free);
@@ -360,11 +362,10 @@ void vsp1_dl_fragment_write(struct vsp1_dl_body *dlb, u32 
reg, u32 data)
  * Display List Transaction Management
  */
 
-static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
+static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm,
+   struct vsp1_dl_fragment_pool *pool)
 {
struct vsp1_dl_list *dl;
-   size_t header_size;
-   int ret;
 
dl = kzalloc(sizeof(*dl), GFP_KERNEL);
if (!dl)
@@ -373,32 +374,19 @@ static struct vsp1_dl_list *vsp1_dl_list_alloc(struct 
vsp1_dl_manager *dlm)
INIT_LIST_HEAD(>fragments);
dl->dlm = dlm;
 
-   /*
-* Initialize the display list body and allocate DMA memory for the body
-* and the optional header. Both are allocated together to avoid memory
-* fragmentation, with the header located right after the body in
-* memory.
-*/
-   header_size = dlm->mode == VSP1_DL_MODE_HEADER
-   ? ALIGN(sizeof(struct vsp1_dl_header), 8)
-   : 0;
-
-   ret = vsp1_dl_body_init(dlm->vsp1, >body0, VSP1_DL_NUM_ENTRIES,
-   header_size);
-   if (ret < 0) {
-   kfree(dl);
+   /* Retrieve a body from our DLM body pool */
+   dl->body0 = vsp1_dl_fragment_get(pool);
+   if (!dl->body0)
return NULL;
-   }
-
if (dlm->mode == VSP1_DL_MODE_HEADER) {
size_t header_offset = VSP1_DL_NUM_ENTRIES
-* sizeof(*dl->body0.entries);
+* sizeof(*dl->body0->entries);
 
-   dl->header = ((void *)dl->body0.entries) + header_offset;
-   dl->dma = dl->body0.dma + header_offset;
+   dl->header = ((void *)dl->body0->entries) + header_offset;
+   dl->dma = dl->body0->dma + header_offset;
 
memset(dl->header, 0, sizeof(*dl->header));
-   dl->header->lists[0].addr = dl->body0.dma;
+   dl->header->lists[0].addr = dl->body0->dma;
}
 
return dl;
@@ -406,7 +394,7 @@ static struct vsp1_dl_list *vsp1_dl_list_alloc(struct 
vsp1_dl_manager *dlm)
 
 static void vsp1_dl_list_free(struct vsp1_dl_list *dl)
 {
-   vsp1_dl_body_cleanup(>body0);
+   vsp1_dl_fragment_put(dl->body0);
list_splice_init(>fragments, >dlm->gc_fragments);
kfree(dl);
 }
@@ -472,7 +460,7 @@ static void __vsp1_dl_list_put(struct vsp1_dl_list *dl)
schedule_work(>dlm->gc_work);
}
 
-   dl->body0.num_entries = 0;
+   dl->body0->num_entries = 0;
 
list_add_tail(>list, >dlm->free);
 }
@@ -509,7 +497,7 @@ void vsp1_dl_list_put(struct vsp1_dl_list *dl)
  */
 void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-   vsp1_dl_fragment_write(>body0, reg, data);
+   vsp1_dl_fragment_write(dl->body0, reg, data);
 }
 
 /**
@@ -581,7 +569,7 @@ static void vsp1_dl_list_fill_header(struct vsp1_dl_list 
*dl, bool is_last)
 * list was allocated.
 */
 
-   hdr->num_bytes = dl->body0.num_entries
+   hdr->num_bytes = dl->body0->num_entries
   * sizeof(*dl->header->lists);
 
list_for_each_entry(dlb, >fragments, list) {
@@ -654,9 +642,9 @@ static void vsp1_dl_list_hw_enqueue(struct vsp1_dl_list *dl)
 * bit will be cleared by the hardware when the display list
 * processing starts.
 */
-   vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl

[PATCH 1/6] v4l: vsp1: Protect fragments against overflow

2017-07-14 Thread Kieran Bingham
The fragment write function relies on the code never asking it to
write more than the entries available in the list.

Currently with each list body containing 256 entries, this is fine,
but we can reduce this number greatly saving memory.

In preparation of this - add a level of protection to catch any
buffer overflows

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
b/drivers/media/platform/vsp1/vsp1_dl.c
index 8b5cbb6b7a70..1311e7cf2733 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -60,6 +60,7 @@ struct vsp1_dl_body {
size_t size;
 
unsigned int num_entries;
+   unsigned int max_entries;
 };
 
 /**
@@ -138,6 +139,7 @@ static int vsp1_dl_body_init(struct vsp1_device *vsp1,
 
dlb->vsp1 = vsp1;
dlb->size = size;
+   dlb->max_entries = num_entries;
 
dlb->entries = dma_alloc_wc(vsp1->bus_master, dlb->size, >dma,
GFP_KERNEL);
@@ -220,6 +222,11 @@ void vsp1_dl_fragment_free(struct vsp1_dl_body *dlb)
  */
 void vsp1_dl_fragment_write(struct vsp1_dl_body *dlb, u32 reg, u32 data)
 {
+   if (unlikely(dlb->num_entries >= dlb->max_entries)) {
+   WARN_ONCE(true, "DLB size exceeded");
+   return;
+   }
+
dlb->entries[dlb->num_entries].addr = reg;
dlb->entries[dlb->num_entries].data = data;
dlb->num_entries++;
-- 
git-series 0.9.1


[PATCH 5/6] v4l: vsp1: Convert LUT to use a fragment pool

2017-07-14 Thread Kieran Bingham
Adapt the LUT to allocate a fragment pool for passing the table updates
to hardware.

Two bodies are pre-allocated in the pool to manage a userspace update
before the hardware has taken a previous set of tables.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_lut.c | 23 +++
 drivers/media/platform/vsp1/vsp1_lut.h |  1 +
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_lut.c 
b/drivers/media/platform/vsp1/vsp1_lut.c
index c67cc60db0db..57482e057e54 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -23,6 +23,8 @@
 #define LUT_MIN_SIZE   4U
 #define LUT_MAX_SIZE   8190U
 
+#define LUT_SIZE   256
+
 /* 
-
  * Device Access
  */
@@ -44,11 +46,11 @@ static int lut_set_table(struct vsp1_lut *lut, struct 
v4l2_ctrl *ctrl)
struct vsp1_dl_body *dlb;
unsigned int i;
 
-   dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, 256);
+   dlb = vsp1_dl_fragment_get(lut->pool);
if (!dlb)
return -ENOMEM;
 
-   for (i = 0; i < 256; ++i)
+   for (i = 0; i < LUT_SIZE; ++i)
vsp1_dl_fragment_write(dlb, VI6_LUT_TABLE + 4 * i,
   ctrl->p_new.p_u32[i]);
 
@@ -56,7 +58,7 @@ static int lut_set_table(struct vsp1_lut *lut, struct 
v4l2_ctrl *ctrl)
swap(lut->lut, dlb);
spin_unlock_irq(>lock);
 
-   vsp1_dl_fragment_free(dlb);
+   vsp1_dl_fragment_put(dlb);
return 0;
 }
 
@@ -87,7 +89,7 @@ static const struct v4l2_ctrl_config lut_table_control = {
.max = 0x00ff,
.step = 1,
.def = 0,
-   .dims = { 256},
+   .dims = { LUT_SIZE },
 };
 
 /* 
-
@@ -217,8 +219,16 @@ static void lut_configure(struct vsp1_entity *entity,
}
 }
 
+static void lut_destroy(struct vsp1_entity *entity)
+{
+   struct vsp1_lut *lut = to_lut(>subdev);
+
+   vsp1_dl_fragment_pool_free(lut->pool);
+}
+
 static const struct vsp1_entity_operations lut_entity_ops = {
.configure = lut_configure,
+   .destroy = lut_destroy,
 };
 
 /* 
-
@@ -244,6 +254,11 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
if (ret < 0)
return ERR_PTR(ret);
 
+   /* Allocate a fragment pool */
+   lut->pool = vsp1_dl_fragment_pool_alloc(vsp1, 2, LUT_SIZE, 0);
+   if (!lut->pool)
+   return ERR_PTR(-ENOMEM);
+
/* Initialize the control handler. */
v4l2_ctrl_handler_init(>ctrls, 1);
v4l2_ctrl_new_custom(>ctrls, _table_control, NULL);
diff --git a/drivers/media/platform/vsp1/vsp1_lut.h 
b/drivers/media/platform/vsp1/vsp1_lut.h
index f8c4e8f0a79d..538563d57454 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.h
+++ b/drivers/media/platform/vsp1/vsp1_lut.h
@@ -33,6 +33,7 @@ struct vsp1_lut {
 
spinlock_t lock;
struct vsp1_dl_body *lut;
+   struct vsp1_dl_fragment_pool *pool;
 };
 
 static inline struct vsp1_lut *to_lut(struct v4l2_subdev *subdev)
-- 
git-series 0.9.1


[PATCH 4/6] v4l: vsp1: Convert CLU to use a fragment pool

2017-07-14 Thread Kieran Bingham
Adapt the CLU to allocate a fragment pool for passing the table updates
to hardware.

Two bodies are pre-allocated in the pool to manage a userspace update
before the hardware has taken a previous set of tables.

Signed-off-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_clu.c | 18 --
 drivers/media/platform/vsp1/vsp1_clu.h |  1 +
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_clu.c 
b/drivers/media/platform/vsp1/vsp1_clu.c
index f2fb26e5ab4e..6079c6465435 100644
--- a/drivers/media/platform/vsp1/vsp1_clu.c
+++ b/drivers/media/platform/vsp1/vsp1_clu.c
@@ -47,7 +47,7 @@ static int clu_set_table(struct vsp1_clu *clu, struct 
v4l2_ctrl *ctrl)
struct vsp1_dl_body *dlb;
unsigned int i;
 
-   dlb = vsp1_dl_fragment_alloc(clu->entity.vsp1, 1 + 17 * 17 * 17);
+   dlb = vsp1_dl_fragment_get(clu->pool);
if (!dlb)
return -ENOMEM;
 
@@ -59,7 +59,7 @@ static int clu_set_table(struct vsp1_clu *clu, struct 
v4l2_ctrl *ctrl)
swap(clu->clu, dlb);
spin_unlock_irq(>lock);
 
-   vsp1_dl_fragment_free(dlb);
+   vsp1_dl_fragment_put(dlb);
return 0;
 }
 
@@ -261,8 +261,16 @@ static void clu_configure(struct vsp1_entity *entity,
}
 }
 
+static void clu_destroy(struct vsp1_entity *entity)
+{
+   struct vsp1_clu *clu = to_clu(>subdev);
+
+   vsp1_dl_fragment_pool_free(clu->pool);
+}
+
 static const struct vsp1_entity_operations clu_entity_ops = {
.configure = clu_configure,
+   .destroy = clu_destroy,
 };
 
 /* 
-
@@ -288,6 +296,12 @@ struct vsp1_clu *vsp1_clu_create(struct vsp1_device *vsp1)
if (ret < 0)
return ERR_PTR(ret);
 
+   /* Allocate a fragment pool */
+   clu->pool = vsp1_dl_fragment_pool_alloc(clu->entity.vsp1, 2,
+   1 + 17 * 17 * 17, 0);
+   if (!clu->pool)
+   return ERR_PTR(-ENOMEM);
+
/* Initialize the control handler. */
v4l2_ctrl_handler_init(>ctrls, 2);
v4l2_ctrl_new_custom(>ctrls, _table_control, NULL);
diff --git a/drivers/media/platform/vsp1/vsp1_clu.h 
b/drivers/media/platform/vsp1/vsp1_clu.h
index 036e0a2f1a42..601ffb558e30 100644
--- a/drivers/media/platform/vsp1/vsp1_clu.h
+++ b/drivers/media/platform/vsp1/vsp1_clu.h
@@ -36,6 +36,7 @@ struct vsp1_clu {
spinlock_t lock;
unsigned int mode;
struct vsp1_dl_body *clu;
+   struct vsp1_dl_fragment_pool *pool;
 };
 
 static inline struct vsp1_clu *to_clu(struct v4l2_subdev *subdev)
-- 
git-series 0.9.1


[PATCH 0/6] vsp1: TLB optimisation

2017-07-14 Thread Kieran Bingham
Each display list currently allocates an area of DMA memory to store register
settings for the VSP1 to process. Each of these allocations adds pressure to
the IPMMU TLB entries.

We can reduce the pressure by pre-allocating larger areas and dividing the area
across multiple bodies represented as a pool.

Patch 1 adds protection to ensure that the display list body does not overflow
and will allow us to reduce the size of the body allocations in the future (it
has already helped me catch an overflow during the development of this series,
so I thought it was a worth while addition)

Patch 2 implements the fragment pool object and provides function helpers to
interact with the pool

Patches 3 to 6 convert the existing allocations to use the new fragment pool.
These are separated for clarity, but I have no objections to squashing those
into a single commit if it is preferred.

This series has been tested and based on top of Laurent's recent ES2.0 patch
set at git://linuxtv.org/pinchartl/media.git drm/next/h3-es2/merged

Kieran Bingham (6):
  v4l: vsp1: Protect fragments against overflow
  v4l: vsp1: Provide a fragment pool
  v4l: vsp1: Convert display lists to use new fragment pool
  v4l: vsp1: Convert CLU to use a fragment pool
  v4l: vsp1: Convert LUT to use a fragment pool
  v4l: vsp1: Remove old fragment management

 drivers/media/platform/vsp1/vsp1_clu.c |  18 +-
 drivers/media/platform/vsp1/vsp1_clu.h |   1 +-
 drivers/media/platform/vsp1/vsp1_dl.c  | 294 +-
 drivers/media/platform/vsp1/vsp1_dl.h  |   8 +-
 drivers/media/platform/vsp1/vsp1_lut.c |  23 +-
 drivers/media/platform/vsp1/vsp1_lut.h |   1 +-
 6 files changed, 199 insertions(+), 146 deletions(-)

base-commit: 5fee73960b9a0ceb0ccf746dfeb06bdb07199670
-- 
git-series 0.9.1


Re: [PATCH v2 00/14] Renesas R-Car VSP: Add H3 ES2.0 support

2017-07-13 Thread Kieran Bingham
Hi Laurent,

Thankyou for these patches, bringing life to the outputs of my ES2.0 target 
board.

I have tested them on my board, and including the VSP unit test suite, and
kmscube utilities.

Feel free to add a Tested-by: Kieran Bingham
<kieran.bingham+rene...@ideasonboard.com> to all of the patches if you desire,
and I'm working through the individual reviews.

Oh - except now I've just said that - I did some extra testing with both HDMI
and VGA output connected and ran
   kmstest --flip --sync

This was soon followed by a kernel error trace [0] shown below.

However replicating this is possibly more complicated than just running kmstest
--flip --sync ... I've had to do various iterations of running with/without
{flip, sync} but I have reproduced 'issues' about 3 times now.

I think the key thing is in the VGA connection or regarding trying to output to
both.

Interestingly, I haven't been able to make this happen on the ES1.0 platform as
yet... though --flip --sync is quicker to fail with 'Flip Commit failed: -16"
there...

For reference this was tested on your pinchartl-media/drm/next/h3-es2/merged,
branch which I don't believe has the recent work on not needing to wait for a
final vblank on shutdown. So it is quite possible that the issue I am seeing is
simply a symptom of that separately repaired issue.

On that basis I've left my comment regarding my Tested-by: tag above as I
suspect that this issue I've hit could likely be separate and already resolved.

I'll try to add those patches to this tree to see if the issue resolves 
itself...

Regardless of that, this series conflicts with my current developments,
therefore I will likely rebase my work on top of this series. I don't need an
immutable branch, but please do let me know if this series changes :-)

--
Regards

Kieran.






[0] : Kernel log snippet posted below:

[  597.471369] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
[CRTC:57:crtc-3] flip_done timed out
[  607.711346] [drm:drm_atomic_helper_wait_for_dependencies] *ERROR*
[CRTC:57:crtc-3] flip_done timed out
[  607.711354] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
[CRTC:57:crtc-3] flip_done timed out
[  607.749585] vsp1 fea2.vsp: failed to reset wpf.1
[  617.951311] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
[CRTC:57:crtc-3] flip_done timed out
[  618.055358] vsp1 fea2.vsp: failed to reset wpf.1
[  618.060498] vsp1 fea2.vsp: DRM pipeline stop timeout
[  628.831762] vsp1 fea2.vsp: failed to reset wpf.1
[  638.943315] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
[CRTC:57:crtc-3] flip_done timed out
[  649.183313] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
[CRTC:57:crtc-3] flip_done timed out
[  677.753465] vsp1 fea2.vsp: failed to reset wpf.1
[  687.839322] [drm:drm_atomic_helper_commit_cleanup_done] *ERROR*
[CRTC:57:crtc-3] flip_done timed out
[  687.935288] vsp1 fea2.vsp: failed to reset wpf.1
[  687.940360] vsp1 fea2.vsp: DRM pipeline stop timeout
[  687.945939] Unable to handle kernel NULL pointer dereference at virtual
address 
[  687.954206] pgd = ff8009a0a000
[  687.957680] [] *pgd=00073fffe003, *pud=00073fffe003,
*pmd=
[  687.966068] Internal error: Oops: 9606 [#1] PREEMPT SMP
[  687.971690] Modules linked in:
[  687.974777] CPU: 0 PID: 10426 Comm: kmstest Not tainted
4.12.0-rc5-01343-g1bc824acf27c #5
[  687.983019] Hardware name: Renesas Salvator-X 2nd version board based on
r8a7795 ES2.0+ (DT)
[  687.991525] task: ffc6f97b4080 task.stack: ffc6f51dc000
[  687.997502] PC is at __media_pipeline_stop+0x24/0xd0
[  688.002507] LR is at media_pipeline_stop+0x34/0x48
[  688.007336] pc : [] lr : [] pstate: 
6145
[  688.014790] sp : ffc6f51df780
[  688.018129] x29: ffc6f51df780 x28: 
[  688.023490] x27: 0038 x26: ff8008960088
[  688.028850] x25: ffc6f98bcb10 x24: ffc6f98b8818
[  688.034210] x23: 0001 x22: ffc6f9ff1998
[  688.039570] x21: ffc6f98bc080 x20: 
[  688.044929] x19: 0008 x18: 0010
[  688.050288] x17: 007f9bc9e1c8 x16: ff8008165bb8
[  688.055648] x15: ff80899bb63f x14: 0006
[  688.061007] x13: ffc6faac6750 x12: ff80087bd078
[  688.066366] x11:  x10: ff80097bb000
[  688.071725] x9 : ff8008afd000 x8 : 
[  688.077085] x7 : ff8008583c1c x6 : ff8008da75c8
[  688.082443] x5 : ff8009585d00 x4 : 2d28ca88
[  688.087803] x3 : 89277f76 x2 : 
[  688.093162] x1 : ffc6f97b4080 x0 : ff8008583c24
[  688.098523] Process kmstest (pid: 10426, stack limit = 0xffc6f51dc000)
[  688.105453] Stack: (0xffc6f51df780 to 0xffc6f51e)
[  688.111245] f780: ffc6f51df7b0 ff8008583c24 ffc6f98b8ae8
ffc6f98bc080
[  688.119138] f7a0: ffc6f98bc818 ff8009d18000 ffc6f51df7e0
ff80085aa688
[  688.1

Re: [PATCH v2 01/14] v4l: vsp1: Fill display list headers without holding dlm spinlock

2017-07-13 Thread Kieran Bingham
Hi Laurent,

Starts easy ... (I haven't gone through these in numerical order of course :D)

On 26/06/17 19:12, Laurent Pinchart wrote:
> The display list headers are filled using information from the display
> list only. Lower the display list manager spinlock contention by filling
> the headers without holding the lock.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>

Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/media/platform/vsp1/vsp1_dl.c | 6 --
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/vsp1/vsp1_dl.c 
> b/drivers/media/platform/vsp1/vsp1_dl.c
> index aaf17b13fd78..dc47e236c780 100644
> --- a/drivers/media/platform/vsp1/vsp1_dl.c
> +++ b/drivers/media/platform/vsp1/vsp1_dl.c
> @@ -483,8 +483,6 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
>   unsigned long flags;
>   bool update;
>  
> - spin_lock_irqsave(>lock, flags);
> -
>   if (dl->dlm->mode == VSP1_DL_MODE_HEADER) {
>   struct vsp1_dl_list *dl_child;
>  
> @@ -501,7 +499,11 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
>  
>   vsp1_dl_list_fill_header(dl_child, last);
>   }
> + }
>  
> + spin_lock_irqsave(>lock, flags);
> +
> + if (dl->dlm->mode == VSP1_DL_MODE_HEADER) {
>   /*
>* Commit the head display list to hardware. Chained headers
>* will auto-start.
> 


Re: [PATCH v2 03/14] v4l: vsp1: Don't set WPF sink pointer

2017-07-13 Thread Kieran Bingham
On 26/06/17 19:12, Laurent Pinchart wrote:
> The sink pointer is used to configure routing inside the VSP, and as
> such must point to the next VSP entity in the pipeline. The WPF being a
> pipeline terminal sink, its output route can't be configured. The
> routing configuration code already handles this correctly without
> referring to the sink pointer, which thus doesn't need to be set.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+rene...@ideasonboard.com>

Reviewed-by: Kieran Bingham <kieran.bingham+rene...@ideasonboard.com>

> ---
>  drivers/media/platform/vsp1/vsp1_drv.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/media/platform/vsp1/vsp1_drv.c 
> b/drivers/media/platform/vsp1/vsp1_drv.c
> index 6b35e043b554..35087d5573ce 100644
> --- a/drivers/media/platform/vsp1/vsp1_drv.c
> +++ b/drivers/media/platform/vsp1/vsp1_drv.c
> @@ -412,7 +412,6 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
>   }
>  
>   list_add_tail(>list, >videos);
> - wpf->entity.sink = >video.entity;
>   }
>   }
>  
> 


<    1   2   3   4   5   6   7   8   9   >