aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2016-06-20 05:07:08 -0400
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2017-04-14 21:36:03 -0400
commit3e9a0e0bfafdf6c28c520d43fd64c5775d04662f (patch)
tree80f6bed9a8978beefe863a4e3a0d0ad6bc33ee8a
parent99bb078eee469f7284b1dca36cf9edf7af1a92bf (diff)
[media] v4l: vsp1: wpf: Implement rotation support
Some WPF instances, on Gen3 devices, can perform 90° rotation when writing frames to memory. Implement support for this using the V4L2_CID_ROTATE control. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.c5
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.h7
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c12
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c205
5 files changed, 177 insertions, 54 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index f5a9a4c8c74d..8feddd59cf8d 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -106,7 +106,7 @@ static void rpf_configure(struct vsp1_entity *entity,
106 * of the pipeline. 106 * of the pipeline.
107 */ 107 */
108 output = vsp1_entity_get_pad_format(wpf, wpf->config, 108 output = vsp1_entity_get_pad_format(wpf, wpf->config,
109 RWPF_PAD_SOURCE); 109 RWPF_PAD_SINK);
110 110
111 crop.width = pipe->partition.width * input_width 111 crop.width = pipe->partition.width * input_width
112 / output->width; 112 / output->width;
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 7d52c88a583e..cfd8f1904fa6 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -121,6 +121,11 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
121 RWPF_PAD_SOURCE); 121 RWPF_PAD_SOURCE);
122 *format = fmt->format; 122 *format = fmt->format;
123 123
124 if (rwpf->flip.rotate) {
125 format->width = fmt->format.height;
126 format->height = fmt->format.width;
127 }
128
124done: 129done:
125 mutex_unlock(&rwpf->entity.lock); 130 mutex_unlock(&rwpf->entity.lock);
126 return ret; 131 return ret;
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 1c98aff3da5d..58215a7ab631 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -56,9 +56,14 @@ struct vsp1_rwpf {
56 56
57 struct { 57 struct {
58 spinlock_t lock; 58 spinlock_t lock;
59 struct v4l2_ctrl *ctrls[2]; 59 struct {
60 struct v4l2_ctrl *vflip;
61 struct v4l2_ctrl *hflip;
62 struct v4l2_ctrl *rotate;
63 } ctrls;
60 unsigned int pending; 64 unsigned int pending;
61 unsigned int active; 65 unsigned int active;
66 bool rotate;
62 } flip; 67 } flip;
63 68
64 struct vsp1_rwpf_memory mem; 69 struct vsp1_rwpf_memory mem;
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 5239e08fabc3..795a3ca9ca03 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -187,9 +187,13 @@ static void vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
187 struct vsp1_entity *entity; 187 struct vsp1_entity *entity;
188 unsigned int div_size; 188 unsigned int div_size;
189 189
190 /*
191 * Partitions are computed on the size before rotation, use the format
192 * at the WPF sink.
193 */
190 format = vsp1_entity_get_pad_format(&pipe->output->entity, 194 format = vsp1_entity_get_pad_format(&pipe->output->entity,
191 pipe->output->entity.config, 195 pipe->output->entity.config,
192 RWPF_PAD_SOURCE); 196 RWPF_PAD_SINK);
193 div_size = format->width; 197 div_size = format->width;
194 198
195 /* Gen2 hardware doesn't require image partitioning. */ 199 /* Gen2 hardware doesn't require image partitioning. */
@@ -229,9 +233,13 @@ static struct v4l2_rect vsp1_video_partition(struct vsp1_pipeline *pipe,
229 struct v4l2_rect partition; 233 struct v4l2_rect partition;
230 unsigned int modulus; 234 unsigned int modulus;
231 235
236 /*
237 * Partitions are computed on the size before rotation, use the format
238 * at the WPF sink.
239 */
232 format = vsp1_entity_get_pad_format(&pipe->output->entity, 240 format = vsp1_entity_get_pad_format(&pipe->output->entity,
233 pipe->output->entity.config, 241 pipe->output->entity.config,
234 RWPF_PAD_SOURCE); 242 RWPF_PAD_SINK);
235 243
236 /* A single partition simply processes the output size in full. */ 244 /* A single partition simply processes the output size in full. */
237 if (pipe->partitions <= 1) { 245 if (pipe->partitions <= 1) {
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 25a2ed6e2e18..32df109b119f 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -43,32 +43,90 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf,
43enum wpf_flip_ctrl { 43enum wpf_flip_ctrl {
44 WPF_CTRL_VFLIP = 0, 44 WPF_CTRL_VFLIP = 0,
45 WPF_CTRL_HFLIP = 1, 45 WPF_CTRL_HFLIP = 1,
46 WPF_CTRL_MAX,
47}; 46};
48 47
48static int vsp1_wpf_set_rotation(struct vsp1_rwpf *wpf, unsigned int rotation)
49{
50 struct vsp1_video *video = wpf->video;
51 struct v4l2_mbus_framefmt *sink_format;
52 struct v4l2_mbus_framefmt *source_format;
53 bool rotate;
54 int ret = 0;
55
56 /*
57 * Only consider the 0°/180° from/to 90°/270° modifications, the rest
58 * is taken care of by the flipping configuration.
59 */
60 rotate = rotation == 90 || rotation == 270;
61 if (rotate == wpf->flip.rotate)
62 return 0;
63
64 /* Changing rotation isn't allowed when buffers are allocated. */
65 mutex_lock(&video->lock);
66
67 if (vb2_is_busy(&video->queue)) {
68 ret = -EBUSY;
69 goto done;
70 }
71
72 sink_format = vsp1_entity_get_pad_format(&wpf->entity,
73 wpf->entity.config,
74 RWPF_PAD_SINK);
75 source_format = vsp1_entity_get_pad_format(&wpf->entity,
76 wpf->entity.config,
77 RWPF_PAD_SOURCE);
78
79 mutex_lock(&wpf->entity.lock);
80
81 if (rotate) {
82 source_format->width = sink_format->height;
83 source_format->height = sink_format->width;
84 } else {
85 source_format->width = sink_format->width;
86 source_format->height = sink_format->height;
87 }
88
89 wpf->flip.rotate = rotate;
90
91 mutex_unlock(&wpf->entity.lock);
92
93done:
94 mutex_unlock(&video->lock);
95 return ret;
96}
97
49static int vsp1_wpf_s_ctrl(struct v4l2_ctrl *ctrl) 98static int vsp1_wpf_s_ctrl(struct v4l2_ctrl *ctrl)
50{ 99{
51 struct vsp1_rwpf *wpf = 100 struct vsp1_rwpf *wpf =
52 container_of(ctrl->handler, struct vsp1_rwpf, ctrls); 101 container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
53 unsigned int i; 102 unsigned int rotation;
54 u32 flip = 0; 103 u32 flip = 0;
104 int ret;
55 105
56 switch (ctrl->id) { 106 /* Update the rotation. */
57 case V4L2_CID_HFLIP: 107 rotation = wpf->flip.ctrls.rotate ? wpf->flip.ctrls.rotate->val : 0;
58 case V4L2_CID_VFLIP: 108 ret = vsp1_wpf_set_rotation(wpf, rotation);
59 for (i = 0; i < WPF_CTRL_MAX; ++i) { 109 if (ret < 0)
60 if (wpf->flip.ctrls[i]) 110 return ret;
61 flip |= wpf->flip.ctrls[i]->val ? BIT(i) : 0;
62 }
63 111
64 spin_lock_irq(&wpf->flip.lock); 112 /*
65 wpf->flip.pending = flip; 113 * Compute the flip value resulting from all three controls, with
66 spin_unlock_irq(&wpf->flip.lock); 114 * rotation by 180° flipping the image in both directions. Store the
67 break; 115 * result in the pending flip field for the next frame that will be
116 * processed.
117 */
118 if (wpf->flip.ctrls.vflip->val)
119 flip |= BIT(WPF_CTRL_VFLIP);
68 120
69 default: 121 if (wpf->flip.ctrls.hflip && wpf->flip.ctrls.hflip->val)
70 return -EINVAL; 122 flip |= BIT(WPF_CTRL_HFLIP);
71 } 123
124 if (rotation == 180 || rotation == 270)
125 flip ^= BIT(WPF_CTRL_VFLIP) | BIT(WPF_CTRL_HFLIP);
126
127 spin_lock_irq(&wpf->flip.lock);
128 wpf->flip.pending = flip;
129 spin_unlock_irq(&wpf->flip.lock);
72 130
73 return 0; 131 return 0;
74} 132}
@@ -89,10 +147,10 @@ static int wpf_init_controls(struct vsp1_rwpf *wpf)
89 num_flip_ctrls = 0; 147 num_flip_ctrls = 0;
90 } else if (vsp1->info->features & VSP1_HAS_WPF_HFLIP) { 148 } else if (vsp1->info->features & VSP1_HAS_WPF_HFLIP) {
91 /* 149 /*
92 * When horizontal flip is supported the WPF implements two 150 * When horizontal flip is supported the WPF implements three
93 * controls (horizontal flip and vertical flip). 151 * controls (horizontal flip, vertical flip and rotation).
94 */ 152 */
95 num_flip_ctrls = 2; 153 num_flip_ctrls = 3;
96 } else if (vsp1->info->features & VSP1_HAS_WPF_VFLIP) { 154 } else if (vsp1->info->features & VSP1_HAS_WPF_VFLIP) {
97 /* 155 /*
98 * When only vertical flip is supported the WPF implements a 156 * When only vertical flip is supported the WPF implements a
@@ -107,17 +165,19 @@ static int wpf_init_controls(struct vsp1_rwpf *wpf)
107 vsp1_rwpf_init_ctrls(wpf, num_flip_ctrls); 165 vsp1_rwpf_init_ctrls(wpf, num_flip_ctrls);
108 166
109 if (num_flip_ctrls >= 1) { 167 if (num_flip_ctrls >= 1) {
110 wpf->flip.ctrls[WPF_CTRL_VFLIP] = 168 wpf->flip.ctrls.vflip =
111 v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops, 169 v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
112 V4L2_CID_VFLIP, 0, 1, 1, 0); 170 V4L2_CID_VFLIP, 0, 1, 1, 0);
113 } 171 }
114 172
115 if (num_flip_ctrls == 2) { 173 if (num_flip_ctrls == 3) {
116 wpf->flip.ctrls[WPF_CTRL_HFLIP] = 174 wpf->flip.ctrls.hflip =
117 v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops, 175 v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
118 V4L2_CID_HFLIP, 0, 1, 1, 0); 176 V4L2_CID_HFLIP, 0, 1, 1, 0);
119 177 wpf->flip.ctrls.rotate =
120 v4l2_ctrl_cluster(2, wpf->flip.ctrls); 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);
121 } 181 }
122 182
123 if (wpf->ctrls.error) { 183 if (wpf->ctrls.error) {
@@ -222,8 +282,8 @@ static void wpf_configure(struct vsp1_entity *entity,
222 const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; 282 const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
223 struct vsp1_rwpf_memory mem = wpf->mem; 283 struct vsp1_rwpf_memory mem = wpf->mem;
224 unsigned int flip = wpf->flip.active; 284 unsigned int flip = wpf->flip.active;
225 unsigned int width = source_format->width; 285 unsigned int width = sink_format->width;
226 unsigned int height = source_format->height; 286 unsigned int height = sink_format->height;
227 unsigned int offset; 287 unsigned int offset;
228 288
229 /* 289 /*
@@ -246,45 +306,78 @@ static void wpf_configure(struct vsp1_entity *entity,
246 /* 306 /*
247 * Update the memory offsets based on flipping configuration. 307 * Update the memory offsets based on flipping configuration.
248 * The destination addresses point to the locations where the 308 * The destination addresses point to the locations where the
249 * VSP starts writing to memory, which can be different corners 309 * VSP starts writing to memory, which can be any corner of the
250 * of the image depending on vertical flipping. 310 * image depending on the combination of flipping and rotation.
251 */ 311 */
252 if (pipe->partitions > 1) {
253 const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
254 312
255 /* 313 /*
256 * Horizontal flipping is handled through a line buffer 314 * First take the partition left coordinate into account.
257 * and doesn't modify the start address, but still needs 315 * Compute the offset to order the partitions correctly on the
258 * to be handled when image partitioning is in effect to 316 * output based on whether flipping is enabled. Consider
259 * order the partitions correctly. 317 * horizontal flipping when rotation is disabled but vertical
260 */ 318 * flipping when rotation is enabled, as rotating the image
261 if (flip & BIT(WPF_CTRL_HFLIP)) 319 * switches the horizontal and vertical directions. The offset
262 offset = format->width - pipe->partition.left 320 * is applied horizontally or vertically accordingly.
263 - pipe->partition.width; 321 */
322 if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate)
323 offset = format->width - pipe->partition.left
324 - pipe->partition.width;
325 else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate)
326 offset = format->height - pipe->partition.left
327 - pipe->partition.width;
328 else
329 offset = pipe->partition.left;
330
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;
334
335 if (wpf->flip.rotate)
336 mem.addr[i] += offset / vsub
337 * format->plane_fmt[i].bytesperline;
264 else 338 else
265 offset = pipe->partition.left; 339 mem.addr[i] += offset / hsub
266 340 * fmtinfo->bpp[i] / 8;
267 mem.addr[0] += offset * fmtinfo->bpp[0] / 8;
268 if (format->num_planes > 1) {
269 mem.addr[1] += offset / fmtinfo->hsub
270 * fmtinfo->bpp[1] / 8;
271 mem.addr[2] += offset / fmtinfo->hsub
272 * fmtinfo->bpp[2] / 8;
273 }
274 } 341 }
275 342
276 if (flip & BIT(WPF_CTRL_VFLIP)) { 343 if (flip & BIT(WPF_CTRL_VFLIP)) {
277 mem.addr[0] += (format->height - 1) 344 /*
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
348 * image height.
349 */
350 if (wpf->flip.rotate)
351 height = pipe->partition.width;
352 else
353 height = format->height;
354
355 mem.addr[0] += (height - 1)
278 * format->plane_fmt[0].bytesperline; 356 * format->plane_fmt[0].bytesperline;
279 357
280 if (format->num_planes > 1) { 358 if (format->num_planes > 1) {
281 offset = (format->height / wpf->fmtinfo->vsub - 1) 359 offset = (height / fmtinfo->vsub - 1)
282 * format->plane_fmt[1].bytesperline; 360 * format->plane_fmt[1].bytesperline;
283 mem.addr[1] += offset; 361 mem.addr[1] += offset;
284 mem.addr[2] += offset; 362 mem.addr[2] += offset;
285 } 363 }
286 } 364 }
287 365
366 if (wpf->flip.rotate && !(flip & BIT(WPF_CTRL_HFLIP))) {
367 unsigned int hoffset = max(0, (int)format->width - 16);
368
369 /*
370 * Compute the output coordinate. The partition
371 * horizontal (left) offset becomes a vertical offset.
372 */
373 for (i = 0; i < format->num_planes; ++i) {
374 unsigned int hsub = i > 0 ? fmtinfo->hsub : 1;
375
376 mem.addr[i] += hoffset / hsub
377 * fmtinfo->bpp[i] / 8;
378 }
379 }
380
288 /* 381 /*
289 * On Gen3 hardware the SPUVS bit has no effect on 3-planar 382 * On Gen3 hardware the SPUVS bit has no effect on 3-planar
290 * formats. Swap the U and V planes manually in that case. 383 * formats. Swap the U and V planes manually in that case.
@@ -306,6 +399,9 @@ static void wpf_configure(struct vsp1_entity *entity,
306 399
307 outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT; 400 outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT;
308 401
402 if (wpf->flip.rotate)
403 outfmt |= VI6_WPF_OUTFMT_ROT;
404
309 if (fmtinfo->alpha) 405 if (fmtinfo->alpha)
310 outfmt |= VI6_WPF_OUTFMT_PXA; 406 outfmt |= VI6_WPF_OUTFMT_PXA;
311 if (fmtinfo->swap_yc) 407 if (fmtinfo->swap_yc)
@@ -367,9 +463,18 @@ static void wpf_configure(struct vsp1_entity *entity,
367 VI6_WFP_IRQ_ENB_DFEE); 463 VI6_WFP_IRQ_ENB_DFEE);
368} 464}
369 465
466static unsigned int wpf_max_width(struct vsp1_entity *entity,
467 struct vsp1_pipeline *pipe)
468{
469 struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
470
471 return wpf->flip.rotate ? 256 : wpf->max_width;
472}
473
370static const struct vsp1_entity_operations wpf_entity_ops = { 474static const struct vsp1_entity_operations wpf_entity_ops = {
371 .destroy = vsp1_wpf_destroy, 475 .destroy = vsp1_wpf_destroy,
372 .configure = wpf_configure, 476 .configure = wpf_configure,
477 .max_width = wpf_max_width,
373}; 478};
374 479
375/* ----------------------------------------------------------------------------- 480/* -----------------------------------------------------------------------------