aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2016-05-26 04:14:22 -0400
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2016-06-28 11:42:43 -0400
commit894dde5c5d1c6d33c4bd3d4384c6cf0aff3f8015 (patch)
tree7ff18ad4a641508512aefd84f13547cdecac071a
parentd05a331029d31836053a934365056616b0142898 (diff)
[media] v4l: vsp1: wpf: Add flipping support
Vertical flipping is available on both Gen2 and Gen3, while horizontal flipping is only available on Gen3. 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.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c16
-rw-r--r--drivers/media/platform/vsp1/vsp1_regs.h7
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.c4
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.h11
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c145
7 files changed, 170 insertions, 17 deletions
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 8713a437076d..06a2ec7e5ad4 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -48,6 +48,8 @@ struct vsp1_uds;
48#define VSP1_HAS_SRU (1 << 2) 48#define VSP1_HAS_SRU (1 << 2)
49#define VSP1_HAS_BRU (1 << 3) 49#define VSP1_HAS_BRU (1 << 3)
50#define VSP1_HAS_CLU (1 << 4) 50#define VSP1_HAS_CLU (1 << 4)
51#define VSP1_HAS_WPF_VFLIP (1 << 5)
52#define VSP1_HAS_WPF_HFLIP (1 << 6)
51 53
52struct vsp1_device_info { 54struct vsp1_device_info {
53 u32 version; 55 u32 version;
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 769b19edb146..e1377ffe3d68 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -563,7 +563,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
563 .version = VI6_IP_VERSION_MODEL_VSPS_H2, 563 .version = VI6_IP_VERSION_MODEL_VSPS_H2,
564 .gen = 2, 564 .gen = 2,
565 .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT 565 .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
566 | VSP1_HAS_SRU, 566 | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
567 .rpf_count = 5, 567 .rpf_count = 5,
568 .uds_count = 3, 568 .uds_count = 3,
569 .wpf_count = 4, 569 .wpf_count = 4,
@@ -572,7 +572,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
572 }, { 572 }, {
573 .version = VI6_IP_VERSION_MODEL_VSPR_H2, 573 .version = VI6_IP_VERSION_MODEL_VSPR_H2,
574 .gen = 2, 574 .gen = 2,
575 .features = VSP1_HAS_BRU | VSP1_HAS_SRU, 575 .features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
576 .rpf_count = 5, 576 .rpf_count = 5,
577 .uds_count = 3, 577 .uds_count = 3,
578 .wpf_count = 4, 578 .wpf_count = 4,
@@ -591,7 +591,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
591 .version = VI6_IP_VERSION_MODEL_VSPS_M2, 591 .version = VI6_IP_VERSION_MODEL_VSPS_M2,
592 .gen = 2, 592 .gen = 2,
593 .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT 593 .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
594 | VSP1_HAS_SRU, 594 | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
595 .rpf_count = 5, 595 .rpf_count = 5,
596 .uds_count = 1, 596 .uds_count = 1,
597 .wpf_count = 4, 597 .wpf_count = 4,
@@ -600,7 +600,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
600 }, { 600 }, {
601 .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, 601 .version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
602 .gen = 3, 602 .gen = 3,
603 .features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU, 603 .features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU
604 | VSP1_HAS_WPF_HFLIP | VSP1_HAS_WPF_VFLIP,
604 .rpf_count = 1, 605 .rpf_count = 1,
605 .uds_count = 1, 606 .uds_count = 1,
606 .wpf_count = 1, 607 .wpf_count = 1,
@@ -608,7 +609,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
608 }, { 609 }, {
609 .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3, 610 .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
610 .gen = 3, 611 .gen = 3,
611 .features = VSP1_HAS_BRU, 612 .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP,
612 .rpf_count = 5, 613 .rpf_count = 5,
613 .wpf_count = 1, 614 .wpf_count = 1,
614 .num_bru_inputs = 5, 615 .num_bru_inputs = 5,
@@ -616,7 +617,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
616 }, { 617 }, {
617 .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, 618 .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
618 .gen = 3, 619 .gen = 3,
619 .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT, 620 .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
621 | VSP1_HAS_WPF_VFLIP,
620 .rpf_count = 5, 622 .rpf_count = 5,
621 .wpf_count = 1, 623 .wpf_count = 1,
622 .num_bru_inputs = 5, 624 .num_bru_inputs = 5,
@@ -624,7 +626,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
624 }, { 626 }, {
625 .version = VI6_IP_VERSION_MODEL_VSPD_GEN3, 627 .version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
626 .gen = 3, 628 .gen = 3,
627 .features = VSP1_HAS_BRU | VSP1_HAS_LIF, 629 .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_WPF_VFLIP,
628 .rpf_count = 5, 630 .rpf_count = 5,
629 .wpf_count = 2, 631 .wpf_count = 2,
630 .num_bru_inputs = 5, 632 .num_bru_inputs = 5,
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index dea0bc471108..3b03007ba625 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -255,6 +255,8 @@
255#define VI6_WPF_OUTFMT_PDV_MASK (0xff << 24) 255#define VI6_WPF_OUTFMT_PDV_MASK (0xff << 24)
256#define VI6_WPF_OUTFMT_PDV_SHIFT 24 256#define VI6_WPF_OUTFMT_PDV_SHIFT 24
257#define VI6_WPF_OUTFMT_PXA (1 << 23) 257#define VI6_WPF_OUTFMT_PXA (1 << 23)
258#define VI6_WPF_OUTFMT_ROT (1 << 18)
259#define VI6_WPF_OUTFMT_HFLP (1 << 17)
258#define VI6_WPF_OUTFMT_FLP (1 << 16) 260#define VI6_WPF_OUTFMT_FLP (1 << 16)
259#define VI6_WPF_OUTFMT_SPYCS (1 << 15) 261#define VI6_WPF_OUTFMT_SPYCS (1 << 15)
260#define VI6_WPF_OUTFMT_SPUVS (1 << 14) 262#define VI6_WPF_OUTFMT_SPUVS (1 << 14)
@@ -289,6 +291,11 @@
289#define VI6_WPF_RNDCTRL_CLMD_EXT (2 << 12) 291#define VI6_WPF_RNDCTRL_CLMD_EXT (2 << 12)
290#define VI6_WPF_RNDCTRL_CLMD_MASK (3 << 12) 292#define VI6_WPF_RNDCTRL_CLMD_MASK (3 << 12)
291 293
294#define VI6_WPF_ROT_CTRL 0x1018
295#define VI6_WPF_ROT_CTRL_LN16 (1 << 17)
296#define VI6_WPF_ROT_CTRL_LMEM_WD_MASK (0x1fff << 0)
297#define VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT 0
298
292#define VI6_WPF_DSTM_STRIDE_Y 0x101c 299#define VI6_WPF_DSTM_STRIDE_Y 0x101c
293#define VI6_WPF_DSTM_STRIDE_C 0x1020 300#define VI6_WPF_DSTM_STRIDE_C 0x1020
294#define VI6_WPF_DSTM_ADDR_Y 0x1024 301#define VI6_WPF_DSTM_ADDR_Y 0x1024
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 4258c7208877..388838913205 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -247,7 +247,7 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
247 return ERR_PTR(ret); 247 return ERR_PTR(ret);
248 248
249 /* Initialize the control handler. */ 249 /* Initialize the control handler. */
250 ret = vsp1_rwpf_init_ctrls(rpf); 250 ret = vsp1_rwpf_init_ctrls(rpf, 0);
251 if (ret < 0) { 251 if (ret < 0) {
252 dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n", 252 dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
253 index); 253 index);
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index cd3562d1d9cf..8d461b375e91 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -241,9 +241,9 @@ static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = {
241 .s_ctrl = vsp1_rwpf_s_ctrl, 241 .s_ctrl = vsp1_rwpf_s_ctrl,
242}; 242};
243 243
244int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf) 244int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols)
245{ 245{
246 v4l2_ctrl_handler_init(&rwpf->ctrls, 1); 246 v4l2_ctrl_handler_init(&rwpf->ctrls, ncontrols + 1);
247 v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops, 247 v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops,
248 V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); 248 V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
249 249
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 801cacc12e07..cb20484e80da 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -13,6 +13,8 @@
13#ifndef __VSP1_RWPF_H__ 13#ifndef __VSP1_RWPF_H__
14#define __VSP1_RWPF_H__ 14#define __VSP1_RWPF_H__
15 15
16#include <linux/spinlock.h>
17
16#include <media/media-entity.h> 18#include <media/media-entity.h>
17#include <media/v4l2-ctrls.h> 19#include <media/v4l2-ctrls.h>
18#include <media/v4l2-subdev.h> 20#include <media/v4l2-subdev.h>
@@ -52,6 +54,13 @@ struct vsp1_rwpf {
52 u32 mult_alpha; 54 u32 mult_alpha;
53 u32 outfmt; 55 u32 outfmt;
54 56
57 struct {
58 spinlock_t lock;
59 struct v4l2_ctrl *ctrls[2];
60 unsigned int pending;
61 unsigned int active;
62 } flip;
63
55 unsigned int offsets[2]; 64 unsigned int offsets[2];
56 struct vsp1_rwpf_memory mem; 65 struct vsp1_rwpf_memory mem;
57 66
@@ -71,7 +80,7 @@ static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity)
71struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); 80struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
72struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); 81struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
73 82
74int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf); 83int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols);
75 84
76extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops; 85extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops;
77 86
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 9385bc703dcd..31983169c24a 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -37,6 +37,97 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf,
37} 37}
38 38
39/* ----------------------------------------------------------------------------- 39/* -----------------------------------------------------------------------------
40 * Controls
41 */
42
43enum wpf_flip_ctrl {
44 WPF_CTRL_VFLIP = 0,
45 WPF_CTRL_HFLIP = 1,
46 WPF_CTRL_MAX,
47};
48
49static int vsp1_wpf_s_ctrl(struct v4l2_ctrl *ctrl)
50{
51 struct vsp1_rwpf *wpf =
52 container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
53 unsigned int i;
54 u32 flip = 0;
55
56 switch (ctrl->id) {
57 case V4L2_CID_HFLIP:
58 case V4L2_CID_VFLIP:
59 for (i = 0; i < WPF_CTRL_MAX; ++i) {
60 if (wpf->flip.ctrls[i])
61 flip |= wpf->flip.ctrls[i]->val ? BIT(i) : 0;
62 }
63
64 spin_lock_irq(&wpf->flip.lock);
65 wpf->flip.pending = flip;
66 spin_unlock_irq(&wpf->flip.lock);
67 break;
68
69 default:
70 return -EINVAL;
71 }
72
73 return 0;
74}
75
76static const struct v4l2_ctrl_ops vsp1_wpf_ctrl_ops = {
77 .s_ctrl = vsp1_wpf_s_ctrl,
78};
79
80static int wpf_init_controls(struct vsp1_rwpf *wpf)
81{
82 struct vsp1_device *vsp1 = wpf->entity.vsp1;
83 unsigned int num_flip_ctrls;
84
85 spin_lock_init(&wpf->flip.lock);
86
87 if (wpf->entity.index != 0) {
88 /* Only WPF0 supports flipping. */
89 num_flip_ctrls = 0;
90 } else if (vsp1->info->features & VSP1_HAS_WPF_HFLIP) {
91 /* When horizontal flip is supported the WPF implements two
92 * controls (horizontal flip and vertical flip).
93 */
94 num_flip_ctrls = 2;
95 } else if (vsp1->info->features & VSP1_HAS_WPF_VFLIP) {
96 /* When only vertical flip is supported the WPF implements a
97 * single control (vertical flip).
98 */
99 num_flip_ctrls = 1;
100 } else {
101 /* Otherwise flipping is not supported. */
102 num_flip_ctrls = 0;
103 }
104
105 vsp1_rwpf_init_ctrls(wpf, num_flip_ctrls);
106
107 if (num_flip_ctrls >= 1) {
108 wpf->flip.ctrls[WPF_CTRL_VFLIP] =
109 v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
110 V4L2_CID_VFLIP, 0, 1, 1, 0);
111 }
112
113 if (num_flip_ctrls == 2) {
114 wpf->flip.ctrls[WPF_CTRL_HFLIP] =
115 v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
116 V4L2_CID_HFLIP, 0, 1, 1, 0);
117
118 v4l2_ctrl_cluster(2, wpf->flip.ctrls);
119 }
120
121 if (wpf->ctrls.error) {
122 dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
123 wpf->entity.index);
124 return wpf->ctrls.error;
125 }
126
127 return 0;
128}
129
130/* -----------------------------------------------------------------------------
40 * V4L2 Subdevice Core Operations 131 * V4L2 Subdevice Core Operations
41 */ 132 */
42 133
@@ -85,10 +176,32 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity)
85static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) 176static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
86{ 177{
87 struct vsp1_rwpf *wpf = entity_to_rwpf(entity); 178 struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
179 const struct v4l2_pix_format_mplane *format = &wpf->format;
180 struct vsp1_rwpf_memory mem = wpf->mem;
181 unsigned int flip = wpf->flip.active;
182 unsigned int offset;
183
184 /* Update the memory offsets based on flipping configuration. The
185 * destination addresses point to the locations where the VSP starts
186 * writing to memory, which can be different corners of the image
187 * depending on vertical flipping. Horizontal flipping is handled
188 * through a line buffer and doesn't modify the start address.
189 */
190 if (flip & BIT(WPF_CTRL_VFLIP)) {
191 mem.addr[0] += (format->height - 1)
192 * format->plane_fmt[0].bytesperline;
193
194 if (format->num_planes > 1) {
195 offset = (format->height / wpf->fmtinfo->vsub - 1)
196 * format->plane_fmt[1].bytesperline;
197 mem.addr[1] += offset;
198 mem.addr[2] += offset;
199 }
200 }
88 201
89 vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]); 202 vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]);
90 vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]); 203 vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]);
91 vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]); 204 vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]);
92} 205}
93 206
94static void wpf_configure(struct vsp1_entity *entity, 207static void wpf_configure(struct vsp1_entity *entity,
@@ -105,8 +218,22 @@ static void wpf_configure(struct vsp1_entity *entity,
105 u32 srcrpf = 0; 218 u32 srcrpf = 0;
106 219
107 if (!full) { 220 if (!full) {
108 vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, wpf->outfmt | 221 const unsigned int mask = BIT(WPF_CTRL_VFLIP)
109 (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT)); 222 | BIT(WPF_CTRL_HFLIP);
223
224 spin_lock(&wpf->flip.lock);
225 wpf->flip.active = (wpf->flip.active & ~mask)
226 | (wpf->flip.pending & mask);
227 spin_unlock(&wpf->flip.lock);
228
229 outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt;
230
231 if (wpf->flip.active & BIT(WPF_CTRL_VFLIP))
232 outfmt |= VI6_WPF_OUTFMT_FLP;
233 if (wpf->flip.active & BIT(WPF_CTRL_HFLIP))
234 outfmt |= VI6_WPF_OUTFMT_HFLP;
235
236 vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt);
110 return; 237 return;
111 } 238 }
112 239
@@ -149,6 +276,12 @@ static void wpf_configure(struct vsp1_entity *entity,
149 format->plane_fmt[1].bytesperline); 276 format->plane_fmt[1].bytesperline);
150 277
151 vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap); 278 vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap);
279
280 if (vsp1->info->features & VSP1_HAS_WPF_HFLIP &&
281 wpf->entity.index == 0)
282 vsp1_wpf_write(wpf, dl, VI6_WPF_ROT_CTRL,
283 VI6_WPF_ROT_CTRL_LN16 |
284 (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT));
152 } 285 }
153 286
154 if (sink_format->code != source_format->code) 287 if (sink_format->code != source_format->code)
@@ -234,7 +367,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
234 } 367 }
235 368
236 /* Initialize the control handler. */ 369 /* Initialize the control handler. */
237 ret = vsp1_rwpf_init_ctrls(wpf); 370 ret = wpf_init_controls(wpf);
238 if (ret < 0) { 371 if (ret < 0) {
239 dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n", 372 dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
240 index); 373 index);