mirror of https://gitee.com/openkylin/linux.git
[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>
This commit is contained in:
parent
d05a331029
commit
894dde5c5d
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -255,6 +255,8 @@
|
|||
#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)
|
||||
|
@ -289,6 +291,11 @@
|
|||
#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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
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]);
|
||||
/* 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, 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);
|
||||
|
|
Loading…
Reference in New Issue