diff options
author | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2016-07-23 07:59:19 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2016-07-23 07:59:19 -0300 |
commit | c278256d05a2fc75b427fa6a5dc0024faa93465d (patch) | |
tree | 2c09c6c65a4b6c597a568ec2425adb75eff7d5d5 /drivers/media/platform/vsp1/vsp1_wpf.c | |
parent | 7e5b7d1b3a8facd4dc1ddb5d9ec53c0687d13de7 (diff) | |
parent | 009a620848218d521f008141c62f56bf19294dd9 (diff) |
Merge branch 'patchwork' into topic/docs-next
* patchwork: (1492 commits)
[media] cec: always check all_device_types and features
[media] cec: poll should check if there is room in the tx queue
[media] vivid: support monitor all mode
[media] cec: fix test for unconfigured adapter in main message loop
[media] cec: limit the size of the transmit queue
[media] cec: zero unused msg part after msg->len
[media] cec: don't set fh to NULL in CEC_TRANSMIT
[media] cec: clear all status fields before transmit and always fill in sequence
[media] cec: CEC_RECEIVE overwrote the timeout field
[media] cxd2841er: Reading SNR for DVB-C added
[media] cxd2841er: Reading BER and UCB for DVB-C added
[media] cxd2841er: fix switch-case for DVB-C
[media] cxd2841er: fix signal strength scale for ISDB-T
[media] cxd2841er: adjust the dB scale for DVB-C
[media] cxd2841er: provide signal strength for DVB-C
[media] cxd2841er: fix BER report via DVBv5 stats API
[media] mb86a20s: apply mask to val after checking for read failure
[media] airspy: fix error logic during device register
[media] s5p-cec/TODO: add TODO item
[media] cec/TODO: drop comment about sphinx documentation
...
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/platform/vsp1/vsp1_wpf.c')
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_wpf.c | 161 |
1 files changed, 151 insertions, 10 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 6c91eaa35e75..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, } /* ----------------------------------------------------------------------------- + * 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 */ @@ -62,11 +153,11 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) * V4L2 Subdevice Operations */ -static struct v4l2_subdev_video_ops wpf_video_ops = { +static const struct v4l2_subdev_video_ops wpf_video_ops = { .s_stream = wpf_s_stream, }; -static struct v4l2_subdev_ops wpf_ops = { +static const struct v4l2_subdev_ops wpf_ops = { .video = &wpf_video_ops, .pad = &vsp1_rwpf_pad_ops, }; @@ -85,15 +176,37 @@ 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, struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl) + struct vsp1_dl_list *dl, bool full) { struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); struct vsp1_device *vsp1 = wpf->entity.vsp1; @@ -104,6 +217,26 @@ static void wpf_configure(struct vsp1_entity *entity, u32 outfmt = 0; u32 srcrpf = 0; + if (!full) { + 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; + } + /* Cropping */ crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config); @@ -143,13 +276,18 @@ 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) outfmt |= VI6_WPF_OUTFMT_CSC; - outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT; - vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt); + wpf->outfmt = outfmt; vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index), VI6_DPR_WPF_FPORCH_FP_WPFN); @@ -216,7 +354,8 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) wpf->entity.index = index; sprintf(name, "wpf.%u", index); - ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops); + ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); if (ret < 0) return ERR_PTR(ret); @@ -228,13 +367,15 @@ 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); goto error; } + v4l2_ctrl_handler_setup(&wpf->ctrls); + return wpf; error: |