aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;