2 * vsp1_wpf.c -- R-Car VSP1 Write Pixel Formatter
4 * Copyright (C) 2013-2014 Renesas Electronics Corporation
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
14 #include <linux/device.h>
16 #include <media/v4l2-subdev.h>
20 #include "vsp1_pipe.h"
21 #include "vsp1_rwpf.h"
22 #include "vsp1_video.h"
24 #define WPF_GEN2_MAX_WIDTH 2048U
25 #define WPF_GEN2_MAX_HEIGHT 2048U
26 #define WPF_GEN3_MAX_WIDTH 8190U
27 #define WPF_GEN3_MAX_HEIGHT 8190U
29 /* -----------------------------------------------------------------------------
33 static inline void vsp1_wpf_write(struct vsp1_rwpf
*wpf
,
34 struct vsp1_dl_list
*dl
, u32 reg
, u32 data
)
36 vsp1_dl_list_write(dl
, reg
+ wpf
->entity
.index
* VI6_WPF_OFFSET
, data
);
39 /* -----------------------------------------------------------------------------
48 static int vsp1_wpf_set_rotation(struct vsp1_rwpf
*wpf
, unsigned int rotation
)
50 struct vsp1_video
*video
= wpf
->video
;
51 struct v4l2_mbus_framefmt
*sink_format
;
52 struct v4l2_mbus_framefmt
*source_format
;
57 * Only consider the 0°/180° from/to 90°/270° modifications, the rest
58 * is taken care of by the flipping configuration.
60 rotate
= rotation
== 90 || rotation
== 270;
61 if (rotate
== wpf
->flip
.rotate
)
64 /* Changing rotation isn't allowed when buffers are allocated. */
65 mutex_lock(&video
->lock
);
67 if (vb2_is_busy(&video
->queue
)) {
72 sink_format
= vsp1_entity_get_pad_format(&wpf
->entity
,
75 source_format
= vsp1_entity_get_pad_format(&wpf
->entity
,
79 mutex_lock(&wpf
->entity
.lock
);
82 source_format
->width
= sink_format
->height
;
83 source_format
->height
= sink_format
->width
;
85 source_format
->width
= sink_format
->width
;
86 source_format
->height
= sink_format
->height
;
89 wpf
->flip
.rotate
= rotate
;
91 mutex_unlock(&wpf
->entity
.lock
);
94 mutex_unlock(&video
->lock
);
98 static int vsp1_wpf_s_ctrl(struct v4l2_ctrl
*ctrl
)
100 struct vsp1_rwpf
*wpf
=
101 container_of(ctrl
->handler
, struct vsp1_rwpf
, ctrls
);
102 unsigned int rotation
;
106 /* Update the rotation. */
107 rotation
= wpf
->flip
.ctrls
.rotate
? wpf
->flip
.ctrls
.rotate
->val
: 0;
108 ret
= vsp1_wpf_set_rotation(wpf
, rotation
);
113 * Compute the flip value resulting from all three controls, with
114 * rotation by 180° flipping the image in both directions. Store the
115 * result in the pending flip field for the next frame that will be
118 if (wpf
->flip
.ctrls
.vflip
->val
)
119 flip
|= BIT(WPF_CTRL_VFLIP
);
121 if (wpf
->flip
.ctrls
.hflip
&& wpf
->flip
.ctrls
.hflip
->val
)
122 flip
|= BIT(WPF_CTRL_HFLIP
);
124 if (rotation
== 180 || rotation
== 270)
125 flip
^= BIT(WPF_CTRL_VFLIP
) | BIT(WPF_CTRL_HFLIP
);
127 spin_lock_irq(&wpf
->flip
.lock
);
128 wpf
->flip
.pending
= flip
;
129 spin_unlock_irq(&wpf
->flip
.lock
);
134 static const struct v4l2_ctrl_ops vsp1_wpf_ctrl_ops
= {
135 .s_ctrl
= vsp1_wpf_s_ctrl
,
138 static int wpf_init_controls(struct vsp1_rwpf
*wpf
)
140 struct vsp1_device
*vsp1
= wpf
->entity
.vsp1
;
141 unsigned int num_flip_ctrls
;
143 spin_lock_init(&wpf
->flip
.lock
);
145 if (wpf
->entity
.index
!= 0) {
146 /* Only WPF0 supports flipping. */
148 } else if (vsp1
->info
->features
& VSP1_HAS_WPF_HFLIP
) {
150 * When horizontal flip is supported the WPF implements three
151 * controls (horizontal flip, vertical flip and rotation).
154 } else if (vsp1
->info
->features
& VSP1_HAS_WPF_VFLIP
) {
156 * When only vertical flip is supported the WPF implements a
157 * single control (vertical flip).
161 /* Otherwise flipping is not supported. */
165 vsp1_rwpf_init_ctrls(wpf
, num_flip_ctrls
);
167 if (num_flip_ctrls
>= 1) {
168 wpf
->flip
.ctrls
.vflip
=
169 v4l2_ctrl_new_std(&wpf
->ctrls
, &vsp1_wpf_ctrl_ops
,
170 V4L2_CID_VFLIP
, 0, 1, 1, 0);
173 if (num_flip_ctrls
== 3) {
174 wpf
->flip
.ctrls
.hflip
=
175 v4l2_ctrl_new_std(&wpf
->ctrls
, &vsp1_wpf_ctrl_ops
,
176 V4L2_CID_HFLIP
, 0, 1, 1, 0);
177 wpf
->flip
.ctrls
.rotate
=
178 v4l2_ctrl_new_std(&wpf
->ctrls
, &vsp1_wpf_ctrl_ops
,
179 V4L2_CID_ROTATE
, 0, 270, 90, 0);
180 v4l2_ctrl_cluster(3, &wpf
->flip
.ctrls
.vflip
);
183 if (wpf
->ctrls
.error
) {
184 dev_err(vsp1
->dev
, "wpf%u: failed to initialize controls\n",
186 return wpf
->ctrls
.error
;
192 /* -----------------------------------------------------------------------------
193 * V4L2 Subdevice Core Operations
196 static int wpf_s_stream(struct v4l2_subdev
*subdev
, int enable
)
198 struct vsp1_rwpf
*wpf
= to_rwpf(subdev
);
199 struct vsp1_device
*vsp1
= wpf
->entity
.vsp1
;
205 * Write to registers directly when stopping the stream as there will be
206 * no pipeline run to apply the display list.
208 vsp1_write(vsp1
, VI6_WPF_IRQ_ENB(wpf
->entity
.index
), 0);
209 vsp1_write(vsp1
, wpf
->entity
.index
* VI6_WPF_OFFSET
+
215 /* -----------------------------------------------------------------------------
216 * V4L2 Subdevice Operations
219 static const struct v4l2_subdev_video_ops wpf_video_ops
= {
220 .s_stream
= wpf_s_stream
,
223 static const struct v4l2_subdev_ops wpf_ops
= {
224 .video
= &wpf_video_ops
,
225 .pad
= &vsp1_rwpf_pad_ops
,
228 /* -----------------------------------------------------------------------------
229 * VSP1 Entity Operations
232 static void vsp1_wpf_destroy(struct vsp1_entity
*entity
)
234 struct vsp1_rwpf
*wpf
= entity_to_rwpf(entity
);
236 vsp1_dlm_destroy(wpf
->dlm
);
239 static void wpf_configure(struct vsp1_entity
*entity
,
240 struct vsp1_pipeline
*pipe
,
241 struct vsp1_dl_list
*dl
,
242 enum vsp1_entity_params params
)
244 struct vsp1_rwpf
*wpf
= to_rwpf(&entity
->subdev
);
245 struct vsp1_device
*vsp1
= wpf
->entity
.vsp1
;
246 const struct v4l2_mbus_framefmt
*source_format
;
247 const struct v4l2_mbus_framefmt
*sink_format
;
252 if (params
== VSP1_ENTITY_PARAMS_RUNTIME
) {
253 const unsigned int mask
= BIT(WPF_CTRL_VFLIP
)
254 | BIT(WPF_CTRL_HFLIP
);
257 spin_lock_irqsave(&wpf
->flip
.lock
, flags
);
258 wpf
->flip
.active
= (wpf
->flip
.active
& ~mask
)
259 | (wpf
->flip
.pending
& mask
);
260 spin_unlock_irqrestore(&wpf
->flip
.lock
, flags
);
262 outfmt
= (wpf
->alpha
<< VI6_WPF_OUTFMT_PDV_SHIFT
) | wpf
->outfmt
;
264 if (wpf
->flip
.active
& BIT(WPF_CTRL_VFLIP
))
265 outfmt
|= VI6_WPF_OUTFMT_FLP
;
266 if (wpf
->flip
.active
& BIT(WPF_CTRL_HFLIP
))
267 outfmt
|= VI6_WPF_OUTFMT_HFLP
;
269 vsp1_wpf_write(wpf
, dl
, VI6_WPF_OUTFMT
, outfmt
);
273 sink_format
= vsp1_entity_get_pad_format(&wpf
->entity
,
276 source_format
= vsp1_entity_get_pad_format(&wpf
->entity
,
280 if (params
== VSP1_ENTITY_PARAMS_PARTITION
) {
281 const struct v4l2_pix_format_mplane
*format
= &wpf
->format
;
282 const struct vsp1_format_info
*fmtinfo
= wpf
->fmtinfo
;
283 struct vsp1_rwpf_memory mem
= wpf
->mem
;
284 unsigned int flip
= wpf
->flip
.active
;
285 unsigned int width
= sink_format
->width
;
286 unsigned int height
= sink_format
->height
;
290 * Cropping. The partition algorithm can split the image into
293 if (pipe
->partitions
> 1)
294 width
= pipe
->partition
->wpf
.width
;
296 vsp1_wpf_write(wpf
, dl
, VI6_WPF_HSZCLIP
, VI6_WPF_SZCLIP_EN
|
297 (0 << VI6_WPF_SZCLIP_OFST_SHIFT
) |
298 (width
<< VI6_WPF_SZCLIP_SIZE_SHIFT
));
299 vsp1_wpf_write(wpf
, dl
, VI6_WPF_VSZCLIP
, VI6_WPF_SZCLIP_EN
|
300 (0 << VI6_WPF_SZCLIP_OFST_SHIFT
) |
301 (height
<< VI6_WPF_SZCLIP_SIZE_SHIFT
));
307 * Update the memory offsets based on flipping configuration.
308 * The destination addresses point to the locations where the
309 * VSP starts writing to memory, which can be any corner of the
310 * image depending on the combination of flipping and rotation.
314 * First take the partition left coordinate into account.
315 * Compute the offset to order the partitions correctly on the
316 * output based on whether flipping is enabled. Consider
317 * horizontal flipping when rotation is disabled but vertical
318 * flipping when rotation is enabled, as rotating the image
319 * switches the horizontal and vertical directions. The offset
320 * is applied horizontally or vertically accordingly.
322 if (flip
& BIT(WPF_CTRL_HFLIP
) && !wpf
->flip
.rotate
)
323 offset
= format
->width
- pipe
->partition
->wpf
.left
324 - pipe
->partition
->wpf
.width
;
325 else if (flip
& BIT(WPF_CTRL_VFLIP
) && wpf
->flip
.rotate
)
326 offset
= format
->height
- pipe
->partition
->wpf
.left
327 - pipe
->partition
->wpf
.width
;
329 offset
= pipe
->partition
->wpf
.left
;
331 for (i
= 0; i
< format
->num_planes
; ++i
) {
332 unsigned int hsub
= i
> 0 ? fmtinfo
->hsub
: 1;
333 unsigned int vsub
= i
> 0 ? fmtinfo
->vsub
: 1;
335 if (wpf
->flip
.rotate
)
336 mem
.addr
[i
] += offset
/ vsub
337 * format
->plane_fmt
[i
].bytesperline
;
339 mem
.addr
[i
] += offset
/ hsub
340 * fmtinfo
->bpp
[i
] / 8;
343 if (flip
& BIT(WPF_CTRL_VFLIP
)) {
345 * When rotating the output (after rotation) image
346 * height is equal to the partition width (before
347 * rotation). Otherwise it is equal to the output
350 if (wpf
->flip
.rotate
)
351 height
= pipe
->partition
->wpf
.width
;
353 height
= format
->height
;
355 mem
.addr
[0] += (height
- 1)
356 * format
->plane_fmt
[0].bytesperline
;
358 if (format
->num_planes
> 1) {
359 offset
= (height
/ fmtinfo
->vsub
- 1)
360 * format
->plane_fmt
[1].bytesperline
;
361 mem
.addr
[1] += offset
;
362 mem
.addr
[2] += offset
;
366 if (wpf
->flip
.rotate
&& !(flip
& BIT(WPF_CTRL_HFLIP
))) {
367 unsigned int hoffset
= max(0, (int)format
->width
- 16);
370 * Compute the output coordinate. The partition
371 * horizontal (left) offset becomes a vertical offset.
373 for (i
= 0; i
< format
->num_planes
; ++i
) {
374 unsigned int hsub
= i
> 0 ? fmtinfo
->hsub
: 1;
376 mem
.addr
[i
] += hoffset
/ hsub
377 * fmtinfo
->bpp
[i
] / 8;
382 * On Gen3 hardware the SPUVS bit has no effect on 3-planar
383 * formats. Swap the U and V planes manually in that case.
385 if (vsp1
->info
->gen
== 3 && format
->num_planes
== 3 &&
387 swap(mem
.addr
[1], mem
.addr
[2]);
389 vsp1_wpf_write(wpf
, dl
, VI6_WPF_DSTM_ADDR_Y
, mem
.addr
[0]);
390 vsp1_wpf_write(wpf
, dl
, VI6_WPF_DSTM_ADDR_C0
, mem
.addr
[1]);
391 vsp1_wpf_write(wpf
, dl
, VI6_WPF_DSTM_ADDR_C1
, mem
.addr
[2]);
397 const struct v4l2_pix_format_mplane
*format
= &wpf
->format
;
398 const struct vsp1_format_info
*fmtinfo
= wpf
->fmtinfo
;
400 outfmt
= fmtinfo
->hwfmt
<< VI6_WPF_OUTFMT_WRFMT_SHIFT
;
402 if (wpf
->flip
.rotate
)
403 outfmt
|= VI6_WPF_OUTFMT_ROT
;
406 outfmt
|= VI6_WPF_OUTFMT_PXA
;
407 if (fmtinfo
->swap_yc
)
408 outfmt
|= VI6_WPF_OUTFMT_SPYCS
;
409 if (fmtinfo
->swap_uv
)
410 outfmt
|= VI6_WPF_OUTFMT_SPUVS
;
412 /* Destination stride and byte swapping. */
413 vsp1_wpf_write(wpf
, dl
, VI6_WPF_DSTM_STRIDE_Y
,
414 format
->plane_fmt
[0].bytesperline
);
415 if (format
->num_planes
> 1)
416 vsp1_wpf_write(wpf
, dl
, VI6_WPF_DSTM_STRIDE_C
,
417 format
->plane_fmt
[1].bytesperline
);
419 vsp1_wpf_write(wpf
, dl
, VI6_WPF_DSWAP
, fmtinfo
->swap
);
421 if (vsp1
->info
->features
& VSP1_HAS_WPF_HFLIP
&&
422 wpf
->entity
.index
== 0)
423 vsp1_wpf_write(wpf
, dl
, VI6_WPF_ROT_CTRL
,
424 VI6_WPF_ROT_CTRL_LN16
|
425 (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT
));
428 if (sink_format
->code
!= source_format
->code
)
429 outfmt
|= VI6_WPF_OUTFMT_CSC
;
431 wpf
->outfmt
= outfmt
;
433 vsp1_dl_list_write(dl
, VI6_DPR_WPF_FPORCH(wpf
->entity
.index
),
434 VI6_DPR_WPF_FPORCH_FP_WPFN
);
436 vsp1_dl_list_write(dl
, VI6_WPF_WRBCK_CTRL
, 0);
439 * Sources. If the pipeline has a single input and BRU is not used,
440 * configure it as the master layer. Otherwise configure all
441 * inputs as sub-layers and select the virtual RPF as the master
444 for (i
= 0; i
< vsp1
->info
->rpf_count
; ++i
) {
445 struct vsp1_rwpf
*input
= pipe
->inputs
[i
];
450 srcrpf
|= (!pipe
->bru
&& pipe
->num_inputs
== 1)
451 ? VI6_WPF_SRCRPF_RPF_ACT_MST(input
->entity
.index
)
452 : VI6_WPF_SRCRPF_RPF_ACT_SUB(input
->entity
.index
);
456 srcrpf
|= pipe
->bru
->type
== VSP1_ENTITY_BRU
457 ? VI6_WPF_SRCRPF_VIRACT_MST
458 : VI6_WPF_SRCRPF_VIRACT2_MST
;
460 vsp1_wpf_write(wpf
, dl
, VI6_WPF_SRCRPF
, srcrpf
);
462 /* Enable interrupts */
463 vsp1_dl_list_write(dl
, VI6_WPF_IRQ_STA(wpf
->entity
.index
), 0);
464 vsp1_dl_list_write(dl
, VI6_WPF_IRQ_ENB(wpf
->entity
.index
),
465 VI6_WFP_IRQ_ENB_DFEE
);
468 static unsigned int wpf_max_width(struct vsp1_entity
*entity
,
469 struct vsp1_pipeline
*pipe
)
471 struct vsp1_rwpf
*wpf
= to_rwpf(&entity
->subdev
);
473 return wpf
->flip
.rotate
? 256 : wpf
->max_width
;
476 static void wpf_partition(struct vsp1_entity
*entity
,
477 struct vsp1_pipeline
*pipe
,
478 struct vsp1_partition
*partition
,
479 unsigned int partition_idx
,
480 struct vsp1_partition_window
*window
)
482 partition
->wpf
= *window
;
485 static const struct vsp1_entity_operations wpf_entity_ops
= {
486 .destroy
= vsp1_wpf_destroy
,
487 .configure
= wpf_configure
,
488 .max_width
= wpf_max_width
,
489 .partition
= wpf_partition
,
492 /* -----------------------------------------------------------------------------
493 * Initialization and Cleanup
496 struct vsp1_rwpf
*vsp1_wpf_create(struct vsp1_device
*vsp1
, unsigned int index
)
498 struct vsp1_rwpf
*wpf
;
502 wpf
= devm_kzalloc(vsp1
->dev
, sizeof(*wpf
), GFP_KERNEL
);
504 return ERR_PTR(-ENOMEM
);
506 if (vsp1
->info
->gen
== 2) {
507 wpf
->max_width
= WPF_GEN2_MAX_WIDTH
;
508 wpf
->max_height
= WPF_GEN2_MAX_HEIGHT
;
510 wpf
->max_width
= WPF_GEN3_MAX_WIDTH
;
511 wpf
->max_height
= WPF_GEN3_MAX_HEIGHT
;
514 wpf
->entity
.ops
= &wpf_entity_ops
;
515 wpf
->entity
.type
= VSP1_ENTITY_WPF
;
516 wpf
->entity
.index
= index
;
518 sprintf(name
, "wpf.%u", index
);
519 ret
= vsp1_entity_init(vsp1
, &wpf
->entity
, name
, 2, &wpf_ops
,
520 MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER
);
524 /* Initialize the display list manager. */
525 wpf
->dlm
= vsp1_dlm_create(vsp1
, index
, 64);
531 /* Initialize the control handler. */
532 ret
= wpf_init_controls(wpf
);
534 dev_err(vsp1
->dev
, "wpf%u: failed to initialize controls\n",
539 v4l2_ctrl_handler_setup(&wpf
->ctrls
);
544 vsp1_entity_destroy(&wpf
->entity
);