[media] v4l: vsp1: wpf: Add flipping support
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Thu, 26 May 2016 08:14:22 +0000 (05:14 -0300)
committerMauro Carvalho Chehab <mchehab@s-opensource.com>
Tue, 28 Jun 2016 15:42:43 +0000 (12:42 -0300)
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>
drivers/media/platform/vsp1/vsp1.h
drivers/media/platform/vsp1/vsp1_drv.c
drivers/media/platform/vsp1/vsp1_regs.h
drivers/media/platform/vsp1/vsp1_rpf.c
drivers/media/platform/vsp1/vsp1_rwpf.c
drivers/media/platform/vsp1/vsp1_rwpf.h
drivers/media/platform/vsp1/vsp1_wpf.c

index 8713a437076d3e84c4712b8df48c8f30188649c7..06a2ec7e5ad401070eb018d1bf6af9eebf22a73a 100644 (file)
@@ -48,6 +48,8 @@ struct vsp1_uds;
 #define VSP1_HAS_SRU           (1 << 2)
 #define VSP1_HAS_BRU           (1 << 3)
 #define VSP1_HAS_CLU           (1 << 4)
+#define VSP1_HAS_WPF_VFLIP     (1 << 5)
+#define VSP1_HAS_WPF_HFLIP     (1 << 6)
 
 struct vsp1_device_info {
        u32 version;
index 769b19edb146f8b17392cbcebf3189a35093c232..e1377ffe3d685e465d02e5c6754d1626506b22fc 100644 (file)
@@ -563,7 +563,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
                .version = VI6_IP_VERSION_MODEL_VSPS_H2,
                .gen = 2,
                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
-                         | VSP1_HAS_SRU,
+                         | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
                .rpf_count = 5,
                .uds_count = 3,
                .wpf_count = 4,
@@ -572,7 +572,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPR_H2,
                .gen = 2,
-               .features = VSP1_HAS_BRU | VSP1_HAS_SRU,
+               .features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
                .rpf_count = 5,
                .uds_count = 3,
                .wpf_count = 4,
@@ -591,7 +591,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
                .version = VI6_IP_VERSION_MODEL_VSPS_M2,
                .gen = 2,
                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
-                         | VSP1_HAS_SRU,
+                         | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
                .rpf_count = 5,
                .uds_count = 1,
                .wpf_count = 4,
@@ -600,7 +600,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
                .gen = 3,
-               .features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU,
+               .features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU
+                         | VSP1_HAS_WPF_HFLIP | VSP1_HAS_WPF_VFLIP,
                .rpf_count = 1,
                .uds_count = 1,
                .wpf_count = 1,
@@ -608,7 +609,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
                .gen = 3,
-               .features = VSP1_HAS_BRU,
+               .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP,
                .rpf_count = 5,
                .wpf_count = 1,
                .num_bru_inputs = 5,
@@ -616,7 +617,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
                .gen = 3,
-               .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT,
+               .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
+                         | VSP1_HAS_WPF_VFLIP,
                .rpf_count = 5,
                .wpf_count = 1,
                .num_bru_inputs = 5,
@@ -624,7 +626,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
        }, {
                .version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
                .gen = 3,
-               .features = VSP1_HAS_BRU | VSP1_HAS_LIF,
+               .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_WPF_VFLIP,
                .rpf_count = 5,
                .wpf_count = 2,
                .num_bru_inputs = 5,
index dea0bc471108d0935050ad2806bfd1fbee1ae91c..3b03007ba625e91ab576ec45a123eb7aca12d108 100644 (file)
 #define VI6_WPF_OUTFMT_PDV_MASK                (0xff << 24)
 #define VI6_WPF_OUTFMT_PDV_SHIFT       24
 #define VI6_WPF_OUTFMT_PXA             (1 << 23)
+#define VI6_WPF_OUTFMT_ROT             (1 << 18)
+#define VI6_WPF_OUTFMT_HFLP            (1 << 17)
 #define VI6_WPF_OUTFMT_FLP             (1 << 16)
 #define VI6_WPF_OUTFMT_SPYCS           (1 << 15)
 #define VI6_WPF_OUTFMT_SPUVS           (1 << 14)
 #define VI6_WPF_RNDCTRL_CLMD_EXT       (2 << 12)
 #define VI6_WPF_RNDCTRL_CLMD_MASK      (3 << 12)
 
+#define VI6_WPF_ROT_CTRL               0x1018
+#define VI6_WPF_ROT_CTRL_LN16          (1 << 17)
+#define VI6_WPF_ROT_CTRL_LMEM_WD_MASK  (0x1fff << 0)
+#define VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT 0
+
 #define VI6_WPF_DSTM_STRIDE_Y          0x101c
 #define VI6_WPF_DSTM_STRIDE_C          0x1020
 #define VI6_WPF_DSTM_ADDR_Y            0x1024
index 4258c7208877c8b954cdf72867ef89c90a8a3190..38883891320518c4352ce24645d5da5f9184017a 100644 (file)
@@ -247,7 +247,7 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
                return ERR_PTR(ret);
 
        /* Initialize the control handler. */
-       ret = vsp1_rwpf_init_ctrls(rpf);
+       ret = vsp1_rwpf_init_ctrls(rpf, 0);
        if (ret < 0) {
                dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
                        index);
index cd3562d1d9cf732600ffc872725f42e839809323..8d461b375e91a101c85ae1dba04a7c7075e5e11d 100644 (file)
@@ -241,9 +241,9 @@ static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = {
        .s_ctrl = vsp1_rwpf_s_ctrl,
 };
 
-int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf)
+int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols)
 {
-       v4l2_ctrl_handler_init(&rwpf->ctrls, 1);
+       v4l2_ctrl_handler_init(&rwpf->ctrls, ncontrols + 1);
        v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops,
                          V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
 
index 801cacc12e073f2785ddead0be315145d283394d..cb20484e80da8f0f08733355309cb8c05dbb089e 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef __VSP1_RWPF_H__
 #define __VSP1_RWPF_H__
 
+#include <linux/spinlock.h>
+
 #include <media/media-entity.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
@@ -52,6 +54,13 @@ struct vsp1_rwpf {
        u32 mult_alpha;
        u32 outfmt;
 
+       struct {
+               spinlock_t lock;
+               struct v4l2_ctrl *ctrls[2];
+               unsigned int pending;
+               unsigned int active;
+       } flip;
+
        unsigned int offsets[2];
        struct vsp1_rwpf_memory mem;
 
@@ -71,7 +80,7 @@ static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity)
 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
 
-int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf);
+int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols);
 
 extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops;
 
index 9385bc703dcd54010aa8a53c3a589bbc95ed99ba..31983169c24a03bc50cdddcbe8e5c300313b2c23 100644 (file)
@@ -36,6 +36,97 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf,
        vsp1_dl_list_write(dl, reg + wpf->entity.index * VI6_WPF_OFFSET, data);
 }
 
+/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+enum wpf_flip_ctrl {
+       WPF_CTRL_VFLIP = 0,
+       WPF_CTRL_HFLIP = 1,
+       WPF_CTRL_MAX,
+};
+
+static int vsp1_wpf_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vsp1_rwpf *wpf =
+               container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
+       unsigned int i;
+       u32 flip = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_HFLIP:
+       case V4L2_CID_VFLIP:
+               for (i = 0; i < WPF_CTRL_MAX; ++i) {
+                       if (wpf->flip.ctrls[i])
+                               flip |= wpf->flip.ctrls[i]->val ? BIT(i) : 0;
+               }
+
+               spin_lock_irq(&wpf->flip.lock);
+               wpf->flip.pending = flip;
+               spin_unlock_irq(&wpf->flip.lock);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vsp1_wpf_ctrl_ops = {
+       .s_ctrl = vsp1_wpf_s_ctrl,
+};
+
+static int wpf_init_controls(struct vsp1_rwpf *wpf)
+{
+       struct vsp1_device *vsp1 = wpf->entity.vsp1;
+       unsigned int num_flip_ctrls;
+
+       spin_lock_init(&wpf->flip.lock);
+
+       if (wpf->entity.index != 0) {
+               /* Only WPF0 supports flipping. */
+               num_flip_ctrls = 0;
+       } else if (vsp1->info->features & VSP1_HAS_WPF_HFLIP) {
+               /* When horizontal flip is supported the WPF implements two
+                * controls (horizontal flip and vertical flip).
+                */
+               num_flip_ctrls = 2;
+       } else if (vsp1->info->features & VSP1_HAS_WPF_VFLIP) {
+               /* When only vertical flip is supported the WPF implements a
+                * single control (vertical flip).
+                */
+               num_flip_ctrls = 1;
+       } else {
+               /* Otherwise flipping is not supported. */
+               num_flip_ctrls = 0;
+       }
+
+       vsp1_rwpf_init_ctrls(wpf, num_flip_ctrls);
+
+       if (num_flip_ctrls >= 1) {
+               wpf->flip.ctrls[WPF_CTRL_VFLIP] =
+                       v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
+                                         V4L2_CID_VFLIP, 0, 1, 1, 0);
+       }
+
+       if (num_flip_ctrls == 2) {
+               wpf->flip.ctrls[WPF_CTRL_HFLIP] =
+                       v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
+                                         V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+               v4l2_ctrl_cluster(2, wpf->flip.ctrls);
+       }
+
+       if (wpf->ctrls.error) {
+               dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
+                       wpf->entity.index);
+               return wpf->ctrls.error;
+       }
+
+       return 0;
+}
+
 /* -----------------------------------------------------------------------------
  * V4L2 Subdevice Core Operations
  */
@@ -85,10 +176,32 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity)
 static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
 {
        struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
+       const struct v4l2_pix_format_mplane *format = &wpf->format;
+       struct vsp1_rwpf_memory mem = wpf->mem;
+       unsigned int flip = wpf->flip.active;
+       unsigned int offset;
+
+       /* Update the memory offsets based on flipping configuration. The
+        * destination addresses point to the locations where the VSP starts
+        * writing to memory, which can be different corners of the image
+        * depending on vertical flipping. Horizontal flipping is handled
+        * through a line buffer and doesn't modify the start address.
+        */
+       if (flip & BIT(WPF_CTRL_VFLIP)) {
+               mem.addr[0] += (format->height - 1)
+                            * format->plane_fmt[0].bytesperline;
+
+               if (format->num_planes > 1) {
+                       offset = (format->height / wpf->fmtinfo->vsub - 1)
+                              * format->plane_fmt[1].bytesperline;
+                       mem.addr[1] += offset;
+                       mem.addr[2] += offset;
+               }
+       }
 
-       vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
-       vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
-       vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
+       vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]);
+       vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]);
+       vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]);
 }
 
 static void wpf_configure(struct vsp1_entity *entity,
@@ -105,8 +218,22 @@ static void wpf_configure(struct vsp1_entity *entity,
        u32 srcrpf = 0;
 
        if (!full) {
-               vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, wpf->outfmt |
-                              (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT));
+               const unsigned int mask = BIT(WPF_CTRL_VFLIP)
+                                       | BIT(WPF_CTRL_HFLIP);
+
+               spin_lock(&wpf->flip.lock);
+               wpf->flip.active = (wpf->flip.active & ~mask)
+                                | (wpf->flip.pending & mask);
+               spin_unlock(&wpf->flip.lock);
+
+               outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt;
+
+               if (wpf->flip.active & BIT(WPF_CTRL_VFLIP))
+                       outfmt |= VI6_WPF_OUTFMT_FLP;
+               if (wpf->flip.active & BIT(WPF_CTRL_HFLIP))
+                       outfmt |= VI6_WPF_OUTFMT_HFLP;
+
+               vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt);
                return;
        }
 
@@ -149,6 +276,12 @@ static void wpf_configure(struct vsp1_entity *entity,
                                       format->plane_fmt[1].bytesperline);
 
                vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap);
+
+               if (vsp1->info->features & VSP1_HAS_WPF_HFLIP &&
+                   wpf->entity.index == 0)
+                       vsp1_wpf_write(wpf, dl, VI6_WPF_ROT_CTRL,
+                                      VI6_WPF_ROT_CTRL_LN16 |
+                                      (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT));
        }
 
        if (sink_format->code != source_format->code)
@@ -234,7 +367,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
        }
 
        /* Initialize the control handler. */
-       ret = vsp1_rwpf_init_ctrls(wpf);
+       ret = wpf_init_controls(wpf);
        if (ret < 0) {
                dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
                        index);