1 // SPDX-License-Identifier: GPL-2.0+
3 * vsp1_wpf.c -- R-Car VSP1 Write Pixel Formatter
5 * Copyright (C) 2013-2014 Renesas Electronics Corporation
7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
10 #include <linux/device.h>
12 #include <media/v4l2-subdev.h>
16 #include "vsp1_pipe.h"
17 #include "vsp1_rwpf.h"
18 #include "vsp1_video.h"
20 #define WPF_GEN2_MAX_WIDTH 2048U
21 #define WPF_GEN2_MAX_HEIGHT 2048U
22 #define WPF_GEN3_MAX_WIDTH 8190U
23 #define WPF_GEN3_MAX_HEIGHT 8190U
25 /* -----------------------------------------------------------------------------
29 static inline void vsp1_wpf_write(struct vsp1_rwpf
*wpf
,
30 struct vsp1_dl_body
*dlb
, u32 reg
, u32 data
)
32 vsp1_dl_body_write(dlb
, reg
+ wpf
->entity
.index
* VI6_WPF_OFFSET
, data
);
35 /* -----------------------------------------------------------------------------
44 static int vsp1_wpf_set_rotation(struct vsp1_rwpf
*wpf
, unsigned int rotation
)
46 struct vsp1_video
*video
= wpf
->video
;
47 struct v4l2_mbus_framefmt
*sink_format
;
48 struct v4l2_mbus_framefmt
*source_format
;
53 * Only consider the 0°/180° from/to 90°/270° modifications, the rest
54 * is taken care of by the flipping configuration.
56 rotate
= rotation
== 90 || rotation
== 270;
57 if (rotate
== wpf
->flip
.rotate
)
60 /* Changing rotation isn't allowed when buffers are allocated. */
61 mutex_lock(&video
->lock
);
63 if (vb2_is_busy(&video
->queue
)) {
68 sink_format
= vsp1_entity_get_pad_format(&wpf
->entity
,
71 source_format
= vsp1_entity_get_pad_format(&wpf
->entity
,
75 mutex_lock(&wpf
->entity
.lock
);
78 source_format
->width
= sink_format
->height
;
79 source_format
->height
= sink_format
->width
;
81 source_format
->width
= sink_format
->width
;
82 source_format
->height
= sink_format
->height
;
85 wpf
->flip
.rotate
= rotate
;
87 mutex_unlock(&wpf
->entity
.lock
);
90 mutex_unlock(&video
->lock
);
94 static int vsp1_wpf_s_ctrl(struct v4l2_ctrl
*ctrl
)
96 struct vsp1_rwpf
*wpf
=
97 container_of(ctrl
->handler
, struct vsp1_rwpf
, ctrls
);
98 unsigned int rotation
;
102 /* Update the rotation. */
103 rotation
= wpf
->flip
.ctrls
.rotate
? wpf
->flip
.ctrls
.rotate
->val
: 0;
104 ret
= vsp1_wpf_set_rotation(wpf
, rotation
);
109 * Compute the flip value resulting from all three controls, with
110 * rotation by 180° flipping the image in both directions. Store the
111 * result in the pending flip field for the next frame that will be
114 if (wpf
->flip
.ctrls
.vflip
->val
)
115 flip
|= BIT(WPF_CTRL_VFLIP
);
117 if (wpf
->flip
.ctrls
.hflip
&& wpf
->flip
.ctrls
.hflip
->val
)
118 flip
|= BIT(WPF_CTRL_HFLIP
);
120 if (rotation
== 180 || rotation
== 270)
121 flip
^= BIT(WPF_CTRL_VFLIP
) | BIT(WPF_CTRL_HFLIP
);
123 spin_lock_irq(&wpf
->flip
.lock
);
124 wpf
->flip
.pending
= flip
;
125 spin_unlock_irq(&wpf
->flip
.lock
);
130 static const struct v4l2_ctrl_ops vsp1_wpf_ctrl_ops
= {
131 .s_ctrl
= vsp1_wpf_s_ctrl
,
134 static int wpf_init_controls(struct vsp1_rwpf
*wpf
)
136 struct vsp1_device
*vsp1
= wpf
->entity
.vsp1
;
137 unsigned int num_flip_ctrls
;
139 spin_lock_init(&wpf
->flip
.lock
);
141 if (wpf
->entity
.index
!= 0) {
142 /* Only WPF0 supports flipping. */
144 } else if (vsp1_feature(vsp1
, VSP1_HAS_WPF_HFLIP
)) {
146 * When horizontal flip is supported the WPF implements three
147 * controls (horizontal flip, vertical flip and rotation).
150 } else if (vsp1_feature(vsp1
, VSP1_HAS_WPF_VFLIP
)) {
152 * When only vertical flip is supported the WPF implements a
153 * single control (vertical flip).
157 /* Otherwise flipping is not supported. */
161 vsp1_rwpf_init_ctrls(wpf
, num_flip_ctrls
);
163 if (num_flip_ctrls
>= 1) {
164 wpf
->flip
.ctrls
.vflip
=
165 v4l2_ctrl_new_std(&wpf
->ctrls
, &vsp1_wpf_ctrl_ops
,
166 V4L2_CID_VFLIP
, 0, 1, 1, 0);
169 if (num_flip_ctrls
== 3) {
170 wpf
->flip
.ctrls
.hflip
=
171 v4l2_ctrl_new_std(&wpf
->ctrls
, &vsp1_wpf_ctrl_ops
,
172 V4L2_CID_HFLIP
, 0, 1, 1, 0);
173 wpf
->flip
.ctrls
.rotate
=
174 v4l2_ctrl_new_std(&wpf
->ctrls
, &vsp1_wpf_ctrl_ops
,
175 V4L2_CID_ROTATE
, 0, 270, 90, 0);
176 v4l2_ctrl_cluster(3, &wpf
->flip
.ctrls
.vflip
);
179 if (wpf
->ctrls
.error
) {
180 dev_err(vsp1
->dev
, "wpf%u: failed to initialize controls\n",
182 return wpf
->ctrls
.error
;
188 /* -----------------------------------------------------------------------------
189 * V4L2 Subdevice Core Operations
192 static int wpf_s_stream(struct v4l2_subdev
*subdev
, int enable
)
194 struct vsp1_rwpf
*wpf
= to_rwpf(subdev
);
195 struct vsp1_device
*vsp1
= wpf
->entity
.vsp1
;
201 * Write to registers directly when stopping the stream as there will be
202 * no pipeline run to apply the display list.
204 vsp1_write(vsp1
, VI6_WPF_IRQ_ENB(wpf
->entity
.index
), 0);
205 vsp1_write(vsp1
, wpf
->entity
.index
* VI6_WPF_OFFSET
+
211 /* -----------------------------------------------------------------------------
212 * V4L2 Subdevice Operations
215 static const struct v4l2_subdev_video_ops wpf_video_ops
= {
216 .s_stream
= wpf_s_stream
,
219 static const struct v4l2_subdev_ops wpf_ops
= {
220 .video
= &wpf_video_ops
,
221 .pad
= &vsp1_rwpf_pad_ops
,
224 /* -----------------------------------------------------------------------------
225 * VSP1 Entity Operations
228 static void vsp1_wpf_destroy(struct vsp1_entity
*entity
)
230 struct vsp1_rwpf
*wpf
= entity_to_rwpf(entity
);
232 vsp1_dlm_destroy(wpf
->dlm
);
235 static int wpf_configure_writeback_chain(struct vsp1_rwpf
*wpf
,
236 struct vsp1_dl_list
*dl
)
238 unsigned int index
= wpf
->entity
.index
;
239 struct vsp1_dl_list
*dl_next
;
240 struct vsp1_dl_body
*dlb
;
242 dl_next
= vsp1_dl_list_get(wpf
->dlm
);
244 dev_err(wpf
->entity
.vsp1
->dev
,
245 "Failed to obtain a dl list, disabling writeback\n");
249 dlb
= vsp1_dl_list_get_body0(dl_next
);
250 vsp1_dl_body_write(dlb
, VI6_WPF_WRBCK_CTRL(index
), 0);
251 vsp1_dl_list_add_chain(dl
, dl_next
);
256 static void wpf_configure_stream(struct vsp1_entity
*entity
,
257 struct vsp1_pipeline
*pipe
,
258 struct vsp1_dl_list
*dl
,
259 struct vsp1_dl_body
*dlb
)
261 struct vsp1_rwpf
*wpf
= to_rwpf(&entity
->subdev
);
262 struct vsp1_device
*vsp1
= wpf
->entity
.vsp1
;
263 const struct v4l2_mbus_framefmt
*source_format
;
264 const struct v4l2_mbus_framefmt
*sink_format
;
265 unsigned int index
= wpf
->entity
.index
;
271 sink_format
= vsp1_entity_get_pad_format(&wpf
->entity
,
274 source_format
= vsp1_entity_get_pad_format(&wpf
->entity
,
279 if (!pipe
->lif
|| wpf
->writeback
) {
280 const struct v4l2_pix_format_mplane
*format
= &wpf
->format
;
281 const struct vsp1_format_info
*fmtinfo
= wpf
->fmtinfo
;
283 outfmt
= fmtinfo
->hwfmt
<< VI6_WPF_OUTFMT_WRFMT_SHIFT
;
285 if (wpf
->flip
.rotate
)
286 outfmt
|= VI6_WPF_OUTFMT_ROT
;
289 outfmt
|= VI6_WPF_OUTFMT_PXA
;
290 if (fmtinfo
->swap_yc
)
291 outfmt
|= VI6_WPF_OUTFMT_SPYCS
;
292 if (fmtinfo
->swap_uv
)
293 outfmt
|= VI6_WPF_OUTFMT_SPUVS
;
295 /* Destination stride and byte swapping. */
296 vsp1_wpf_write(wpf
, dlb
, VI6_WPF_DSTM_STRIDE_Y
,
297 format
->plane_fmt
[0].bytesperline
);
298 if (format
->num_planes
> 1)
299 vsp1_wpf_write(wpf
, dlb
, VI6_WPF_DSTM_STRIDE_C
,
300 format
->plane_fmt
[1].bytesperline
);
302 vsp1_wpf_write(wpf
, dlb
, VI6_WPF_DSWAP
, fmtinfo
->swap
);
304 if (vsp1_feature(vsp1
, VSP1_HAS_WPF_HFLIP
) && index
== 0)
305 vsp1_wpf_write(wpf
, dlb
, VI6_WPF_ROT_CTRL
,
306 VI6_WPF_ROT_CTRL_LN16
|
307 (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT
));
310 if (sink_format
->code
!= source_format
->code
)
311 outfmt
|= VI6_WPF_OUTFMT_CSC
;
313 wpf
->outfmt
= outfmt
;
315 vsp1_dl_body_write(dlb
, VI6_DPR_WPF_FPORCH(index
),
316 VI6_DPR_WPF_FPORCH_FP_WPFN
);
319 * Sources. If the pipeline has a single input and BRx is not used,
320 * configure it as the master layer. Otherwise configure all
321 * inputs as sub-layers and select the virtual RPF as the master
324 for (i
= 0; i
< vsp1
->info
->rpf_count
; ++i
) {
325 struct vsp1_rwpf
*input
= pipe
->inputs
[i
];
330 srcrpf
|= (!pipe
->brx
&& pipe
->num_inputs
== 1)
331 ? VI6_WPF_SRCRPF_RPF_ACT_MST(input
->entity
.index
)
332 : VI6_WPF_SRCRPF_RPF_ACT_SUB(input
->entity
.index
);
336 srcrpf
|= pipe
->brx
->type
== VSP1_ENTITY_BRU
337 ? VI6_WPF_SRCRPF_VIRACT_MST
338 : VI6_WPF_SRCRPF_VIRACT2_MST
;
340 vsp1_wpf_write(wpf
, dlb
, VI6_WPF_SRCRPF
, srcrpf
);
342 /* Enable interrupts. */
343 vsp1_dl_body_write(dlb
, VI6_WPF_IRQ_STA(index
), 0);
344 vsp1_dl_body_write(dlb
, VI6_WPF_IRQ_ENB(index
),
345 VI6_WFP_IRQ_ENB_DFEE
);
348 * Configure writeback for display pipelines (the wpf writeback flag is
349 * never set for memory-to-memory pipelines). Start by adding a chained
350 * display list to disable writeback after a single frame, and process
351 * to enable writeback. If the display list allocation fails don't
352 * enable writeback as we wouldn't be able to safely disable it,
353 * resulting in possible memory corruption.
355 if (wpf
->writeback
) {
356 ret
= wpf_configure_writeback_chain(wpf
, dl
);
358 wpf
->writeback
= false;
361 vsp1_dl_body_write(dlb
, VI6_WPF_WRBCK_CTRL(index
),
362 wpf
->writeback
? VI6_WPF_WRBCK_CTRL_WBMD
: 0);
365 static void wpf_configure_frame(struct vsp1_entity
*entity
,
366 struct vsp1_pipeline
*pipe
,
367 struct vsp1_dl_list
*dl
,
368 struct vsp1_dl_body
*dlb
)
370 const unsigned int mask
= BIT(WPF_CTRL_VFLIP
)
371 | BIT(WPF_CTRL_HFLIP
);
372 struct vsp1_rwpf
*wpf
= to_rwpf(&entity
->subdev
);
376 spin_lock_irqsave(&wpf
->flip
.lock
, flags
);
377 wpf
->flip
.active
= (wpf
->flip
.active
& ~mask
)
378 | (wpf
->flip
.pending
& mask
);
379 spin_unlock_irqrestore(&wpf
->flip
.lock
, flags
);
381 outfmt
= (wpf
->alpha
<< VI6_WPF_OUTFMT_PDV_SHIFT
) | wpf
->outfmt
;
383 if (wpf
->flip
.active
& BIT(WPF_CTRL_VFLIP
))
384 outfmt
|= VI6_WPF_OUTFMT_FLP
;
385 if (wpf
->flip
.active
& BIT(WPF_CTRL_HFLIP
))
386 outfmt
|= VI6_WPF_OUTFMT_HFLP
;
388 vsp1_wpf_write(wpf
, dlb
, VI6_WPF_OUTFMT
, outfmt
);
391 static void wpf_configure_partition(struct vsp1_entity
*entity
,
392 struct vsp1_pipeline
*pipe
,
393 struct vsp1_dl_list
*dl
,
394 struct vsp1_dl_body
*dlb
)
396 struct vsp1_rwpf
*wpf
= to_rwpf(&entity
->subdev
);
397 struct vsp1_device
*vsp1
= wpf
->entity
.vsp1
;
398 struct vsp1_rwpf_memory mem
= wpf
->mem
;
399 const struct v4l2_mbus_framefmt
*sink_format
;
400 const struct v4l2_pix_format_mplane
*format
= &wpf
->format
;
401 const struct vsp1_format_info
*fmtinfo
= wpf
->fmtinfo
;
409 sink_format
= vsp1_entity_get_pad_format(&wpf
->entity
,
412 width
= sink_format
->width
;
413 height
= sink_format
->height
;
417 * Cropping. The partition algorithm can split the image into
420 if (pipe
->partitions
> 1) {
421 width
= pipe
->partition
->wpf
.width
;
422 left
= pipe
->partition
->wpf
.left
;
425 vsp1_wpf_write(wpf
, dlb
, VI6_WPF_HSZCLIP
, VI6_WPF_SZCLIP_EN
|
426 (0 << VI6_WPF_SZCLIP_OFST_SHIFT
) |
427 (width
<< VI6_WPF_SZCLIP_SIZE_SHIFT
));
428 vsp1_wpf_write(wpf
, dlb
, VI6_WPF_VSZCLIP
, VI6_WPF_SZCLIP_EN
|
429 (0 << VI6_WPF_SZCLIP_OFST_SHIFT
) |
430 (height
<< VI6_WPF_SZCLIP_SIZE_SHIFT
));
433 * For display pipelines without writeback enabled there's no memory
434 * address to configure, return now.
436 if (pipe
->lif
&& !wpf
->writeback
)
440 * Update the memory offsets based on flipping configuration.
441 * The destination addresses point to the locations where the
442 * VSP starts writing to memory, which can be any corner of the
443 * image depending on the combination of flipping and rotation.
447 * First take the partition left coordinate into account.
448 * Compute the offset to order the partitions correctly on the
449 * output based on whether flipping is enabled. Consider
450 * horizontal flipping when rotation is disabled but vertical
451 * flipping when rotation is enabled, as rotating the image
452 * switches the horizontal and vertical directions. The offset
453 * is applied horizontally or vertically accordingly.
455 flip
= wpf
->flip
.active
;
457 if (flip
& BIT(WPF_CTRL_HFLIP
) && !wpf
->flip
.rotate
)
458 offset
= format
->width
- left
- width
;
459 else if (flip
& BIT(WPF_CTRL_VFLIP
) && wpf
->flip
.rotate
)
460 offset
= format
->height
- left
- width
;
464 for (i
= 0; i
< format
->num_planes
; ++i
) {
465 unsigned int hsub
= i
> 0 ? fmtinfo
->hsub
: 1;
466 unsigned int vsub
= i
> 0 ? fmtinfo
->vsub
: 1;
468 if (wpf
->flip
.rotate
)
469 mem
.addr
[i
] += offset
/ vsub
470 * format
->plane_fmt
[i
].bytesperline
;
472 mem
.addr
[i
] += offset
/ hsub
473 * fmtinfo
->bpp
[i
] / 8;
476 if (flip
& BIT(WPF_CTRL_VFLIP
)) {
478 * When rotating the output (after rotation) image
479 * height is equal to the partition width (before
480 * rotation). Otherwise it is equal to the output
483 if (wpf
->flip
.rotate
)
486 height
= format
->height
;
488 mem
.addr
[0] += (height
- 1)
489 * format
->plane_fmt
[0].bytesperline
;
491 if (format
->num_planes
> 1) {
492 offset
= (height
/ fmtinfo
->vsub
- 1)
493 * format
->plane_fmt
[1].bytesperline
;
494 mem
.addr
[1] += offset
;
495 mem
.addr
[2] += offset
;
499 if (wpf
->flip
.rotate
&& !(flip
& BIT(WPF_CTRL_HFLIP
))) {
500 unsigned int hoffset
= max(0, (int)format
->width
- 16);
503 * Compute the output coordinate. The partition
504 * horizontal (left) offset becomes a vertical offset.
506 for (i
= 0; i
< format
->num_planes
; ++i
) {
507 unsigned int hsub
= i
> 0 ? fmtinfo
->hsub
: 1;
509 mem
.addr
[i
] += hoffset
/ hsub
510 * fmtinfo
->bpp
[i
] / 8;
515 * On Gen3 hardware the SPUVS bit has no effect on 3-planar
516 * formats. Swap the U and V planes manually in that case.
518 if (vsp1
->info
->gen
== 3 && format
->num_planes
== 3 &&
520 swap(mem
.addr
[1], mem
.addr
[2]);
522 vsp1_wpf_write(wpf
, dlb
, VI6_WPF_DSTM_ADDR_Y
, mem
.addr
[0]);
523 vsp1_wpf_write(wpf
, dlb
, VI6_WPF_DSTM_ADDR_C0
, mem
.addr
[1]);
524 vsp1_wpf_write(wpf
, dlb
, VI6_WPF_DSTM_ADDR_C1
, mem
.addr
[2]);
527 * Writeback operates in single-shot mode and lasts for a single frame,
528 * reset the writeback flag to false for the next frame.
530 wpf
->writeback
= false;
533 static unsigned int wpf_max_width(struct vsp1_entity
*entity
,
534 struct vsp1_pipeline
*pipe
)
536 struct vsp1_rwpf
*wpf
= to_rwpf(&entity
->subdev
);
538 return wpf
->flip
.rotate
? 256 : wpf
->max_width
;
541 static void wpf_partition(struct vsp1_entity
*entity
,
542 struct vsp1_pipeline
*pipe
,
543 struct vsp1_partition
*partition
,
544 unsigned int partition_idx
,
545 struct vsp1_partition_window
*window
)
547 partition
->wpf
= *window
;
550 static const struct vsp1_entity_operations wpf_entity_ops
= {
551 .destroy
= vsp1_wpf_destroy
,
552 .configure_stream
= wpf_configure_stream
,
553 .configure_frame
= wpf_configure_frame
,
554 .configure_partition
= wpf_configure_partition
,
555 .max_width
= wpf_max_width
,
556 .partition
= wpf_partition
,
559 /* -----------------------------------------------------------------------------
560 * Initialization and Cleanup
563 struct vsp1_rwpf
*vsp1_wpf_create(struct vsp1_device
*vsp1
, unsigned int index
)
565 struct vsp1_rwpf
*wpf
;
569 wpf
= devm_kzalloc(vsp1
->dev
, sizeof(*wpf
), GFP_KERNEL
);
571 return ERR_PTR(-ENOMEM
);
573 if (vsp1
->info
->gen
== 2) {
574 wpf
->max_width
= WPF_GEN2_MAX_WIDTH
;
575 wpf
->max_height
= WPF_GEN2_MAX_HEIGHT
;
577 wpf
->max_width
= WPF_GEN3_MAX_WIDTH
;
578 wpf
->max_height
= WPF_GEN3_MAX_HEIGHT
;
581 wpf
->entity
.ops
= &wpf_entity_ops
;
582 wpf
->entity
.type
= VSP1_ENTITY_WPF
;
583 wpf
->entity
.index
= index
;
585 sprintf(name
, "wpf.%u", index
);
586 ret
= vsp1_entity_init(vsp1
, &wpf
->entity
, name
, 2, &wpf_ops
,
587 MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER
);
591 /* Initialize the display list manager. */
592 wpf
->dlm
= vsp1_dlm_create(vsp1
, index
, 64);
598 /* Initialize the control handler. */
599 ret
= wpf_init_controls(wpf
);
601 dev_err(vsp1
->dev
, "wpf%u: failed to initialize controls\n",
606 v4l2_ctrl_handler_setup(&wpf
->ctrls
);
611 vsp1_entity_destroy(&wpf
->entity
);