aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform
diff options
context:
space:
mode:
authorKieran Bingham <kieran+renesas@bingham.xyz>2016-09-11 22:26:35 -0400
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2016-09-19 14:01:30 -0400
commitfc6e514a72c718f025d69e3006d6827b25a6df27 (patch)
treea76c9831ec374a2b305f27b4484bb7af95ba1c0a /drivers/media/platform
parentdf32c924518716160d43defc444199e894859c08 (diff)
[media] v4l: vsp1: Support multiple partitions per frame
Adapt vsp1_video_pipeline_run() such that it can iterate each partition required for constructing this frame's display list chain in the event that multiple display lists are required to process in hardware. The first display list is held as the head list object, whilst any following parition display lists are linked to the head by means of vsp1_dl_list_add_chain(). Linking the chained display list headers to process using the auto start mechanism of the hardware is performed during the vsp1_dl_list_commit(). Signed-off-by: Kieran Bingham <kieran+renesas@bingham.xyz> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/platform')
-rw-r--r--drivers/media/platform/vsp1/vsp1_pipe.h3
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c46
-rw-r--r--drivers/media/platform/vsp1/vsp1_uds.c15
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c121
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c30
5 files changed, 195 insertions, 20 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index af4cd23d399b..f15b697ad999 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -79,6 +79,7 @@ enum vsp1_pipeline_state {
79 * @dl: display list associated with the pipeline 79 * @dl: display list associated with the pipeline
80 * @div_size: The maximum allowed partition size for the pipeline 80 * @div_size: The maximum allowed partition size for the pipeline
81 * @partitions: The number of partitions used to process one frame 81 * @partitions: The number of partitions used to process one frame
82 * @current_partition: The partition number currently being configured
82 */ 83 */
83struct vsp1_pipeline { 84struct vsp1_pipeline {
84 struct media_pipeline pipe; 85 struct media_pipeline pipe;
@@ -109,6 +110,8 @@ struct vsp1_pipeline {
109 110
110 unsigned int div_size; 111 unsigned int div_size;
111 unsigned int partitions; 112 unsigned int partitions;
113 struct v4l2_rect partition;
114 unsigned int current_partition;
112}; 115};
113 116
114void vsp1_pipeline_reset(struct vsp1_pipeline *pipe); 117void 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 de5ef76c5004..e6236ff2f74a 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -72,8 +72,8 @@ static void rpf_configure(struct vsp1_entity *entity,
72 } 72 }
73 73
74 if (params == VSP1_ENTITY_PARAMS_PARTITION) { 74 if (params == VSP1_ENTITY_PARAMS_PARTITION) {
75 const struct v4l2_rect *crop;
76 unsigned int offsets[2]; 75 unsigned int offsets[2];
76 struct v4l2_rect crop;
77 77
78 /* Source size and crop offsets. 78 /* Source size and crop offsets.
79 * 79 *
@@ -82,21 +82,47 @@ static void rpf_configure(struct vsp1_entity *entity,
82 * offsets are needed, as planes 2 and 3 always have identical 82 * offsets are needed, as planes 2 and 3 always have identical
83 * strides. 83 * strides.
84 */ 84 */
85 crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config); 85 crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.config);
86
87 /* Partition Algorithm Control
88 *
89 * The partition algorithm can split this frame into multiple
90 * slices. We must scale our partition window based on the pipe
91 * configuration to match the destination partition window.
92 * To achieve this, we adjust our crop to provide a 'sub-crop'
93 * matching the expected partition window. Only 'left' and
94 * 'width' need to be adjusted.
95 */
96 if (pipe->partitions > 1) {
97 const struct v4l2_mbus_framefmt *output;
98 struct vsp1_entity *wpf = &pipe->output->entity;
99 unsigned int input_width = crop.width;
100
101 /* Scale the partition window based on the configuration
102 * of the pipeline.
103 */
104 output = vsp1_entity_get_pad_format(wpf, wpf->config,
105 RWPF_PAD_SOURCE);
106
107 crop.width = pipe->partition.width * input_width
108 / output->width;
109 crop.left += pipe->partition.left * input_width
110 / output->width;
111 }
86 112
87 vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE, 113 vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE,
88 (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | 114 (crop.width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
89 (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); 115 (crop.height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
90 vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE, 116 vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE,
91 (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | 117 (crop.width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
92 (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); 118 (crop.height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
93 119
94 offsets[0] = crop->top * format->plane_fmt[0].bytesperline 120 offsets[0] = crop.top * format->plane_fmt[0].bytesperline
95 + crop->left * fmtinfo->bpp[0] / 8; 121 + crop.left * fmtinfo->bpp[0] / 8;
96 122
97 if (format->num_planes > 1) 123 if (format->num_planes > 1)
98 offsets[1] = crop->top * format->plane_fmt[1].bytesperline 124 offsets[1] = crop.top * format->plane_fmt[1].bytesperline
99 + crop->left / fmtinfo->hsub 125 + crop.left / fmtinfo->hsub
100 * fmtinfo->bpp[1] / 8; 126 * fmtinfo->bpp[1] / 8;
101 else 127 else
102 offsets[1] = 0; 128 offsets[1] = 0;
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 706b6e85f47d..da8f89a31ea4 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -18,6 +18,7 @@
18 18
19#include "vsp1.h" 19#include "vsp1.h"
20#include "vsp1_dl.h" 20#include "vsp1_dl.h"
21#include "vsp1_pipe.h"
21#include "vsp1_uds.h" 22#include "vsp1_uds.h"
22 23
23#define UDS_MIN_SIZE 4U 24#define UDS_MIN_SIZE 4U
@@ -270,6 +271,15 @@ static void uds_configure(struct vsp1_entity *entity,
270 unsigned int vscale; 271 unsigned int vscale;
271 bool multitap; 272 bool multitap;
272 273
274 if (params == VSP1_ENTITY_PARAMS_PARTITION) {
275 const struct v4l2_rect *clip = &pipe->partition;
276
277 vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE,
278 (clip->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
279 (clip->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
280 return;
281 }
282
273 if (params != VSP1_ENTITY_PARAMS_INIT) 283 if (params != VSP1_ENTITY_PARAMS_INIT)
274 return; 284 return;
275 285
@@ -302,13 +312,10 @@ static void uds_configure(struct vsp1_entity *entity,
302 (uds_passband_width(vscale) 312 (uds_passband_width(vscale)
303 << VI6_UDS_PASS_BWIDTH_V_SHIFT)); 313 << VI6_UDS_PASS_BWIDTH_V_SHIFT));
304 314
305 /* Set the scaling ratios and the output size. */ 315 /* Set the scaling ratios. */
306 vsp1_uds_write(uds, dl, VI6_UDS_SCALE, 316 vsp1_uds_write(uds, dl, VI6_UDS_SCALE,
307 (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) | 317 (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
308 (vscale << VI6_UDS_SCALE_VFRAC_SHIFT)); 318 (vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
309 vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE,
310 (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
311 (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
312} 319}
313 320
314static unsigned int uds_max_width(struct vsp1_entity *entity, 321static unsigned int uds_max_width(struct vsp1_entity *entity,
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index b903cc5471e0..15d08cb50bd1 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -205,6 +205,74 @@ static void vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
205 pipe->partitions = DIV_ROUND_UP(format->width, div_size); 205 pipe->partitions = DIV_ROUND_UP(format->width, div_size);
206} 206}
207 207
208/*
209 * vsp1_video_partition - Calculate the active partition output window
210 *
211 * @div_size: pre-determined maximum partition division size
212 * @index: partition index
213 *
214 * Returns a v4l2_rect describing the partition window.
215 */
216static struct v4l2_rect vsp1_video_partition(struct vsp1_pipeline *pipe,
217 unsigned int div_size,
218 unsigned int index)
219{
220 const struct v4l2_mbus_framefmt *format;
221 struct v4l2_rect partition;
222 unsigned int modulus;
223
224 format = vsp1_entity_get_pad_format(&pipe->output->entity,
225 pipe->output->entity.config,
226 RWPF_PAD_SOURCE);
227
228 /* A single partition simply processes the output size in full. */
229 if (pipe->partitions <= 1) {
230 partition.left = 0;
231 partition.top = 0;
232 partition.width = format->width;
233 partition.height = format->height;
234 return partition;
235 }
236
237 /* Initialise the partition with sane starting conditions. */
238 partition.left = index * div_size;
239 partition.top = 0;
240 partition.width = div_size;
241 partition.height = format->height;
242
243 modulus = format->width % div_size;
244
245 /* We need to prevent the last partition from being smaller than the
246 * *minimum* width of the hardware capabilities.
247 *
248 * If the modulus is less than half of the partition size,
249 * the penultimate partition is reduced to half, which is added
250 * to the final partition: |1234|1234|1234|12|341|
251 * to prevents this: |1234|1234|1234|1234|1|.
252 */
253 if (modulus) {
254 /* pipe->partitions is 1 based, whilst index is a 0 based index.
255 * Normalise this locally.
256 */
257 unsigned int partitions = pipe->partitions - 1;
258
259 if (modulus < div_size / 2) {
260 if (index == partitions - 1) {
261 /* Halve the penultimate partition. */
262 partition.width = div_size / 2;
263 } else if (index == partitions) {
264 /* Increase the final partition. */
265 partition.width = (div_size / 2) + modulus;
266 partition.left -= div_size / 2;
267 }
268 } else if (index == partitions) {
269 partition.width = modulus;
270 }
271 }
272
273 return partition;
274}
275
208/* ----------------------------------------------------------------------------- 276/* -----------------------------------------------------------------------------
209 * Pipeline Management 277 * Pipeline Management
210 */ 278 */
@@ -280,22 +348,69 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
280 pipe->buffers_ready |= 1 << video->pipe_index; 348 pipe->buffers_ready |= 1 << video->pipe_index;
281} 349}
282 350
351static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe,
352 struct vsp1_dl_list *dl)
353{
354 struct vsp1_entity *entity;
355
356 pipe->partition = vsp1_video_partition(pipe, pipe->div_size,
357 pipe->current_partition);
358
359 list_for_each_entry(entity, &pipe->entities, list_pipe) {
360 if (entity->ops->configure)
361 entity->ops->configure(entity, pipe, dl,
362 VSP1_ENTITY_PARAMS_PARTITION);
363 }
364}
365
283static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) 366static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
284{ 367{
368 struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
285 struct vsp1_entity *entity; 369 struct vsp1_entity *entity;
286 370
287 if (!pipe->dl) 371 if (!pipe->dl)
288 pipe->dl = vsp1_dl_list_get(pipe->output->dlm); 372 pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
289 373
374 /* Start with the runtime parameters as the configure operation can
375 * compute/cache information needed when configuring partitions. This
376 * is the case with flipping in the WPF.
377 */
290 list_for_each_entry(entity, &pipe->entities, list_pipe) { 378 list_for_each_entry(entity, &pipe->entities, list_pipe) {
291 if (entity->ops->configure) { 379 if (entity->ops->configure)
292 entity->ops->configure(entity, pipe, pipe->dl, 380 entity->ops->configure(entity, pipe, pipe->dl,
293 VSP1_ENTITY_PARAMS_RUNTIME); 381 VSP1_ENTITY_PARAMS_RUNTIME);
294 entity->ops->configure(entity, pipe, pipe->dl, 382 }
295 VSP1_ENTITY_PARAMS_PARTITION); 383
384 /* Run the first partition */
385 pipe->current_partition = 0;
386 vsp1_video_pipeline_run_partition(pipe, pipe->dl);
387
388 /* Process consecutive partitions as necessary */
389 for (pipe->current_partition = 1;
390 pipe->current_partition < pipe->partitions;
391 pipe->current_partition++) {
392 struct vsp1_dl_list *dl;
393
394 /* Partition configuration operations will utilise
395 * the pipe->current_partition variable to determine
396 * the work they should complete.
397 */
398 dl = vsp1_dl_list_get(pipe->output->dlm);
399
400 /* An incomplete chain will still function, but output only
401 * the partitions that had a dl available. The frame end
402 * interrupt will be marked on the last dl in the chain.
403 */
404 if (!dl) {
405 dev_err(vsp1->dev, "Failed to obtain a dl list. Frame will be incomplete\n");
406 break;
296 } 407 }
408
409 vsp1_video_pipeline_run_partition(pipe, dl);
410 vsp1_dl_list_add_chain(pipe->dl, dl);
297 } 411 }
298 412
413 /* Complete, and commit the head display list. */
299 vsp1_dl_list_commit(pipe->dl); 414 vsp1_dl_list_commit(pipe->dl);
300 pipe->dl = NULL; 415 pipe->dl = NULL;
301 416
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index b757d2579d6c..fdee5a891e40 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -224,6 +224,9 @@ static void wpf_configure(struct vsp1_entity *entity,
224 /* Cropping. The partition algorithm can split the image into 224 /* Cropping. The partition algorithm can split the image into
225 * multiple slices. 225 * multiple slices.
226 */ 226 */
227 if (pipe->partitions > 1)
228 width = pipe->partition.width;
229
227 vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | 230 vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
228 (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | 231 (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
229 (width << VI6_WPF_SZCLIP_SIZE_SHIFT)); 232 (width << VI6_WPF_SZCLIP_SIZE_SHIFT));
@@ -237,10 +240,31 @@ static void wpf_configure(struct vsp1_entity *entity,
237 /* Update the memory offsets based on flipping configuration. 240 /* Update the memory offsets based on flipping configuration.
238 * The destination addresses point to the locations where the 241 * The destination addresses point to the locations where the
239 * VSP starts writing to memory, which can be different corners 242 * VSP starts writing to memory, which can be different corners
240 * of the image depending on vertical flipping. Horizontal 243 * of the image depending on vertical flipping.
241 * flipping is handled through a line buffer and doesn't modify
242 * the start address.
243 */ 244 */
245 if (pipe->partitions > 1) {
246 const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
247
248 /* Horizontal flipping is handled through a line buffer
249 * and doesn't modify the start address, but still needs
250 * to be handled when image partitioning is in effect to
251 * order the partitions correctly.
252 */
253 if (flip & BIT(WPF_CTRL_HFLIP))
254 offset = format->width - pipe->partition.left
255 - pipe->partition.width;
256 else
257 offset = pipe->partition.left;
258
259 mem.addr[0] += offset * fmtinfo->bpp[0] / 8;
260 if (format->num_planes > 1) {
261 mem.addr[1] += offset / fmtinfo->hsub
262 * fmtinfo->bpp[1] / 8;
263 mem.addr[2] += offset / fmtinfo->hsub
264 * fmtinfo->bpp[2] / 8;
265 }
266 }
267
244 if (flip & BIT(WPF_CTRL_VFLIP)) { 268 if (flip & BIT(WPF_CTRL_VFLIP)) {
245 mem.addr[0] += (format->height - 1) 269 mem.addr[0] += (format->height - 1)
246 * format->plane_fmt[0].bytesperline; 270 * format->plane_fmt[0].bytesperline;