diff options
author | Kieran Bingham <kieran.bingham+renesas@ideasonboard.com> | 2018-05-18 16:42:01 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | 2018-05-25 19:03:16 -0400 |
commit | 46ce3639a579c29dc3166a9a66522f72f11f560c (patch) | |
tree | 13bb07c31eb5edde959931cf7ef23d5b2f6bd5bc /drivers/media/platform/vsp1/vsp1_wpf.c | |
parent | 2d9445db0ee9d8695ab3dadb614829b70e43b61f (diff) |
media: vsp1: Refactor display list configure operations
The entities provide a single .configure operation which configures the
object into the target display list, based on the vsp1_entity_params
selection.
Split the configure function into three parts, '.configure_stream()',
'.configure_frame()', and '.configure_partition()' to facilitate
splitting the configuration of each parameter class into separate
display list bodies.
[laurent.pinchart+renesas@ideasonboard.com: Blank line reformatting, remote unneeded local variable initialization]
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Diffstat (limited to 'drivers/media/platform/vsp1/vsp1_wpf.c')
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_wpf.c | 302 |
1 files changed, 160 insertions, 142 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 65ed2f849551..8662c5d2fc64 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c | |||
@@ -232,10 +232,9 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity) | |||
232 | vsp1_dlm_destroy(wpf->dlm); | 232 | vsp1_dlm_destroy(wpf->dlm); |
233 | } | 233 | } |
234 | 234 | ||
235 | static void wpf_configure(struct vsp1_entity *entity, | 235 | static void wpf_configure_stream(struct vsp1_entity *entity, |
236 | struct vsp1_pipeline *pipe, | 236 | struct vsp1_pipeline *pipe, |
237 | struct vsp1_dl_list *dl, | 237 | struct vsp1_dl_list *dl) |
238 | enum vsp1_entity_params params) | ||
239 | { | 238 | { |
240 | struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); | 239 | struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); |
241 | struct vsp1_device *vsp1 = wpf->entity.vsp1; | 240 | struct vsp1_device *vsp1 = wpf->entity.vsp1; |
@@ -245,149 +244,12 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
245 | u32 outfmt = 0; | 244 | u32 outfmt = 0; |
246 | u32 srcrpf = 0; | 245 | u32 srcrpf = 0; |
247 | 246 | ||
248 | if (params == VSP1_ENTITY_PARAMS_RUNTIME) { | ||
249 | const unsigned int mask = BIT(WPF_CTRL_VFLIP) | ||
250 | | BIT(WPF_CTRL_HFLIP); | ||
251 | unsigned long flags; | ||
252 | |||
253 | spin_lock_irqsave(&wpf->flip.lock, flags); | ||
254 | wpf->flip.active = (wpf->flip.active & ~mask) | ||
255 | | (wpf->flip.pending & mask); | ||
256 | spin_unlock_irqrestore(&wpf->flip.lock, flags); | ||
257 | |||
258 | outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt; | ||
259 | |||
260 | if (wpf->flip.active & BIT(WPF_CTRL_VFLIP)) | ||
261 | outfmt |= VI6_WPF_OUTFMT_FLP; | ||
262 | if (wpf->flip.active & BIT(WPF_CTRL_HFLIP)) | ||
263 | outfmt |= VI6_WPF_OUTFMT_HFLP; | ||
264 | |||
265 | vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt); | ||
266 | return; | ||
267 | } | ||
268 | |||
269 | sink_format = vsp1_entity_get_pad_format(&wpf->entity, | 247 | sink_format = vsp1_entity_get_pad_format(&wpf->entity, |
270 | wpf->entity.config, | 248 | wpf->entity.config, |
271 | RWPF_PAD_SINK); | 249 | RWPF_PAD_SINK); |
272 | source_format = vsp1_entity_get_pad_format(&wpf->entity, | 250 | source_format = vsp1_entity_get_pad_format(&wpf->entity, |
273 | wpf->entity.config, | 251 | wpf->entity.config, |
274 | RWPF_PAD_SOURCE); | 252 | RWPF_PAD_SOURCE); |
275 | |||
276 | if (params == VSP1_ENTITY_PARAMS_PARTITION) { | ||
277 | const struct v4l2_pix_format_mplane *format = &wpf->format; | ||
278 | const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; | ||
279 | struct vsp1_rwpf_memory mem = wpf->mem; | ||
280 | unsigned int flip = wpf->flip.active; | ||
281 | unsigned int width = sink_format->width; | ||
282 | unsigned int height = sink_format->height; | ||
283 | unsigned int offset; | ||
284 | |||
285 | /* | ||
286 | * Cropping. The partition algorithm can split the image into | ||
287 | * multiple slices. | ||
288 | */ | ||
289 | if (pipe->partitions > 1) | ||
290 | width = pipe->partition->wpf.width; | ||
291 | |||
292 | vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | | ||
293 | (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | | ||
294 | (width << VI6_WPF_SZCLIP_SIZE_SHIFT)); | ||
295 | vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN | | ||
296 | (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | | ||
297 | (height << VI6_WPF_SZCLIP_SIZE_SHIFT)); | ||
298 | |||
299 | if (pipe->lif) | ||
300 | return; | ||
301 | |||
302 | /* | ||
303 | * Update the memory offsets based on flipping configuration. | ||
304 | * The destination addresses point to the locations where the | ||
305 | * VSP starts writing to memory, which can be any corner of the | ||
306 | * image depending on the combination of flipping and rotation. | ||
307 | */ | ||
308 | |||
309 | /* | ||
310 | * First take the partition left coordinate into account. | ||
311 | * Compute the offset to order the partitions correctly on the | ||
312 | * output based on whether flipping is enabled. Consider | ||
313 | * horizontal flipping when rotation is disabled but vertical | ||
314 | * flipping when rotation is enabled, as rotating the image | ||
315 | * switches the horizontal and vertical directions. The offset | ||
316 | * is applied horizontally or vertically accordingly. | ||
317 | */ | ||
318 | if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate) | ||
319 | offset = format->width - pipe->partition->wpf.left | ||
320 | - pipe->partition->wpf.width; | ||
321 | else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate) | ||
322 | offset = format->height - pipe->partition->wpf.left | ||
323 | - pipe->partition->wpf.width; | ||
324 | else | ||
325 | offset = pipe->partition->wpf.left; | ||
326 | |||
327 | for (i = 0; i < format->num_planes; ++i) { | ||
328 | unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; | ||
329 | unsigned int vsub = i > 0 ? fmtinfo->vsub : 1; | ||
330 | |||
331 | if (wpf->flip.rotate) | ||
332 | mem.addr[i] += offset / vsub | ||
333 | * format->plane_fmt[i].bytesperline; | ||
334 | else | ||
335 | mem.addr[i] += offset / hsub | ||
336 | * fmtinfo->bpp[i] / 8; | ||
337 | } | ||
338 | |||
339 | if (flip & BIT(WPF_CTRL_VFLIP)) { | ||
340 | /* | ||
341 | * When rotating the output (after rotation) image | ||
342 | * height is equal to the partition width (before | ||
343 | * rotation). Otherwise it is equal to the output | ||
344 | * image height. | ||
345 | */ | ||
346 | if (wpf->flip.rotate) | ||
347 | height = pipe->partition->wpf.width; | ||
348 | else | ||
349 | height = format->height; | ||
350 | |||
351 | mem.addr[0] += (height - 1) | ||
352 | * format->plane_fmt[0].bytesperline; | ||
353 | |||
354 | if (format->num_planes > 1) { | ||
355 | offset = (height / fmtinfo->vsub - 1) | ||
356 | * format->plane_fmt[1].bytesperline; | ||
357 | mem.addr[1] += offset; | ||
358 | mem.addr[2] += offset; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | if (wpf->flip.rotate && !(flip & BIT(WPF_CTRL_HFLIP))) { | ||
363 | unsigned int hoffset = max(0, (int)format->width - 16); | ||
364 | |||
365 | /* | ||
366 | * Compute the output coordinate. The partition | ||
367 | * horizontal (left) offset becomes a vertical offset. | ||
368 | */ | ||
369 | for (i = 0; i < format->num_planes; ++i) { | ||
370 | unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; | ||
371 | |||
372 | mem.addr[i] += hoffset / hsub | ||
373 | * fmtinfo->bpp[i] / 8; | ||
374 | } | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * On Gen3 hardware the SPUVS bit has no effect on 3-planar | ||
379 | * formats. Swap the U and V planes manually in that case. | ||
380 | */ | ||
381 | if (vsp1->info->gen == 3 && format->num_planes == 3 && | ||
382 | fmtinfo->swap_uv) | ||
383 | swap(mem.addr[1], mem.addr[2]); | ||
384 | |||
385 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]); | ||
386 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]); | ||
387 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]); | ||
388 | return; | ||
389 | } | ||
390 | |||
391 | /* Format */ | 253 | /* Format */ |
392 | if (!pipe->lif) { | 254 | if (!pipe->lif) { |
393 | const struct v4l2_pix_format_mplane *format = &wpf->format; | 255 | const struct v4l2_pix_format_mplane *format = &wpf->format; |
@@ -461,6 +323,160 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
461 | VI6_WFP_IRQ_ENB_DFEE); | 323 | VI6_WFP_IRQ_ENB_DFEE); |
462 | } | 324 | } |
463 | 325 | ||
326 | static void wpf_configure_frame(struct vsp1_entity *entity, | ||
327 | struct vsp1_pipeline *pipe, | ||
328 | struct vsp1_dl_list *dl) | ||
329 | { | ||
330 | const unsigned int mask = BIT(WPF_CTRL_VFLIP) | ||
331 | | BIT(WPF_CTRL_HFLIP); | ||
332 | struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); | ||
333 | unsigned long flags; | ||
334 | u32 outfmt; | ||
335 | |||
336 | spin_lock_irqsave(&wpf->flip.lock, flags); | ||
337 | wpf->flip.active = (wpf->flip.active & ~mask) | ||
338 | | (wpf->flip.pending & mask); | ||
339 | spin_unlock_irqrestore(&wpf->flip.lock, flags); | ||
340 | |||
341 | outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt; | ||
342 | |||
343 | if (wpf->flip.active & BIT(WPF_CTRL_VFLIP)) | ||
344 | outfmt |= VI6_WPF_OUTFMT_FLP; | ||
345 | if (wpf->flip.active & BIT(WPF_CTRL_HFLIP)) | ||
346 | outfmt |= VI6_WPF_OUTFMT_HFLP; | ||
347 | |||
348 | vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt); | ||
349 | } | ||
350 | |||
351 | static void wpf_configure_partition(struct vsp1_entity *entity, | ||
352 | struct vsp1_pipeline *pipe, | ||
353 | struct vsp1_dl_list *dl) | ||
354 | { | ||
355 | struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); | ||
356 | struct vsp1_device *vsp1 = wpf->entity.vsp1; | ||
357 | struct vsp1_rwpf_memory mem = wpf->mem; | ||
358 | const struct v4l2_mbus_framefmt *sink_format; | ||
359 | const struct v4l2_pix_format_mplane *format = &wpf->format; | ||
360 | const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; | ||
361 | unsigned int width; | ||
362 | unsigned int height; | ||
363 | unsigned int offset; | ||
364 | unsigned int flip; | ||
365 | unsigned int i; | ||
366 | |||
367 | sink_format = vsp1_entity_get_pad_format(&wpf->entity, | ||
368 | wpf->entity.config, | ||
369 | RWPF_PAD_SINK); | ||
370 | width = sink_format->width; | ||
371 | height = sink_format->height; | ||
372 | |||
373 | /* | ||
374 | * Cropping. The partition algorithm can split the image into | ||
375 | * multiple slices. | ||
376 | */ | ||
377 | if (pipe->partitions > 1) | ||
378 | width = pipe->partition->wpf.width; | ||
379 | |||
380 | vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | | ||
381 | (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | | ||
382 | (width << VI6_WPF_SZCLIP_SIZE_SHIFT)); | ||
383 | vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN | | ||
384 | (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | | ||
385 | (height << VI6_WPF_SZCLIP_SIZE_SHIFT)); | ||
386 | |||
387 | if (pipe->lif) | ||
388 | return; | ||
389 | |||
390 | /* | ||
391 | * Update the memory offsets based on flipping configuration. | ||
392 | * The destination addresses point to the locations where the | ||
393 | * VSP starts writing to memory, which can be any corner of the | ||
394 | * image depending on the combination of flipping and rotation. | ||
395 | */ | ||
396 | |||
397 | /* | ||
398 | * First take the partition left coordinate into account. | ||
399 | * Compute the offset to order the partitions correctly on the | ||
400 | * output based on whether flipping is enabled. Consider | ||
401 | * horizontal flipping when rotation is disabled but vertical | ||
402 | * flipping when rotation is enabled, as rotating the image | ||
403 | * switches the horizontal and vertical directions. The offset | ||
404 | * is applied horizontally or vertically accordingly. | ||
405 | */ | ||
406 | flip = wpf->flip.active; | ||
407 | |||
408 | if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate) | ||
409 | offset = format->width - pipe->partition->wpf.left | ||
410 | - pipe->partition->wpf.width; | ||
411 | else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate) | ||
412 | offset = format->height - pipe->partition->wpf.left | ||
413 | - pipe->partition->wpf.width; | ||
414 | else | ||
415 | offset = pipe->partition->wpf.left; | ||
416 | |||
417 | for (i = 0; i < format->num_planes; ++i) { | ||
418 | unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; | ||
419 | unsigned int vsub = i > 0 ? fmtinfo->vsub : 1; | ||
420 | |||
421 | if (wpf->flip.rotate) | ||
422 | mem.addr[i] += offset / vsub | ||
423 | * format->plane_fmt[i].bytesperline; | ||
424 | else | ||
425 | mem.addr[i] += offset / hsub | ||
426 | * fmtinfo->bpp[i] / 8; | ||
427 | } | ||
428 | |||
429 | if (flip & BIT(WPF_CTRL_VFLIP)) { | ||
430 | /* | ||
431 | * When rotating the output (after rotation) image | ||
432 | * height is equal to the partition width (before | ||
433 | * rotation). Otherwise it is equal to the output | ||
434 | * image height. | ||
435 | */ | ||
436 | if (wpf->flip.rotate) | ||
437 | height = pipe->partition->wpf.width; | ||
438 | else | ||
439 | height = format->height; | ||
440 | |||
441 | mem.addr[0] += (height - 1) | ||
442 | * format->plane_fmt[0].bytesperline; | ||
443 | |||
444 | if (format->num_planes > 1) { | ||
445 | offset = (height / fmtinfo->vsub - 1) | ||
446 | * format->plane_fmt[1].bytesperline; | ||
447 | mem.addr[1] += offset; | ||
448 | mem.addr[2] += offset; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | if (wpf->flip.rotate && !(flip & BIT(WPF_CTRL_HFLIP))) { | ||
453 | unsigned int hoffset = max(0, (int)format->width - 16); | ||
454 | |||
455 | /* | ||
456 | * Compute the output coordinate. The partition | ||
457 | * horizontal (left) offset becomes a vertical offset. | ||
458 | */ | ||
459 | for (i = 0; i < format->num_planes; ++i) { | ||
460 | unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; | ||
461 | |||
462 | mem.addr[i] += hoffset / hsub | ||
463 | * fmtinfo->bpp[i] / 8; | ||
464 | } | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * On Gen3 hardware the SPUVS bit has no effect on 3-planar | ||
469 | * formats. Swap the U and V planes manually in that case. | ||
470 | */ | ||
471 | if (vsp1->info->gen == 3 && format->num_planes == 3 && | ||
472 | fmtinfo->swap_uv) | ||
473 | swap(mem.addr[1], mem.addr[2]); | ||
474 | |||
475 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]); | ||
476 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]); | ||
477 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]); | ||
478 | } | ||
479 | |||
464 | static unsigned int wpf_max_width(struct vsp1_entity *entity, | 480 | static unsigned int wpf_max_width(struct vsp1_entity *entity, |
465 | struct vsp1_pipeline *pipe) | 481 | struct vsp1_pipeline *pipe) |
466 | { | 482 | { |
@@ -480,7 +496,9 @@ static void wpf_partition(struct vsp1_entity *entity, | |||
480 | 496 | ||
481 | static const struct vsp1_entity_operations wpf_entity_ops = { | 497 | static const struct vsp1_entity_operations wpf_entity_ops = { |
482 | .destroy = vsp1_wpf_destroy, | 498 | .destroy = vsp1_wpf_destroy, |
483 | .configure = wpf_configure, | 499 | .configure_stream = wpf_configure_stream, |
500 | .configure_frame = wpf_configure_frame, | ||
501 | .configure_partition = wpf_configure_partition, | ||
484 | .max_width = wpf_max_width, | 502 | .max_width = wpf_max_width, |
485 | .partition = wpf_partition, | 503 | .partition = wpf_partition, |
486 | }; | 504 | }; |