diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-18 03:55:23 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-18 03:55:23 +0300 |
commit | e7345f92c27af003f219ad026d0e629a50b41e5c (patch) | |
tree | e4a68d230e460d25e340128e60a7e7efe4165244 /drivers | |
parent | 6ab8ad31601f29470eb895fd95e5c963e125aa1b (diff) | |
parent | 6f51fdfd8229d5358c2d6e272cf73478866e8ddc (diff) | |
download | linux-e7345f92c27af003f219ad026d0e629a50b41e5c.tar.xz |
Merge tag 'media/v5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- a new sensor driver for ov5675
- a new platform driver for Allwinner A10 sensor interface
- some new remote controller keymaps
- some cosmetic changes at V4L2 core in order to avoid #ifdefs and to
merge two core modules into one
- removal of bcm2048 radio driver from staging
- removal of davinci_vpfe video driver from staging
- regression fix since Kernel 5.1 at the legacy VideoBuffer version 1
core
- added some documentation for remote controller protocols
- pixel format documentation was split on two files
- lots of other driver improvements and cleanups
* tag 'media/v5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (321 commits)
media: videobuf-core.c: poll_wait needs a non-NULL buf pointer
media: sun4i: Make sun4i_csi_formats static
media: imx: remove unused including <linux/version.h>
media: stm32-dcmi: Delete an unnecessary of_node_put() call in dcmi_probe()
media: pvrusb2: qctrl.flag will be uninitlaized if cx2341x_ctrl_query() returns error code
media: em28xx: Fix exception handling in em28xx_alloc_urbs()
media: don't do a 31 bit shift on a signed int
media: use the BIT() macro
media: ov9650: add a sanity check
media: aspeed-video: address a protential usage of an unitialized var
media: vicodec: make life easier for static analyzers
media: remove include stdarg.h from some drivers
v4l2-core: fix coding style for the two new c files
media: v4l2-core: Remove BUG() from i2c and spi helpers
media: v4l2-core: introduce a helper to unregister a i2c subdev
media: v4l2-core: introduce a helper to unregister a spi subdev
media: v4l2-core: move i2c helpers out of v4l2-common.c
media: v4l2-core: move spi helpers out of v4l2-common.c
media: v4l2-core: Module re-organization
media: usbvision: Remove dead code
...
Diffstat (limited to 'drivers')
419 files changed, 12434 insertions, 22461 deletions
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index 00cb1ba2d364..3fd3e862269b 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -186,7 +186,7 @@ static const struct v4l2_pix_format sur40_pix_format[] = { .width = SENSOR_RES_X / 2, .height = SENSOR_RES_Y / 2, .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, + .colorspace = V4L2_COLORSPACE_RAW, .bytesperline = SENSOR_RES_X / 2, .sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2), }, @@ -195,7 +195,7 @@ static const struct v4l2_pix_format sur40_pix_format[] = { .width = SENSOR_RES_X / 2, .height = SENSOR_RES_Y / 2, .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, + .colorspace = V4L2_COLORSPACE_RAW, .bytesperline = SENSOR_RES_X / 2, .sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2), } diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 21cd9c02960b..b36a41332867 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -190,7 +190,7 @@ config MEDIA_SUBDRV_AUTOSELECT depends on HAS_IOMEM select I2C select I2C_MUX - default y + default y if !EMBEDDED help By default, a media driver auto-selects all possible ancillary devices such as tuners, sensors, video encoders/decoders and @@ -207,6 +207,11 @@ config MEDIA_SUBDRV_AUTOSELECT If unsure say Y. +config MEDIA_HIDE_ANCILLARY_SUBDRV + bool + depends on MEDIA_SUBDRV_AUTOSELECT && !COMPILE_TEST && !EXPERT + default y + config MEDIA_ATTACH bool depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 451c61bde4d4..5ef7daeb8cbd 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -1614,6 +1614,9 @@ EXPORT_SYMBOL_GPL(cec_s_phys_addr_from_edid); void cec_s_conn_info(struct cec_adapter *adap, const struct cec_connector_info *conn_info) { + if (IS_ERR_OR_NULL(adap)) + return; + if (!(adap->capabilities & CEC_CAP_CONNECTOR_INFO)) return; diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index 52a867bde15f..4d82a5522072 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -218,6 +218,8 @@ void cec_notifier_unregister(struct cec_notifier *n) mutex_lock(&n->lock); n->callback = NULL; + n->cec_adap->notifier = NULL; + n->cec_adap = NULL; mutex_unlock(&n->lock); cec_notifier_put(n); } diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 4c399a42e874..d16122039b0c 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -20,62 +20,52 @@ MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: /* format descriptions for capture and preview */ static struct saa7146_format formats[] = { { - .name = "RGB-8 (3-3-2)", .pixelformat = V4L2_PIX_FMT_RGB332, .trans = RGB08_COMPOSED, .depth = 8, .flags = 0, }, { - .name = "RGB-16 (5/B-6/G-5/R)", .pixelformat = V4L2_PIX_FMT_RGB565, .trans = RGB16_COMPOSED, .depth = 16, .flags = 0, }, { - .name = "RGB-24 (B-G-R)", .pixelformat = V4L2_PIX_FMT_BGR24, .trans = RGB24_COMPOSED, .depth = 24, .flags = 0, }, { - .name = "RGB-32 (B-G-R)", .pixelformat = V4L2_PIX_FMT_BGR32, .trans = RGB32_COMPOSED, .depth = 32, .flags = 0, }, { - .name = "RGB-32 (R-G-B)", .pixelformat = V4L2_PIX_FMT_RGB32, .trans = RGB32_COMPOSED, .depth = 32, .flags = 0, .swap = 0x2, }, { - .name = "Greyscale-8", .pixelformat = V4L2_PIX_FMT_GREY, .trans = Y8, .depth = 8, .flags = 0, }, { - .name = "YUV 4:2:2 planar (Y-Cb-Cr)", .pixelformat = V4L2_PIX_FMT_YUV422P, .trans = YUV422_DECOMPOSED, .depth = 16, .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, }, { - .name = "YVU 4:2:0 planar (Y-Cb-Cr)", .pixelformat = V4L2_PIX_FMT_YVU420, .trans = YUV420_DECOMPOSED, .depth = 12, .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, }, { - .name = "YUV 4:2:0 planar (Y-Cb-Cr)", .pixelformat = V4L2_PIX_FMT_YUV420, .trans = YUV420_DECOMPOSED, .depth = 12, .flags = FORMAT_IS_PLANAR, }, { - .name = "YUV 4:2:2 (U-Y-V-Y)", .pixelformat = V4L2_PIX_FMT_UYVY, .trans = YUV422_COMPOSED, .depth = 16, @@ -147,10 +137,10 @@ int saa7146_start_preview(struct saa7146_fh *fh) } vv->ov.win = fmt.fmt.win; - DEB_D("%dx%d+%d+%d %s field=%s\n", + DEB_D("%dx%d+%d+%d 0x%08x field=%s\n", vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.w.left, vv->ov.win.w.top, - vv->ov_fmt->name, v4l2_field_names[vv->ov.win.field]); + vv->ov_fmt->pixelformat, v4l2_field_names[vv->ov.win.field]); if (0 != (ret = saa7146_enable_overlay(fh))) { DEB_D("enabling overlay failed: %d\n", ret); @@ -515,8 +505,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtd { if (f->index >= ARRAY_SIZE(formats)) return -EINVAL; - strscpy((char *)f->description, formats[f->index].name, - sizeof(f->description)); f->pixelformat = formats[f->index].pixelformat; return 0; } diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 07e0629af8ed..50f1e0b28b25 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -217,9 +217,21 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_XRGB444: case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_RGBX444: + case V4L2_PIX_FMT_RGBA444: + case V4L2_PIX_FMT_XBGR444: + case V4L2_PIX_FMT_ABGR444: + case V4L2_PIX_FMT_BGRX444: + case V4L2_PIX_FMT_BGRA444: case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_RGBX555: + case V4L2_PIX_FMT_RGBA555: + case V4L2_PIX_FMT_XBGR555: + case V4L2_PIX_FMT_ABGR555: + case V4L2_PIX_FMT_BGRX555: + case V4L2_PIX_FMT_BGRA555: case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: case V4L2_PIX_FMT_ARGB555X: @@ -232,6 +244,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_RGBX32: + case V4L2_PIX_FMT_BGRX32: + case V4L2_PIX_FMT_RGBA32: + case V4L2_PIX_FMT_BGRA32: tpg->color_enc = TGP_COLOR_ENC_RGB; break; case V4L2_PIX_FMT_GREY: @@ -343,9 +359,21 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_XRGB444: case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_RGBX444: + case V4L2_PIX_FMT_RGBA444: + case V4L2_PIX_FMT_XBGR444: + case V4L2_PIX_FMT_ABGR444: + case V4L2_PIX_FMT_BGRX444: + case V4L2_PIX_FMT_BGRA444: case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_RGBX555: + case V4L2_PIX_FMT_RGBA555: + case V4L2_PIX_FMT_XBGR555: + case V4L2_PIX_FMT_ABGR555: + case V4L2_PIX_FMT_BGRX555: + case V4L2_PIX_FMT_BGRA555: case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: case V4L2_PIX_FMT_ARGB555X: @@ -375,6 +403,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_RGBX32: + case V4L2_PIX_FMT_BGRX32: + case V4L2_PIX_FMT_RGBA32: + case V4L2_PIX_FMT_BGRA32: case V4L2_PIX_FMT_YUV32: case V4L2_PIX_FMT_AYUV32: case V4L2_PIX_FMT_XYUV32: @@ -1007,6 +1039,12 @@ static void precalculate_color(struct tpg_data *tpg, int k) case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_XRGB444: case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_RGBX444: + case V4L2_PIX_FMT_RGBA444: + case V4L2_PIX_FMT_XBGR444: + case V4L2_PIX_FMT_ABGR444: + case V4L2_PIX_FMT_BGRX444: + case V4L2_PIX_FMT_BGRA444: r >>= 8; g >>= 8; b >>= 8; @@ -1014,6 +1052,12 @@ static void precalculate_color(struct tpg_data *tpg, int k) case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_RGBX555: + case V4L2_PIX_FMT_RGBA555: + case V4L2_PIX_FMT_XBGR555: + case V4L2_PIX_FMT_ABGR555: + case V4L2_PIX_FMT_BGRX555: + case V4L2_PIX_FMT_BGRA555: case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: case V4L2_PIX_FMT_ARGB555X: @@ -1237,6 +1281,27 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset] = (g_u_s << 4) | b_v; buf[0][offset + 1] = (alpha & 0xf0) | r_y_h; break; + case V4L2_PIX_FMT_RGBX444: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_RGBA444: + buf[0][offset] = (b_v << 4) | (alpha >> 4); + buf[0][offset + 1] = (r_y_h << 4) | g_u_s; + break; + case V4L2_PIX_FMT_XBGR444: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_ABGR444: + buf[0][offset] = (g_u_s << 4) | r_y_h; + buf[0][offset + 1] = (alpha & 0xf0) | b_v; + break; + case V4L2_PIX_FMT_BGRX444: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_BGRA444: + buf[0][offset] = (r_y_h << 4) | (alpha >> 4); + buf[0][offset + 1] = (b_v << 4) | g_u_s; + break; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: alpha = 0; @@ -1247,6 +1312,30 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 1] = (alpha & 0x80) | (r_y_h << 2) | (g_u_s >> 3); break; + case V4L2_PIX_FMT_RGBX555: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_RGBA555: + buf[0][offset] = (g_u_s << 6) | (b_v << 1) | + ((alpha & 0x80) >> 7); + buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 2); + break; + case V4L2_PIX_FMT_XBGR555: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_ABGR555: + buf[0][offset] = (g_u_s << 5) | r_y_h; + buf[0][offset + 1] = (alpha & 0x80) | (b_v << 2) + | (g_u_s >> 3); + break; + case V4L2_PIX_FMT_BGRX555: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_BGRA555: + buf[0][offset] = (g_u_s << 6) | (r_y_h << 1) | + ((alpha & 0x80) >> 7); + buf[0][offset + 1] = (b_v << 3) | (g_u_s >> 2); + break; case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: alpha = 0; @@ -1286,6 +1375,15 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 2] = g_u_s; buf[0][offset + 3] = b_v; break; + case V4L2_PIX_FMT_RGBX32: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_RGBA32: + buf[0][offset] = r_y_h; + buf[0][offset + 1] = g_u_s; + buf[0][offset + 2] = b_v; + buf[0][offset + 3] = alpha; + break; case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_VUYX32: @@ -1298,6 +1396,15 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 2] = r_y_h; buf[0][offset + 3] = alpha; break; + case V4L2_PIX_FMT_BGRX32: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_BGRA32: + buf[0][offset] = alpha; + buf[0][offset + 1] = b_v; + buf[0][offset + 2] = g_u_s; + buf[0][offset + 3] = r_y_h; + break; case V4L2_PIX_FMT_SBGGR8: buf[0][offset] = odd ? g_u_s : b_v; buf[1][offset] = odd ? r_y_h : g_u_s; diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 7d77e4d30c8a..44cd0e530bbd 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -267,8 +267,14 @@ static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf, /* release the scatterlist cache */ if (attach->dma_dir != DMA_NONE) - dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, - attach->dma_dir); + /* + * Cache sync can be skipped here, as the vb2_dc memory is + * allocated from device coherent memory, which means the + * memory locations do not require any explicit cache + * maintenance prior or after being used by the device. + */ + dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents, + attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC); sg_free_table(sgt); kfree(attach); db_attach->priv = NULL; @@ -293,14 +299,17 @@ static struct sg_table *vb2_dc_dmabuf_ops_map( /* release any previous cache */ if (attach->dma_dir != DMA_NONE) { - dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, - attach->dma_dir); + dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents, + attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC); attach->dma_dir = DMA_NONE; } - /* mapping to the client with new direction */ - sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, - dma_dir); + /* + * mapping to the client with new direction, no cache sync + * required see comment in vb2_dc_dmabuf_ops_detach() + */ + sgt->nents = dma_map_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents, + dma_dir, DMA_ATTR_SKIP_CPU_SYNC); if (!sgt->nents) { pr_err("failed to map scatterlist\n"); mutex_unlock(lock); diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 40d76eb4c2fe..5a9ba3846f0a 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -872,17 +872,19 @@ EXPORT_SYMBOL_GPL(vb2_queue_release); __poll_t vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) { struct video_device *vfd = video_devdata(file); - __poll_t res = 0; + __poll_t res; + + res = vb2_core_poll(q, file, wait); if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { struct v4l2_fh *fh = file->private_data; poll_wait(file, &fh->wait, wait); if (v4l2_event_pending(fh)) - res = EPOLLPRI; + res |= EPOLLPRI; } - return res | vb2_core_poll(q, file, wait); + return res; } EXPORT_SYMBOL_GPL(vb2_poll); diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 209186c5cd9b..06ea30a689d7 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -152,6 +152,9 @@ static void dvb_frontend_free(struct kref *ref) static void dvb_frontend_put(struct dvb_frontend *fe) { + /* call detach before dropping the reference count */ + if (fe->ops.detach) + fe->ops.detach(fe); /* * Check if the frontend was registered, as otherwise * kref was not initialized yet. @@ -3040,7 +3043,6 @@ void dvb_frontend_detach(struct dvb_frontend *fe) dvb_frontend_invoke_release(fe, fe->ops.release_sec); dvb_frontend_invoke_release(fe, fe->ops.tuner_ops.release); dvb_frontend_invoke_release(fe, fe->ops.analog_ops.release); - dvb_frontend_invoke_release(fe, fe->ops.detach); dvb_frontend_put(fe); } EXPORT_SYMBOL(dvb_frontend_detach); diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index a3393cd4e584..917fe034af37 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -339,8 +339,10 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev, if (npads) { dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads), GFP_KERNEL); - if (!dvbdev->pads) + if (!dvbdev->pads) { + kfree(dvbdev->entity); return -ENOMEM; + } } switch (type) { @@ -476,7 +478,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, return -ENOMEM; } - dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); + dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL); if (!dvbdevfops){ kfree (dvbdev); @@ -492,7 +494,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, dvbdev->fops = dvbdevfops; init_waitqueue_head (&dvbdev->wait_queue); - memcpy(dvbdevfops, template->fops, sizeof(struct file_operations)); dvbdevfops->owner = adap->module; list_add_tail (&dvbdev->list_head, &adap->device_list); diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index dc43749177df..a29e9ddf9c82 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -1,5 +1,8 @@ +comment "DVB Frontend drivers hidden by 'Autoselect ancillary drivers'" + depends on MEDIA_HIDE_ANCILLARY_SUBDRV + menu "Customise DVB Frontends" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT + visible if !MEDIA_HIDE_ANCILLARY_SUBDRV comment "Multistandard (satellite) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c index 42697a5999f7..9fccc906d85a 100644 --- a/drivers/media/dvb-frontends/cx24117.c +++ b/drivers/media/dvb-frontends/cx24117.c @@ -619,8 +619,10 @@ static int cx24117_load_firmware(struct dvb_frontend *fe, /* send fw */ ret = i2c_transfer(state->priv->i2c, &msg, 1); - if (ret < 0) + if (ret < 0) { + kfree(buf); return ret; + } kfree(buf); diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c index ac519c3eff18..3d84ee17e54c 100644 --- a/drivers/media/dvb-frontends/cx24123.c +++ b/drivers/media/dvb-frontends/cx24123.c @@ -431,7 +431,7 @@ static u32 cx24123_int_log2(u32 a, u32 b) u32 div = a / b; if (a % b >= b / 2) ++div; - if (div < (1 << 31)) { + if (div < (1UL << 31)) { for (exp = 1; div > exp; nearest++) exp += exp; } diff --git a/drivers/media/dvb-frontends/cxd2099.c b/drivers/media/dvb-frontends/cxd2099.c index 5264e873850e..f88b5355493e 100644 --- a/drivers/media/dvb-frontends/cxd2099.c +++ b/drivers/media/dvb-frontends/cxd2099.c @@ -594,7 +594,7 @@ static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) return ecount; } -static struct dvb_ca_en50221 en_templ = { +static const struct dvb_ca_en50221 en_templ = { .read_attribute_mem = read_attribute_mem, .write_attribute_mem = write_attribute_mem, .read_cam_control = read_cam_control, diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 1f006f8e8cc2..d137199e13e6 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -632,12 +632,11 @@ static int cxd2820r_probe(struct i2c_client *client, * one dummy I2C client in in order to get own I2C client for each * register bank. */ - priv->client[1] = i2c_new_dummy(client->adapter, client->addr | (1 << 1)); - if (!priv->client[1]) { - ret = -ENODEV; + priv->client[1] = i2c_new_dummy_device(client->adapter, client->addr | (1 << 1)); + if (IS_ERR(priv->client[1])) { + ret = PTR_ERR(priv->client[1]); dev_err(&client->dev, "I2C registration failed\n"); - if (ret) - goto err_regmap_0_regmap_exit; + goto err_regmap_0_regmap_exit; } priv->regmap[1] = regmap_init_i2c(priv->client[1], ®map_config1); diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 52f5e697c5dc..0d22c700016d 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -2036,7 +2036,8 @@ static int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { dprintk("-D- DiB7000PC detected\n"); - return 1; + ret = 1; + goto out; } msg[0].addr = msg[1].addr = 0x40; @@ -2044,11 +2045,13 @@ static int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { dprintk("-D- DiB7000PC detected\n"); - return 1; + ret = 1; + goto out; } dprintk("-D- DiB7000PC not detected\n"); +out: kfree(rx); rx_memory_error: kfree(tx); diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index a6876fa48753..2f5af4813a74 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -12287,7 +12287,8 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c) if (state == NULL) goto error; - demod = kmalloc(sizeof(struct drx_demod_instance), GFP_KERNEL); + demod = kmemdup(&drxj_default_demod_g, + sizeof(struct drx_demod_instance), GFP_KERNEL); if (demod == NULL) goto error; @@ -12311,8 +12312,6 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c) state->demod = demod; /* setup the demod data */ - memcpy(demod, &drxj_default_demod_g, sizeof(struct drx_demod_instance)); - demod->my_i2c_dev_addr = demod_addr; demod->my_common_attr = demod_comm_attr; demod->my_i2c_dev_addr->user_data = state; diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index ba0c49107bd2..d45b4ddc8f91 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -9,6 +9,7 @@ #include <linux/slab.h> #include <linux/module.h> +#include <linux/idr.h> #include <linux/dvb/frontend.h> #include <asm/types.h> @@ -34,8 +35,7 @@ struct dvb_pll_priv { }; #define DVB_PLL_MAX 64 - -static unsigned int dvb_pll_devcount; +static DEFINE_IDA(pll_ida); static int debug; module_param(debug, int, 0644); @@ -787,6 +787,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct dvb_pll_priv *priv = NULL; int ret; const struct dvb_pll_desc *desc; + int nr; b1 = kmalloc(1, GFP_KERNEL); if (!b1) @@ -795,9 +796,14 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, b1[0] = 0; msg.buf = b1; - if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) && - (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list))) - pll_desc_id = id[dvb_pll_devcount]; + nr = ida_simple_get(&pll_ida, 0, DVB_PLL_MAX, GFP_KERNEL); + if (nr < 0) { + kfree(b1); + return NULL; + } + + if (id[nr] > DVB_PLL_UNDEFINED && id[nr] < ARRAY_SIZE(pll_list)) + pll_desc_id = id[nr]; BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list)); @@ -808,24 +814,20 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, fe->ops.i2c_gate_ctrl(fe, 1); ret = i2c_transfer (i2c, &msg, 1); - if (ret != 1) { - kfree(b1); - return NULL; - } + if (ret != 1) + goto out; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL); - if (!priv) { - kfree(b1); - return NULL; - } + if (!priv) + goto out; priv->pll_i2c_address = pll_addr; priv->i2c = i2c; priv->pll_desc = desc; - priv->nr = dvb_pll_devcount++; + priv->nr = nr; memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -858,6 +860,11 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, kfree(b1); return fe; +out: + kfree(b1); + ida_simple_remove(&pll_ida, nr); + + return NULL; } EXPORT_SYMBOL(dvb_pll_attach); @@ -894,9 +901,10 @@ dvb_pll_probe(struct i2c_client *client, const struct i2c_device_id *id) static int dvb_pll_remove(struct i2c_client *client) { - struct dvb_frontend *fe; + struct dvb_frontend *fe = i2c_get_clientdata(client); + struct dvb_pll_priv *priv = fe->tuner_priv; - fe = i2c_get_clientdata(client); + ida_simple_remove(&pll_ida, priv->nr); dvb_pll_release(fe); return 0; } diff --git a/drivers/media/dvb-frontends/mn88443x.c b/drivers/media/dvb-frontends/mn88443x.c index 9ec1aeef03d5..e4528784f847 100644 --- a/drivers/media/dvb-frontends/mn88443x.c +++ b/drivers/media/dvb-frontends/mn88443x.c @@ -722,9 +722,9 @@ static int mn88443x_probe(struct i2c_client *client, * Chip has two I2C addresses for each satellite/terrestrial system. * ISDB-T uses address ISDB-S + 4, so we register a dummy client. */ - chip->client_t = i2c_new_dummy(client->adapter, client->addr + 4); - if (!chip->client_t) - return -ENODEV; + chip->client_t = i2c_new_dummy_device(client->adapter, client->addr + 4); + if (IS_ERR(chip->client_t)) + return PTR_ERR(chip->client_t); chip->regmap_t = devm_regmap_init_i2c(chip->client_t, ®map_config); if (IS_ERR(chip->regmap_t)) { diff --git a/drivers/media/dvb-frontends/mn88472.c b/drivers/media/dvb-frontends/mn88472.c index 731b44b9b74c..73922fc8f39c 100644 --- a/drivers/media/dvb-frontends/mn88472.c +++ b/drivers/media/dvb-frontends/mn88472.c @@ -612,12 +612,11 @@ static int mn88472_probe(struct i2c_client *client, * Also, register bank 2 do not support sequential I/O. Only single * register write or read is allowed to that bank. */ - dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); - if (!dev->client[1]) { - ret = -ENODEV; + dev->client[1] = i2c_new_dummy_device(client->adapter, 0x1a); + if (IS_ERR(dev->client[1])) { + ret = PTR_ERR(dev->client[1]); dev_err(&client->dev, "I2C registration failed\n"); - if (ret) - goto err_regmap_0_regmap_exit; + goto err_regmap_0_regmap_exit; } dev->regmap[1] = regmap_init_i2c(dev->client[1], ®map_config); if (IS_ERR(dev->regmap[1])) { @@ -626,12 +625,11 @@ static int mn88472_probe(struct i2c_client *client, } i2c_set_clientdata(dev->client[1], dev); - dev->client[2] = i2c_new_dummy(client->adapter, 0x1c); - if (!dev->client[2]) { - ret = -ENODEV; + dev->client[2] = i2c_new_dummy_device(client->adapter, 0x1c); + if (IS_ERR(dev->client[2])) { + ret = PTR_ERR(dev->client[2]); dev_err(&client->dev, "2nd I2C registration failed\n"); - if (ret) - goto err_regmap_1_regmap_exit; + goto err_regmap_1_regmap_exit; } dev->regmap[2] = regmap_init_i2c(dev->client[2], ®map_config); if (IS_ERR(dev->regmap[2])) { diff --git a/drivers/media/dvb-frontends/mn88473.c b/drivers/media/dvb-frontends/mn88473.c index 08118b38533b..4838969ef735 100644 --- a/drivers/media/dvb-frontends/mn88473.c +++ b/drivers/media/dvb-frontends/mn88473.c @@ -657,12 +657,11 @@ static int mn88473_probe(struct i2c_client *client, * Also, register bank 2 do not support sequential I/O. Only single * register write or read is allowed to that bank. */ - dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); - if (dev->client[1] == NULL) { - ret = -ENODEV; + dev->client[1] = i2c_new_dummy_device(client->adapter, 0x1a); + if (IS_ERR(dev->client[1])) { + ret = PTR_ERR(dev->client[1]); dev_err(&client->dev, "I2C registration failed\n"); - if (ret) - goto err_regmap_0_regmap_exit; + goto err_regmap_0_regmap_exit; } dev->regmap[1] = regmap_init_i2c(dev->client[1], ®map_config); if (IS_ERR(dev->regmap[1])) { @@ -671,12 +670,11 @@ static int mn88473_probe(struct i2c_client *client, } i2c_set_clientdata(dev->client[1], dev); - dev->client[2] = i2c_new_dummy(client->adapter, 0x1c); - if (dev->client[2] == NULL) { - ret = -ENODEV; + dev->client[2] = i2c_new_dummy_device(client->adapter, 0x1c); + if (IS_ERR(dev->client[2])) { + ret = PTR_ERR(dev->client[2]); dev_err(&client->dev, "2nd I2C registration failed\n"); - if (ret) - goto err_regmap_1_regmap_exit; + goto err_regmap_1_regmap_exit; } dev->regmap[2] = regmap_init_i2c(dev->client[2], ®map_config); if (IS_ERR(dev->regmap[2])) { diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index e05c21d35dc8..60d1e59d2292 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -81,11 +81,9 @@ struct rtl2832_sdr_format { static struct rtl2832_sdr_format formats[] = { { - .name = "Complex U8", .pixelformat = V4L2_SDR_FMT_CU8, .buffersize = BULK_BUFFER_SIZE, }, { - .name = "Complex U16LE (emulated)", .pixelformat = V4L2_SDR_FMT_CU16LE, .buffersize = BULK_BUFFER_SIZE * 2, }, @@ -1116,7 +1114,6 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv, if (f->index >= dev->num_formats) return -EINVAL; - strscpy(f->description, formats[f->index].name, sizeof(f->description)); f->pixelformat = formats[f->index].pixelformat; return 0; diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 168c503e9154..14b93a7d3358 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -11,6 +11,13 @@ static const struct dvb_frontend_ops si2168_ops; +static void cmd_init(struct si2168_cmd *cmd, const u8 *buf, int wlen, int rlen) +{ + memcpy(cmd->args, buf, wlen); + cmd->wlen = wlen; + cmd->rlen = rlen; +} + /* execute firmware command */ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) { @@ -82,16 +89,23 @@ static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + /* set manual value */ + if (dev->ts_mode & SI2168_TS_CLK_MANUAL) { + cmd_init(&cmd, "\x14\x00\x0d\x10\xe8\x03", 6, 4); + ret = si2168_cmd_execute(client, &cmd); + if (ret) + return ret; + } /* set TS_MODE property */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + cmd_init(&cmd, "\x14\x00\x01\x10\x10\x00", 6, 4); + if (dev->ts_mode & SI2168_TS_CLK_MANUAL) + cmd.args[4] = SI2168_TS_CLK_MANUAL; if (acquire) cmd.args[4] |= dev->ts_mode; else cmd.args[4] |= SI2168_TS_TRISTATE; if (dev->ts_clock_gapped) cmd.args[4] |= 0x40; - cmd.wlen = 6; - cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); return ret; @@ -115,19 +129,13 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) switch (c->delivery_system) { case SYS_DVBT: - memcpy(cmd.args, "\xa0\x01", 2); - cmd.wlen = 2; - cmd.rlen = 13; + cmd_init(&cmd, "\xa0\x01", 2, 13); break; case SYS_DVBC_ANNEX_A: - memcpy(cmd.args, "\x90\x01", 2); - cmd.wlen = 2; - cmd.rlen = 9; + cmd_init(&cmd, "\x90\x01", 2, 9); break; case SYS_DVBT2: - memcpy(cmd.args, "\x50\x01", 2); - cmd.wlen = 2; - cmd.rlen = 14; + cmd_init(&cmd, "\x50\x01", 2, 14); break; default: ret = -EINVAL; @@ -164,9 +172,7 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) /* BER */ if (*status & FE_HAS_VITERBI) { - memcpy(cmd.args, "\x82\x00", 2); - cmd.wlen = 2; - cmd.rlen = 3; + cmd_init(&cmd, "\x82\x00", 2, 3); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -197,9 +203,7 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) /* UCB */ if (*status & FE_HAS_SYNC) { - memcpy(cmd.args, "\x84\x01", 2); - cmd.wlen = 2; - cmd.rlen = 3; + cmd_init(&cmd, "\x84\x01", 2, 3); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -285,22 +289,18 @@ static int si2168_set_frontend(struct dvb_frontend *fe) goto err; } - memcpy(cmd.args, "\x88\x02\x02\x02\x02", 5); - cmd.wlen = 5; - cmd.rlen = 5; + cmd_init(&cmd, "\x88\x02\x02\x02\x02", 5, 5); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; /* that has no big effect */ if (c->delivery_system == SYS_DVBT) - memcpy(cmd.args, "\x89\x21\x06\x11\xff\x98", 6); + cmd_init(&cmd, "\x89\x21\x06\x11\xff\x98", 6, 3); else if (c->delivery_system == SYS_DVBC_ANNEX_A) - memcpy(cmd.args, "\x89\x21\x06\x11\x89\xf0", 6); + cmd_init(&cmd, "\x89\x21\x06\x11\x89\xf0", 6, 3); else if (c->delivery_system == SYS_DVBT2) - memcpy(cmd.args, "\x89\x21\x06\x11\x89\x20", 6); - cmd.wlen = 6; - cmd.rlen = 3; + cmd_init(&cmd, "\x89\x21\x06\x11\x89\x20", 6, 3); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -317,103 +317,77 @@ static int si2168_set_frontend(struct dvb_frontend *fe) goto err; } - memcpy(cmd.args, "\x51\x03", 2); - cmd.wlen = 2; - cmd.rlen = 12; + cmd_init(&cmd, "\x51\x03", 2, 12); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x12\x08\x04", 3); - cmd.wlen = 3; - cmd.rlen = 3; + cmd_init(&cmd, "\x12\x08\x04", 3, 3); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x0c\x10\x12\x00", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x06\x10\x24\x00", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x07\x10\x00\x24", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6); + cmd_init(&cmd, "\x14\x00\x0a\x10\x00\x00", 6, 4); cmd.args[4] = delivery_system | bandwidth; if (dev->spectral_inversion) cmd.args[5] |= 1; - cmd.wlen = 6; - cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; /* set DVB-C symbol rate */ if (c->delivery_system == SYS_DVBC_ANNEX_A) { - memcpy(cmd.args, "\x14\x00\x02\x11", 4); + cmd_init(&cmd, "\x14\x00\x02\x11\x00\x00", 6, 4); cmd.args[4] = ((c->symbol_rate / 1000) >> 0) & 0xff; cmd.args[5] = ((c->symbol_rate / 1000) >> 8) & 0xff; - cmd.wlen = 6; - cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; } - memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x0f\x10\x10\x00", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x08", 6); + cmd_init(&cmd, "\x14\x00\x09\x10\xe3\x08", 6, 4); cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10; - cmd.wlen = 6; - cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x05", 6); + cmd_init(&cmd, "\x14\x00\x08\x10\xd7\x05", 6, 4); cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10; - cmd.wlen = 6; - cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x01\x12\x00\x00", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x01\x03\x0c\x00", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x85", 1); - cmd.wlen = 1; - cmd.rlen = 1; + cmd_init(&cmd, "\x85", 1, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -443,26 +417,21 @@ static int si2168_init(struct dvb_frontend *fe) dev_dbg(&client->dev, "\n"); /* initialize */ - memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13); - cmd.wlen = 13; - cmd.rlen = 0; + cmd_init(&cmd, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", + 13, 0); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; if (dev->warm) { /* resume */ - memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8); - cmd.wlen = 8; - cmd.rlen = 1; + cmd_init(&cmd, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; udelay(100); - memcpy(cmd.args, "\x85", 1); - cmd.wlen = 1; - cmd.rlen = 1; + cmd_init(&cmd, "\x85", 1, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -471,9 +440,7 @@ static int si2168_init(struct dvb_frontend *fe) } /* power up */ - memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8); - cmd.wlen = 8; - cmd.rlen = 1; + cmd_init(&cmd, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -511,9 +478,8 @@ static int si2168_init(struct dvb_frontend *fe) ret = -EINVAL; break; } - memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len); - cmd.wlen = len; - cmd.rlen = 1; + cmd_init(&cmd, &fw->data[(fw->size - remaining) + 1], + len, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) break; @@ -521,10 +487,7 @@ static int si2168_init(struct dvb_frontend *fe) } else if (fw->size % 8 == 0) { /* firmware is in the old format */ for (remaining = fw->size; remaining > 0; remaining -= 8) { - len = 8; - memcpy(cmd.args, &fw->data[fw->size - remaining], len); - cmd.wlen = len; - cmd.rlen = 1; + cmd_init(&cmd, &fw->data[fw->size - remaining], 8, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) break; @@ -541,17 +504,13 @@ static int si2168_init(struct dvb_frontend *fe) release_firmware(fw); - memcpy(cmd.args, "\x01\x01", 2); - cmd.wlen = 2; - cmd.rlen = 1; + cmd_init(&cmd, "\x01\x01", 2, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; /* query firmware version */ - memcpy(cmd.args, "\x11", 1); - cmd.wlen = 1; - cmd.rlen = 10; + cmd_init(&cmd, "\x11", 1, 10); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -609,9 +568,7 @@ static int si2168_sleep(struct dvb_frontend *fe) if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) dev->warm = false; - memcpy(cmd.args, "\x13", 1); - cmd.wlen = 1; - cmd.rlen = 0; + cmd_init(&cmd, "\x13", 1, 0); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -637,9 +594,7 @@ static int si2168_select(struct i2c_mux_core *muxc, u32 chan) struct si2168_cmd cmd; /* open I2C gate */ - memcpy(cmd.args, "\xc0\x0d\x01", 3); - cmd.wlen = 3; - cmd.rlen = 0; + cmd_init(&cmd, "\xc0\x0d\x01", 3, 0); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -657,9 +612,7 @@ static int si2168_deselect(struct i2c_mux_core *muxc, u32 chan) struct si2168_cmd cmd; /* close I2C gate */ - memcpy(cmd.args, "\xc0\x0d\x00", 3); - cmd.wlen = 3; - cmd.rlen = 0; + cmd_init(&cmd, "\xc0\x0d\x00", 3, 0); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -730,25 +683,20 @@ static int si2168_probe(struct i2c_client *client, mutex_init(&dev->i2c_mutex); /* Initialize */ - memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13); - cmd.wlen = 13; - cmd.rlen = 0; + cmd_init(&cmd, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", + 13, 0); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err_kfree; /* Power up */ - memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8); - cmd.wlen = 8; - cmd.rlen = 1; + cmd_init(&cmd, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err_kfree; /* Query chip revision */ - memcpy(cmd.args, "\x02", 1); - cmd.wlen = 1; - cmd.rlen = 13; + cmd_init(&cmd, "\x02", 1, 13); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err_kfree; diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index 3b04f84272d9..50dccb394efa 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -30,6 +30,7 @@ struct si2168_config { #define SI2168_TS_PARALLEL 0x06 #define SI2168_TS_SERIAL 0x03 #define SI2168_TS_TRISTATE 0x00 +#define SI2168_TS_CLK_MANUAL 0x20 u8 ts_mode; /* TS clock inverted */ diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index 0c50740e7bb8..7d93a1617e86 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -270,7 +270,7 @@ static enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp) static u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk) { - u32 mclk = 90000000, div = 0, ad_div = 0; + u32 mclk, div, ad_div; div = stv0900_get_bits(intp, F0900_M_DIV); ad_div = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6); diff --git a/drivers/media/dvb-frontends/zd1301_demod.c b/drivers/media/dvb-frontends/zd1301_demod.c index 96adbba7a82b..bbabe6a2d4f4 100644 --- a/drivers/media/dvb-frontends/zd1301_demod.c +++ b/drivers/media/dvb-frontends/zd1301_demod.c @@ -421,8 +421,7 @@ static int zd1301_demod_i2c_master_xfer(struct i2c_adapter *adapter, } else { dev_dbg(&pdev->dev, "unknown msg[0].len=%u\n", msg[0].len); ret = -EOPNOTSUPP; - if (ret) - goto err; + goto err; } return num; diff --git a/drivers/media/firewire/firedtv-ci.c b/drivers/media/firewire/firedtv-ci.c index a960a0ce9deb..9363d005e2b6 100644 --- a/drivers/media/firewire/firedtv-ci.c +++ b/drivers/media/firewire/firedtv-ci.c @@ -217,7 +217,7 @@ static const struct file_operations fdtv_ca_fops = { .llseek = noop_llseek, }; -static struct dvb_device fdtv_ca = { +static const struct dvb_device fdtv_ca = { .users = 1, .readers = 1, .writers = 1, diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 79ce9ec6fc1b..7eee1812bba3 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -22,8 +22,11 @@ config VIDEO_IR_I2C # Encoder / Decoder module configuration # +comment "I2C drivers hidden by 'Autoselect ancillary drivers'" + depends on MEDIA_HIDE_ANCILLARY_SUBDRV + menu "I2C Encoders, decoders, sensors and other helper chips" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT + visible if !MEDIA_HIDE_ANCILLARY_SUBDRV comment "Audio decoders, processors and mixers" @@ -723,6 +726,19 @@ config VIDEO_OV5670 To compile this driver as a module, choose M here: the module will be called ov5670. +config VIDEO_OV5675 + tristate "OmniVision OV5675 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT + depends on MEDIA_CONTROLLER + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the OmniVision + OV5675 camera. + + To compile this driver as a module, choose M here: the + module will be called ov5675. + config VIDEO_OV5695 tristate "OmniVision OV5695 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index fd4ea86dedd5..beb170b002dc 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_VIDEO_OV5640) += ov5640.o obj-$(CONFIG_VIDEO_OV5645) += ov5645.o obj-$(CONFIG_VIDEO_OV5647) += ov5647.o obj-$(CONFIG_VIDEO_OV5670) += ov5670.o +obj-$(CONFIG_VIDEO_OV5675) += ov5675.o obj-$(CONFIG_VIDEO_OV5695) += ov5695.o obj-$(CONFIG_VIDEO_OV6650) += ov6650.o obj-$(CONFIG_VIDEO_OV7251) += ov7251.o diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index aa8b04cfed0f..8679a44e6413 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c @@ -1148,10 +1148,10 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id * v4l2_dbg(1, debug, sd, "reg 0x41 0x%x, chip version (reg 0x00) 0x%x\n", ad9389b_rd(sd, 0x41), state->chip_revision); - state->edid_i2c_client = i2c_new_dummy(client->adapter, (0x7e>>1)); - if (state->edid_i2c_client == NULL) { + state->edid_i2c_client = i2c_new_dummy_device(client->adapter, (0x7e >> 1)); + if (IS_ERR(state->edid_i2c_client)) { v4l2_err(sd, "failed to register edid i2c client\n"); - err = -ENOMEM; + err = PTR_ERR(state->edid_i2c_client); goto err_entity; } diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 6f3dc8862622..e780969cc2f2 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1329,17 +1329,17 @@ static int adv7180_probe(struct i2c_client *client, } if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { - state->csi_client = i2c_new_dummy(client->adapter, + state->csi_client = i2c_new_dummy_device(client->adapter, ADV7180_DEFAULT_CSI_I2C_ADDR); - if (!state->csi_client) - return -ENOMEM; + if (IS_ERR(state->csi_client)) + return PTR_ERR(state->csi_client); } if (state->chip_info->flags & ADV7180_FLAG_I2P) { - state->vpp_client = i2c_new_dummy(client->adapter, + state->vpp_client = i2c_new_dummy_device(client->adapter, ADV7180_DEFAULT_VPP_I2C_ADDR); - if (!state->vpp_client) { - ret = -ENOMEM; + if (IS_ERR(state->vpp_client)) { + ret = PTR_ERR(state->vpp_client); goto err_unregister_csi_client; } } diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index 4a441ee99dd8..63e94dfcb5d3 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c @@ -428,8 +428,7 @@ done: return pdata; } -static int adv7343_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adv7343_probe(struct i2c_client *client) { struct adv7343_state *state; int err; @@ -524,7 +523,7 @@ static struct i2c_driver adv7343_driver = { .of_match_table = of_match_ptr(adv7343_of_match), .name = "adv7343", }, - .probe = adv7343_probe, + .probe_new = adv7343_probe, .remove = adv7343_remove, .id_table = adv7343_id, }; diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index f57cd77a32fa..0a47d474e97a 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -668,8 +668,7 @@ static void adv748x_dt_cleanup(struct adv748x_state *state) of_node_put(state->endpoints[i]); } -static int adv748x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adv748x_probe(struct i2c_client *client) { struct adv748x_state *state; int ret; @@ -797,13 +796,6 @@ static int adv748x_remove(struct i2c_client *client) return 0; } -static const struct i2c_device_id adv748x_id[] = { - { "adv7481", 0 }, - { "adv7482", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, adv748x_id); - static const struct of_device_id adv748x_of_table[] = { { .compatible = "adi,adv7481", }, { .compatible = "adi,adv7482", }, @@ -816,9 +808,8 @@ static struct i2c_driver adv748x_driver = { .name = "adv748x", .of_match_table = adv748x_of_table, }, - .probe = adv748x_probe, + .probe_new = adv748x_probe, .remove = adv748x_remove, - .id_table = adv748x_id, }; module_i2c_driver(adv748x_driver); diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c index 2ad6bdf1a9fc..62763ec4cd07 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -1872,11 +1872,11 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * goto err_entity; } - state->i2c_edid = i2c_new_dummy(client->adapter, + state->i2c_edid = i2c_new_dummy_device(client->adapter, state->i2c_edid_addr >> 1); - if (state->i2c_edid == NULL) { + if (IS_ERR(state->i2c_edid)) { v4l2_err(sd, "failed to register edid i2c client\n"); - err = -ENOMEM; + err = PTR_ERR(state->i2c_edid); goto err_entity; } @@ -1889,11 +1889,11 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * } if (state->pdata.cec_clk) { - state->i2c_cec = i2c_new_dummy(client->adapter, + state->i2c_cec = i2c_new_dummy_device(client->adapter, state->i2c_cec_addr >> 1); - if (state->i2c_cec == NULL) { + if (IS_ERR(state->i2c_cec)) { v4l2_err(sd, "failed to register cec i2c client\n"); - err = -ENOMEM; + err = PTR_ERR(state->i2c_cec); goto err_unreg_edid; } adv7511_wr(sd, 0xe2, 0x00); /* power up cec section */ @@ -1901,10 +1901,10 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */ } - state->i2c_pktmem = i2c_new_dummy(client->adapter, state->i2c_pktmem_addr >> 1); - if (state->i2c_pktmem == NULL) { + state->i2c_pktmem = i2c_new_dummy_device(client->adapter, state->i2c_pktmem_addr >> 1); + if (IS_ERR(state->i2c_pktmem)) { v4l2_err(sd, "failed to register pktmem i2c client\n"); - err = -ENOMEM; + err = PTR_ERR(state->i2c_pktmem); goto err_unreg_cec; } @@ -1940,8 +1940,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * err_unreg_pktmem: i2c_unregister_device(state->i2c_pktmem); err_unreg_cec: - if (state->i2c_cec) - i2c_unregister_device(state->i2c_cec); + i2c_unregister_device(state->i2c_cec); err_unreg_edid: i2c_unregister_device(state->i2c_edid); err_entity: @@ -1967,8 +1966,7 @@ static int adv7511_remove(struct i2c_client *client) adv7511_init_setup(sd); cancel_delayed_work(&state->edid_handler); i2c_unregister_device(state->i2c_edid); - if (state->i2c_cec) - i2c_unregister_device(state->i2c_cec); + i2c_unregister_device(state->i2c_cec); i2c_unregister_device(state->i2c_pktmem); destroy_workqueue(state->work_queue); v4l2_device_unregister_subdev(sd); @@ -1980,14 +1978,14 @@ static int adv7511_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ static const struct i2c_device_id adv7511_id[] = { - { "adv7511", 0 }, + { "adv7511-v4l2", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, adv7511_id); static struct i2c_driver adv7511_driver = { .driver = { - .name = "adv7511", + .name = "adv7511-v4l2", }, .probe = adv7511_probe, .remove = adv7511_remove, diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 11ab2df02dc7..885619841719 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -3351,28 +3351,17 @@ static const struct v4l2_ctrl_config adv7842_ctrl_free_run_color = { static void adv7842_unregister_clients(struct v4l2_subdev *sd) { struct adv7842_state *state = to_state(sd); - if (state->i2c_avlink) - i2c_unregister_device(state->i2c_avlink); - if (state->i2c_cec) - i2c_unregister_device(state->i2c_cec); - if (state->i2c_infoframe) - i2c_unregister_device(state->i2c_infoframe); - if (state->i2c_sdp_io) - i2c_unregister_device(state->i2c_sdp_io); - if (state->i2c_sdp) - i2c_unregister_device(state->i2c_sdp); - if (state->i2c_afe) - i2c_unregister_device(state->i2c_afe); - if (state->i2c_repeater) - i2c_unregister_device(state->i2c_repeater); - if (state->i2c_edid) - i2c_unregister_device(state->i2c_edid); - if (state->i2c_hdmi) - i2c_unregister_device(state->i2c_hdmi); - if (state->i2c_cp) - i2c_unregister_device(state->i2c_cp); - if (state->i2c_vdp) - i2c_unregister_device(state->i2c_vdp); + i2c_unregister_device(state->i2c_avlink); + i2c_unregister_device(state->i2c_cec); + i2c_unregister_device(state->i2c_infoframe); + i2c_unregister_device(state->i2c_sdp_io); + i2c_unregister_device(state->i2c_sdp); + i2c_unregister_device(state->i2c_afe); + i2c_unregister_device(state->i2c_repeater); + i2c_unregister_device(state->i2c_edid); + i2c_unregister_device(state->i2c_hdmi); + i2c_unregister_device(state->i2c_cp); + i2c_unregister_device(state->i2c_vdp); state->i2c_avlink = NULL; state->i2c_cec = NULL; @@ -3400,9 +3389,12 @@ static struct i2c_client *adv7842_dummy_client(struct v4l2_subdev *sd, const cha return NULL; } - cp = i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); - if (!cp) - v4l2_err(sd, "register %s on i2c addr 0x%x failed\n", desc, addr); + cp = i2c_new_dummy_device(client->adapter, io_read(sd, io_reg) >> 1); + if (IS_ERR(cp)) { + v4l2_err(sd, "register %s on i2c addr 0x%x failed with %ld\n", + desc, addr, PTR_ERR(cp)); + cp = NULL; + } return cp; } diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index e6c06cb75d33..256acf73d5ea 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -1396,8 +1396,7 @@ static int __maybe_unused et8ek8_resume(struct device *dev) return __et8ek8_set_power(sensor, true); } -static int et8ek8_probe(struct i2c_client *client, - const struct i2c_device_id *devid) +static int et8ek8_probe(struct i2c_client *client) { struct et8ek8_sensor *sensor; struct device *dev = &client->dev; @@ -1504,7 +1503,7 @@ static struct i2c_driver et8ek8_i2c_driver = { .pm = &et8ek8_pm_ops, .of_match_table = et8ek8_of_table, }, - .probe = et8ek8_probe, + .probe_new = et8ek8_probe, .remove = __exit_p(et8ek8_remove), .id_table = et8ek8_id_table, }; diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index f3ff1af209f9..6011cec5e351 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -1821,8 +1821,7 @@ static const struct i2c_device_id imx274_id[] = { }; MODULE_DEVICE_TABLE(i2c, imx274_id); -static int imx274_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int imx274_probe(struct i2c_client *client) { struct v4l2_subdev *sd; struct stimx274 *imx274; @@ -1984,7 +1983,7 @@ static struct i2c_driver imx274_i2c_driver = { .name = DRIVER_NAME, .of_match_table = imx274_of_id_table, }, - .probe = imx274_probe, + .probe_new = imx274_probe, .remove = imx274_remove, .id_table = imx274_id, }; diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 876d7587a1da..e8119ad0bc71 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -885,9 +885,11 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) INIT_DELAYED_WORK(&ir->work, ir_work); if (probe_tx) { - ir->tx_c = i2c_new_dummy(client->adapter, 0x70); - if (!ir->tx_c) { + ir->tx_c = i2c_new_dummy_device(client->adapter, 0x70); + if (IS_ERR(ir->tx_c)) { dev_err(&client->dev, "failed to setup tx i2c address"); + err = PTR_ERR(ir->tx_c); + goto err_out_free; } else if (!zilog_init(ir)) { ir->carrier = 38000; ir->duty_cycle = 40; @@ -904,7 +906,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) return 0; err_out_free: - if (ir->tx_c) + if (!IS_ERR(ir->tx_c)) i2c_unregister_device(ir->tx_c); /* Only frees rc if it were allocated internally */ @@ -916,16 +918,12 @@ static int ir_remove(struct i2c_client *client) { struct IR_i2c *ir = i2c_get_clientdata(client); - /* kill outstanding polls */ cancel_delayed_work_sync(&ir->work); - if (ir->tx_c) - i2c_unregister_device(ir->tx_c); + i2c_unregister_device(ir->tx_c); - /* unregister device */ rc_unregister_device(ir->rc); - /* free memory */ return 0; } diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c index 7b226fadcdb8..19a3ceea3bc2 100644 --- a/drivers/media/i2c/max2175.c +++ b/drivers/media/i2c/max2175.c @@ -1271,8 +1271,7 @@ static int max2175_refout_load_to_bits(struct i2c_client *client, u32 load, return 0; } -static int max2175_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max2175_probe(struct i2c_client *client) { bool master = true, am_hiz = false; u32 refout_load, refout_bits = 0; /* REFOUT disabled */ @@ -1433,7 +1432,7 @@ static struct i2c_driver max2175_driver = { .name = DRIVER_NAME, .of_match_table = max2175_of_ids, }, - .probe = max2175_probe, + .probe_new = max2175_probe, .remove = max2175_remove, .id_table = max2175_id, }; diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index 2df743cbe09d..5613072908ac 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -726,8 +726,7 @@ static const struct v4l2_subdev_ops mt9m001_subdev_ops = { .pad = &mt9m001_subdev_pad_ops, }; -static int mt9m001_probe(struct i2c_client *client, - const struct i2c_device_id *did) +static int mt9m001_probe(struct i2c_client *client) { struct mt9m001 *mt9m001; struct i2c_adapter *adapter = client->adapter; @@ -872,7 +871,7 @@ static struct i2c_driver mt9m001_i2c_driver = { .pm = &mt9m001_pm_ops, .of_match_table = mt9m001_of_match, }, - .probe = mt9m001_probe, + .probe_new = mt9m001_probe, .remove = mt9m001_remove, .id_table = mt9m001_id, }; diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 12cb012d91f7..17e8253f5748 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -533,7 +533,7 @@ static int mt9m111_get_fmt(struct v4l2_subdev *sd, format->format = *mf; return 0; #else - return -ENOTTY; + return -EINVAL; #endif } @@ -1243,8 +1243,7 @@ out_put_fw: return ret; } -static int mt9m111_probe(struct i2c_client *client, - const struct i2c_device_id *did) +static int mt9m111_probe(struct i2c_client *client) { struct mt9m111 *mt9m111; struct i2c_adapter *adapter = client->adapter; @@ -1388,7 +1387,7 @@ static struct i2c_driver mt9m111_i2c_driver = { .name = "mt9m111", .of_match_table = of_match_ptr(mt9m111_of_match), }, - .probe = mt9m111_probe, + .probe_new = mt9m111_probe, .remove = mt9m111_remove, .id_table = mt9m111_id, }; diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index ecd167d7c4d2..4a4bd5b665a1 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -929,7 +929,7 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, format->format = *mf; return 0; #else - return -ENOTTY; + return -EINVAL; #endif } @@ -1190,8 +1190,7 @@ static int ov2640_probe_dt(struct i2c_client *client, /* * i2c_driver functions */ -static int ov2640_probe(struct i2c_client *client, - const struct i2c_device_id *did) +static int ov2640_probe(struct i2c_client *client) { struct ov2640_priv *priv; struct i2c_adapter *adapter = client->adapter; @@ -1302,7 +1301,7 @@ static struct i2c_driver ov2640_i2c_driver = { .name = "ov2640", .of_match_table = of_match_ptr(ov2640_of_match), }, - .probe = ov2640_probe, + .probe_new = ov2640_probe, .remove = ov2640_remove, .id_table = ov2640_id, }; diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 5ed2413eac8a..f4ded0669ff9 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1055,7 +1055,7 @@ static int ov2659_get_fmt(struct v4l2_subdev *sd, mutex_unlock(&ov2659->lock); return 0; #else - return -ENOTTY; + return -EINVAL; #endif } @@ -1131,8 +1131,6 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; -#else - ret = -ENOTTY; #endif } else { s64 val; @@ -1386,8 +1384,7 @@ done: return pdata; } -static int ov2659_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov2659_probe(struct i2c_client *client) { const struct ov2659_platform_data *pdata = ov2659_get_pdata(client); struct v4l2_subdev *sd; @@ -1515,7 +1512,7 @@ static struct i2c_driver ov2659_i2c_driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(ov2659_of_match), }, - .probe = ov2659_probe, + .probe_new = ov2659_probe, .remove = ov2659_remove, .id_table = ov2659_id, }; diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c index b10bcfabaeeb..59cdbc33658c 100644 --- a/drivers/media/i2c/ov2680.c +++ b/drivers/media/i2c/ov2680.c @@ -675,7 +675,7 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API fmt = v4l2_subdev_get_try_format(&sensor->sd, cfg, format->pad); #else - ret = -ENOTTY; + ret = -EINVAL; #endif } else { fmt = &sensor->fmt; @@ -723,10 +723,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API try_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); format->format = *try_fmt; -#else - ret = -ENOTTY; #endif - goto unlock; } @@ -1023,7 +1020,7 @@ static int ov2680_check_id(struct ov2680_dev *sensor) return 0; } -static int ov2860_parse_dt(struct ov2680_dev *sensor) +static int ov2680_parse_dt(struct ov2680_dev *sensor) { struct device *dev = ov2680_to_dev(sensor); int ret; @@ -1064,7 +1061,7 @@ static int ov2680_probe(struct i2c_client *client) sensor->i2c_client = client; - ret = ov2860_parse_dt(sensor); + ret = ov2680_parse_dt(sensor); if (ret < 0) return -EINVAL; diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 759d60c6d630..500d9bbff10b 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -158,8 +158,8 @@ static const int ov5640_framerates[] = { /* regulator supplies */ static const char * const ov5640_supply_name[] = { "DOVDD", /* Digital I/O (1.8V) supply */ - "DVDD", /* Digital Core (1.5V) supply */ "AVDD", /* Analog (2.8V) supply */ + "DVDD", /* Digital Core (1.5V) supply */ }; #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name) @@ -2936,8 +2936,7 @@ power_off: return ret; } -static int ov5640_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov5640_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct fwnode_handle *endpoint; @@ -3022,9 +3021,14 @@ static int ov5640_probe(struct i2c_client *client, /* request optional power down pin */ sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->pwdn_gpio)) + return PTR_ERR(sensor->pwdn_gpio); + /* request optional reset pin */ sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset_gpio)) + return PTR_ERR(sensor->reset_gpio); v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops); @@ -3050,7 +3054,7 @@ static int ov5640_probe(struct i2c_client *client, if (ret) goto entity_cleanup; - ret = v4l2_async_register_subdev(&sensor->sd); + ret = v4l2_async_register_subdev_sensor_common(&sensor->sd); if (ret) goto free_ctrls; @@ -3095,7 +3099,7 @@ static struct i2c_driver ov5640_i2c_driver = { .of_match_table = ov5640_dt_ids, }, .id_table = ov5640_id, - .probe = ov5640_probe, + .probe_new = ov5640_probe, .remove = ov5640_remove, }; diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index 124c8df04633..a6c17d15d754 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -34,10 +34,6 @@ #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> -#define OV5645_VOLTAGE_ANALOG 2800000 -#define OV5645_VOLTAGE_DIGITAL_CORE 1500000 -#define OV5645_VOLTAGE_DIGITAL_IO 1800000 - #define OV5645_SYSTEM_CTRL0 0x3008 #define OV5645_SYSTEM_CTRL0_START 0x02 #define OV5645_SYSTEM_CTRL0_STOP 0x42 @@ -45,6 +41,8 @@ #define OV5645_CHIP_ID_HIGH_BYTE 0x56 #define OV5645_CHIP_ID_LOW 0x300b #define OV5645_CHIP_ID_LOW_BYTE 0x45 +#define OV5645_IO_MIPI_CTRL00 0x300e +#define OV5645_PAD_OUTPUT00 0x3019 #define OV5645_AWB_MANUAL_CONTROL 0x3406 #define OV5645_AWB_MANUAL_ENABLE BIT(0) #define OV5645_AEC_PK_MANUAL 0x3503 @@ -55,6 +53,7 @@ #define OV5645_ISP_VFLIP BIT(2) #define OV5645_TIMING_TC_REG21 0x3821 #define OV5645_SENSOR_MIRROR BIT(1) +#define OV5645_MIPI_CTRL00 0x4800 #define OV5645_PRE_ISP_TEST_SETTING_1 0x503d #define OV5645_TEST_PATTERN_MASK 0x3 #define OV5645_SET_TEST_PATTERN(x) ((x) & OV5645_TEST_PATTERN_MASK) @@ -62,6 +61,15 @@ #define OV5645_SDE_SAT_U 0x5583 #define OV5645_SDE_SAT_V 0x5584 +/* regulator supplies */ +static const char * const ov5645_supply_name[] = { + "vdddo", /* Digital I/O (1.8V) supply */ + "vdda", /* Analog (2.8V) supply */ + "vddd", /* Digital Core (1.5V) supply */ +}; + +#define OV5645_NUM_SUPPLIES ARRAY_SIZE(ov5645_supply_name) + struct reg_value { u16 reg; u8 val; @@ -86,9 +94,7 @@ struct ov5645 { struct v4l2_rect crop; struct clk *xclk; - struct regulator *io_regulator; - struct regulator *core_regulator; - struct regulator *analog_regulator; + struct regulator_bulk_data supplies[OV5645_NUM_SUPPLIES]; const struct ov5645_mode_info *current_mode; @@ -121,7 +127,6 @@ static const struct reg_value ov5645_global_init_setting[] = { { 0x3503, 0x07 }, { 0x3002, 0x1c }, { 0x3006, 0xc3 }, - { 0x300e, 0x45 }, { 0x3017, 0x00 }, { 0x3018, 0x00 }, { 0x302e, 0x0b }, @@ -350,7 +355,10 @@ static const struct reg_value ov5645_global_init_setting[] = { { 0x3a1f, 0x14 }, { 0x0601, 0x02 }, { 0x3008, 0x42 }, - { 0x3008, 0x02 } + { 0x3008, 0x02 }, + { OV5645_IO_MIPI_CTRL00, 0x40 }, + { OV5645_MIPI_CTRL00, 0x24 }, + { OV5645_PAD_OUTPUT00, 0x70 } }; static const struct reg_value ov5645_setting_sxga[] = { @@ -533,55 +541,6 @@ static const struct ov5645_mode_info ov5645_mode_info_data[] = { }, }; -static int ov5645_regulators_enable(struct ov5645 *ov5645) -{ - int ret; - - ret = regulator_enable(ov5645->io_regulator); - if (ret < 0) { - dev_err(ov5645->dev, "set io voltage failed\n"); - return ret; - } - - ret = regulator_enable(ov5645->analog_regulator); - if (ret) { - dev_err(ov5645->dev, "set analog voltage failed\n"); - goto err_disable_io; - } - - ret = regulator_enable(ov5645->core_regulator); - if (ret) { - dev_err(ov5645->dev, "set core voltage failed\n"); - goto err_disable_analog; - } - - return 0; - -err_disable_analog: - regulator_disable(ov5645->analog_regulator); -err_disable_io: - regulator_disable(ov5645->io_regulator); - - return ret; -} - -static void ov5645_regulators_disable(struct ov5645 *ov5645) -{ - int ret; - - ret = regulator_disable(ov5645->core_regulator); - if (ret < 0) - dev_err(ov5645->dev, "core regulator disable failed\n"); - - ret = regulator_disable(ov5645->analog_regulator); - if (ret < 0) - dev_err(ov5645->dev, "analog regulator disable failed\n"); - - ret = regulator_disable(ov5645->io_regulator); - if (ret < 0) - dev_err(ov5645->dev, "io regulator disable failed\n"); -} - static int ov5645_write_reg(struct ov5645 *ov5645, u16 reg, u8 val) { u8 regbuf[3]; @@ -680,15 +639,14 @@ static int ov5645_set_power_on(struct ov5645 *ov5645) { int ret; - ret = ov5645_regulators_enable(ov5645); - if (ret < 0) { + ret = regulator_bulk_enable(OV5645_NUM_SUPPLIES, ov5645->supplies); + if (ret < 0) return ret; - } ret = clk_prepare_enable(ov5645->xclk); if (ret < 0) { dev_err(ov5645->dev, "clk prepare enable failed\n"); - ov5645_regulators_disable(ov5645); + regulator_bulk_disable(OV5645_NUM_SUPPLIES, ov5645->supplies); return ret; } @@ -708,7 +666,7 @@ static void ov5645_set_power_off(struct ov5645 *ov5645) gpiod_set_value_cansleep(ov5645->rst_gpio, 1); gpiod_set_value_cansleep(ov5645->enable_gpio, 0); clk_disable_unprepare(ov5645->xclk); - ov5645_regulators_disable(ov5645); + regulator_bulk_disable(OV5645_NUM_SUPPLIES, ov5645->supplies); } static int ov5645_s_power(struct v4l2_subdev *sd, int on) @@ -737,13 +695,9 @@ static int ov5645_s_power(struct v4l2_subdev *sd, int on) goto exit; } - ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, - OV5645_SYSTEM_CTRL0_STOP); - if (ret < 0) { - ov5645_set_power_off(ov5645); - goto exit; - } + usleep_range(500, 1000); } else { + ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x58); ov5645_set_power_off(ov5645); } } @@ -1049,11 +1003,20 @@ static int ov5645_s_stream(struct v4l2_subdev *subdev, int enable) dev_err(ov5645->dev, "could not sync v4l2 controls\n"); return ret; } + + ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x45); + if (ret < 0) + return ret; + ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, OV5645_SYSTEM_CTRL0_START); if (ret < 0) return ret; } else { + ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x40); + if (ret < 0) + return ret; + ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, OV5645_SYSTEM_CTRL0_STOP); if (ret < 0) @@ -1086,13 +1049,13 @@ static const struct v4l2_subdev_ops ov5645_subdev_ops = { .pad = &ov5645_subdev_pad_ops, }; -static int ov5645_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov5645_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device_node *endpoint; struct ov5645 *ov5645; u8 chip_id_high, chip_id_low; + unsigned int i; u32 xclk_freq; int ret; @@ -1150,47 +1113,13 @@ static int ov5645_probe(struct i2c_client *client, return ret; } - ov5645->io_regulator = devm_regulator_get(dev, "vdddo"); - if (IS_ERR(ov5645->io_regulator)) { - dev_err(dev, "cannot get io regulator\n"); - return PTR_ERR(ov5645->io_regulator); - } - - ret = regulator_set_voltage(ov5645->io_regulator, - OV5645_VOLTAGE_DIGITAL_IO, - OV5645_VOLTAGE_DIGITAL_IO); - if (ret < 0) { - dev_err(dev, "cannot set io voltage\n"); - return ret; - } - - ov5645->core_regulator = devm_regulator_get(dev, "vddd"); - if (IS_ERR(ov5645->core_regulator)) { - dev_err(dev, "cannot get core regulator\n"); - return PTR_ERR(ov5645->core_regulator); - } - - ret = regulator_set_voltage(ov5645->core_regulator, - OV5645_VOLTAGE_DIGITAL_CORE, - OV5645_VOLTAGE_DIGITAL_CORE); - if (ret < 0) { - dev_err(dev, "cannot set core voltage\n"); - return ret; - } - - ov5645->analog_regulator = devm_regulator_get(dev, "vdda"); - if (IS_ERR(ov5645->analog_regulator)) { - dev_err(dev, "cannot get analog regulator\n"); - return PTR_ERR(ov5645->analog_regulator); - } + for (i = 0; i < OV5645_NUM_SUPPLIES; i++) + ov5645->supplies[i].supply = ov5645_supply_name[i]; - ret = regulator_set_voltage(ov5645->analog_regulator, - OV5645_VOLTAGE_ANALOG, - OV5645_VOLTAGE_ANALOG); - if (ret < 0) { - dev_err(dev, "cannot set analog voltage\n"); + ret = devm_regulator_bulk_get(dev, OV5645_NUM_SUPPLIES, + ov5645->supplies); + if (ret < 0) return ret; - } ov5645->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); if (IS_ERR(ov5645->enable_gpio)) { @@ -1355,7 +1284,7 @@ static struct i2c_driver ov5645_i2c_driver = { .of_match_table = of_match_ptr(ov5645_of_match), .name = "ov5645", }, - .probe = ov5645_probe, + .probe_new = ov5645_probe, .remove = ov5645_remove, .id_table = ov5645_id, }; diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 4589631798c9..e7d2e5b4ad4b 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -547,8 +547,7 @@ static int ov5647_parse_dt(struct device_node *np) return ret; } -static int ov5647_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov5647_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ov5647 *sensor; @@ -644,7 +643,7 @@ static struct i2c_driver ov5647_driver = { .of_match_table = of_match_ptr(ov5647_of_match), .name = SENSOR_NAME, }, - .probe = ov5647_probe, + .probe_new = ov5647_probe, .remove = ov5647_remove, .id_table = ov5647_id, }; diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c new file mode 100644 index 000000000000..1ae252378799 --- /dev/null +++ b/drivers/media/i2c/ov5675.c @@ -0,0 +1,1183 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Intel Corporation. + +#include <asm/unaligned.h> +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define OV5675_REG_VALUE_08BIT 1 +#define OV5675_REG_VALUE_16BIT 2 +#define OV5675_REG_VALUE_24BIT 3 + +#define OV5675_LINK_FREQ_450MHZ 450000000ULL +#define OV5675_SCLK 90000000LL +#define OV5675_MCLK 19200000 +#define OV5675_DATA_LANES 2 +#define OV5675_RGB_DEPTH 10 + +#define OV5675_REG_CHIP_ID 0x300a +#define OV5675_CHIP_ID 0x5675 + +#define OV5675_REG_MODE_SELECT 0x0100 +#define OV5675_MODE_STANDBY 0x00 +#define OV5675_MODE_STREAMING 0x01 + +/* vertical-timings from sensor */ +#define OV5675_REG_VTS 0x380e +#define OV5675_VTS_30FPS 0x07e4 +#define OV5675_VTS_30FPS_MIN 0x07e4 +#define OV5675_VTS_MAX 0x7fff + +/* horizontal-timings from sensor */ +#define OV5675_REG_HTS 0x380c + +/* Exposure controls from sensor */ +#define OV5675_REG_EXPOSURE 0x3500 +#define OV5675_EXPOSURE_MIN 4 +#define OV5675_EXPOSURE_MAX_MARGIN 4 +#define OV5675_EXPOSURE_STEP 1 + +/* Analog gain controls from sensor */ +#define OV5675_REG_ANALOG_GAIN 0x3508 +#define OV5675_ANAL_GAIN_MIN 128 +#define OV5675_ANAL_GAIN_MAX 2047 +#define OV5675_ANAL_GAIN_STEP 1 + +/* Digital gain controls from sensor */ +#define OV5675_REG_MWB_R_GAIN 0x5019 +#define OV5675_REG_MWB_G_GAIN 0x501b +#define OV5675_REG_MWB_B_GAIN 0x501d +#define OV5675_DGTL_GAIN_MIN 0 +#define OV5675_DGTL_GAIN_MAX 4095 +#define OV5675_DGTL_GAIN_STEP 1 +#define OV5675_DGTL_GAIN_DEFAULT 1024 + +/* Test Pattern Control */ +#define OV5675_REG_TEST_PATTERN 0x4503 +#define OV5675_TEST_PATTERN_ENABLE BIT(7) +#define OV5675_TEST_PATTERN_BAR_SHIFT 2 + +#define to_ov5675(_sd) container_of(_sd, struct ov5675, sd) + +enum { + OV5675_LINK_FREQ_900MBPS, +}; + +struct ov5675_reg { + u16 address; + u8 val; +}; + +struct ov5675_reg_list { + u32 num_of_regs; + const struct ov5675_reg *regs; +}; + +struct ov5675_link_freq_config { + const struct ov5675_reg_list reg_list; +}; + +struct ov5675_mode { + /* Frame width in pixels */ + u32 width; + + /* Frame height in pixels */ + u32 height; + + /* Horizontal timining size */ + u32 hts; + + /* Default vertical timining size */ + u32 vts_def; + + /* Min vertical timining size */ + u32 vts_min; + + /* Link frequency needed for this resolution */ + u32 link_freq_index; + + /* Sensor register settings for this resolution */ + const struct ov5675_reg_list reg_list; +}; + +static const struct ov5675_reg mipi_data_rate_900mbps[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x0300, 0x04}, + {0x0302, 0x8d}, + {0x0303, 0x00}, + {0x030d, 0x26}, +}; + +static const struct ov5675_reg mode_2592x1944_regs[] = { + {0x3002, 0x21}, + {0x3107, 0x23}, + {0x3501, 0x20}, + {0x3503, 0x0c}, + {0x3508, 0x03}, + {0x3509, 0x00}, + {0x3600, 0x66}, + {0x3602, 0x30}, + {0x3610, 0xa5}, + {0x3612, 0x93}, + {0x3620, 0x80}, + {0x3642, 0x0e}, + {0x3661, 0x00}, + {0x3662, 0x10}, + {0x3664, 0xf3}, + {0x3665, 0x9e}, + {0x3667, 0xa5}, + {0x366e, 0x55}, + {0x366f, 0x55}, + {0x3670, 0x11}, + {0x3671, 0x11}, + {0x3672, 0x11}, + {0x3673, 0x11}, + {0x3714, 0x24}, + {0x371a, 0x3e}, + {0x3733, 0x10}, + {0x3734, 0x00}, + {0x373d, 0x24}, + {0x3764, 0x20}, + {0x3765, 0x20}, + {0x3766, 0x12}, + {0x37a1, 0x14}, + {0x37a8, 0x1c}, + {0x37ab, 0x0f}, + {0x37c2, 0x04}, + {0x37cb, 0x00}, + {0x37cc, 0x00}, + {0x37cd, 0x00}, + {0x37ce, 0x00}, + {0x37d8, 0x02}, + {0x37d9, 0x08}, + {0x37dc, 0x04}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0xb3}, + {0x3808, 0x0a}, + {0x3809, 0x20}, + {0x380a, 0x07}, + {0x380b, 0x98}, + {0x380c, 0x02}, + {0x380d, 0xee}, + {0x380e, 0x07}, + {0x380f, 0xe4}, + {0x3811, 0x10}, + {0x3813, 0x0d}, + {0x3814, 0x01}, + {0x3815, 0x01}, + {0x3816, 0x01}, + {0x3817, 0x01}, + {0x381e, 0x02}, + {0x3820, 0x88}, + {0x3821, 0x01}, + {0x3832, 0x04}, + {0x3c80, 0x01}, + {0x3c82, 0x00}, + {0x3c83, 0xc8}, + {0x3c8c, 0x0f}, + {0x3c8d, 0xa0}, + {0x3c90, 0x07}, + {0x3c91, 0x00}, + {0x3c92, 0x00}, + {0x3c93, 0x00}, + {0x3c94, 0xd0}, + {0x3c95, 0x50}, + {0x3c96, 0x35}, + {0x3c97, 0x00}, + {0x4001, 0xe0}, + {0x4008, 0x02}, + {0x4009, 0x0d}, + {0x400f, 0x80}, + {0x4013, 0x02}, + {0x4040, 0x00}, + {0x4041, 0x07}, + {0x404c, 0x50}, + {0x404e, 0x20}, + {0x4500, 0x06}, + {0x4503, 0x00}, + {0x450a, 0x04}, + {0x4809, 0x04}, + {0x480c, 0x12}, + {0x4819, 0x70}, + {0x4825, 0x32}, + {0x4826, 0x32}, + {0x482a, 0x06}, + {0x4833, 0x08}, + {0x4837, 0x0d}, + {0x5000, 0x77}, + {0x5b00, 0x01}, + {0x5b01, 0x10}, + {0x5b02, 0x01}, + {0x5b03, 0xdb}, + {0x5b05, 0x6c}, + {0x5e10, 0xfc}, + {0x3500, 0x00}, + {0x3501, 0x3E}, + {0x3502, 0x60}, + {0x3503, 0x08}, + {0x3508, 0x04}, + {0x3509, 0x00}, + {0x3832, 0x48}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x4003, 0x40}, + {0x3107, 0x01}, + {0x3c80, 0x08}, + {0x3c83, 0xb1}, + {0x3c8c, 0x10}, + {0x3c8d, 0x00}, + {0x3c90, 0x00}, + {0x3c94, 0x00}, + {0x3c95, 0x00}, + {0x3c96, 0x00}, + {0x37cb, 0x09}, + {0x37cc, 0x15}, + {0x37cd, 0x1f}, + {0x37ce, 0x1f}, +}; + +static const struct ov5675_reg mode_1296x972_regs[] = { + {0x3002, 0x21}, + {0x3107, 0x23}, + {0x3501, 0x20}, + {0x3503, 0x0c}, + {0x3508, 0x03}, + {0x3509, 0x00}, + {0x3600, 0x66}, + {0x3602, 0x30}, + {0x3610, 0xa5}, + {0x3612, 0x93}, + {0x3620, 0x80}, + {0x3642, 0x0e}, + {0x3661, 0x00}, + {0x3662, 0x08}, + {0x3664, 0xf3}, + {0x3665, 0x9e}, + {0x3667, 0xa5}, + {0x366e, 0x55}, + {0x366f, 0x55}, + {0x3670, 0x11}, + {0x3671, 0x11}, + {0x3672, 0x11}, + {0x3673, 0x11}, + {0x3714, 0x28}, + {0x371a, 0x3e}, + {0x3733, 0x10}, + {0x3734, 0x00}, + {0x373d, 0x24}, + {0x3764, 0x20}, + {0x3765, 0x20}, + {0x3766, 0x12}, + {0x37a1, 0x14}, + {0x37a8, 0x1c}, + {0x37ab, 0x0f}, + {0x37c2, 0x14}, + {0x37cb, 0x00}, + {0x37cc, 0x00}, + {0x37cd, 0x00}, + {0x37ce, 0x00}, + {0x37d8, 0x02}, + {0x37d9, 0x04}, + {0x37dc, 0x04}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0xf4}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x06}, + {0x3807, 0xb3}, + {0x3808, 0x05}, + {0x3809, 0x00}, + {0x380a, 0x02}, + {0x380b, 0xd0}, + {0x380c, 0x02}, + {0x380d, 0xee}, + {0x380e, 0x07}, + {0x380f, 0xe4}, + {0x3811, 0x10}, + {0x3813, 0x09}, + {0x3814, 0x03}, + {0x3815, 0x01}, + {0x3816, 0x03}, + {0x3817, 0x01}, + {0x381e, 0x02}, + {0x3820, 0x8b}, + {0x3821, 0x01}, + {0x3832, 0x04}, + {0x3c80, 0x01}, + {0x3c82, 0x00}, + {0x3c83, 0xc8}, + {0x3c8c, 0x0f}, + {0x3c8d, 0xa0}, + {0x3c90, 0x07}, + {0x3c91, 0x00}, + {0x3c92, 0x00}, + {0x3c93, 0x00}, + {0x3c94, 0xd0}, + {0x3c95, 0x50}, + {0x3c96, 0x35}, + {0x3c97, 0x00}, + {0x4001, 0xe0}, + {0x4008, 0x00}, + {0x4009, 0x07}, + {0x400f, 0x80}, + {0x4013, 0x02}, + {0x4040, 0x00}, + {0x4041, 0x03}, + {0x404c, 0x50}, + {0x404e, 0x20}, + {0x4500, 0x06}, + {0x4503, 0x00}, + {0x450a, 0x04}, + {0x4809, 0x04}, + {0x480c, 0x12}, + {0x4819, 0x70}, + {0x4825, 0x32}, + {0x4826, 0x32}, + {0x482a, 0x06}, + {0x4833, 0x08}, + {0x4837, 0x0d}, + {0x5000, 0x77}, + {0x5b00, 0x01}, + {0x5b01, 0x10}, + {0x5b02, 0x01}, + {0x5b03, 0xdb}, + {0x5b05, 0x6c}, + {0x5e10, 0xfc}, + {0x3500, 0x00}, + {0x3501, 0x1F}, + {0x3502, 0x20}, + {0x3503, 0x08}, + {0x3508, 0x04}, + {0x3509, 0x00}, + {0x3832, 0x48}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x4003, 0x40}, + {0x3107, 0x01}, + {0x3c80, 0x08}, + {0x3c83, 0xb1}, + {0x3c8c, 0x10}, + {0x3c8d, 0x00}, + {0x3c90, 0x00}, + {0x3c94, 0x00}, + {0x3c95, 0x00}, + {0x3c96, 0x00}, + {0x37cb, 0x09}, + {0x37cc, 0x15}, + {0x37cd, 0x1f}, + {0x37ce, 0x1f}, +}; + +static const char * const ov5675_test_pattern_menu[] = { + "Disabled", + "Standard Color Bar", + "Top-Bottom Darker Color Bar", + "Right-Left Darker Color Bar", + "Bottom-Top Darker Color Bar" +}; + +static const s64 link_freq_menu_items[] = { + OV5675_LINK_FREQ_450MHZ, +}; + +static const struct ov5675_link_freq_config link_freq_configs[] = { + [OV5675_LINK_FREQ_900MBPS] = { + .reg_list = { + .num_of_regs = ARRAY_SIZE(mipi_data_rate_900mbps), + .regs = mipi_data_rate_900mbps, + } + } +}; + +static const struct ov5675_mode supported_modes[] = { + { + .width = 2592, + .height = 1944, + .hts = 1500, + .vts_def = OV5675_VTS_30FPS, + .vts_min = OV5675_VTS_30FPS_MIN, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2592x1944_regs), + .regs = mode_2592x1944_regs, + }, + .link_freq_index = OV5675_LINK_FREQ_900MBPS, + }, + { + .width = 1296, + .height = 972, + .hts = 1500, + .vts_def = OV5675_VTS_30FPS, + .vts_min = OV5675_VTS_30FPS_MIN, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1296x972_regs), + .regs = mode_1296x972_regs, + }, + .link_freq_index = OV5675_LINK_FREQ_900MBPS, + } +}; + +struct ov5675 { + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; + + /* V4L2 Controls */ + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *exposure; + + /* Current mode */ + const struct ov5675_mode *cur_mode; + + /* To serialize asynchronus callbacks */ + struct mutex mutex; + + /* Streaming on/off */ + bool streaming; +}; + +static u64 to_pixel_rate(u32 f_index) +{ + u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OV5675_DATA_LANES; + + do_div(pixel_rate, OV5675_RGB_DEPTH); + + return pixel_rate; +} + +static u64 to_pixels_per_line(u32 hts, u32 f_index) +{ + u64 ppl = hts * to_pixel_rate(f_index); + + do_div(ppl, OV5675_SCLK); + + return ppl; +} + +static int ov5675_read_reg(struct ov5675 *ov5675, u16 reg, u16 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + struct i2c_msg msgs[2]; + u8 addr_buf[2]; + u8 data_buf[4] = {0}; + int ret; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(addr_buf); + msgs[0].buf = addr_buf; + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_buf[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +static int ov5675_write_reg(struct ov5675 *ov5675, u16 reg, u16 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + u8 buf[6]; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << 8 * (4 - len), buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +static int ov5675_write_reg_list(struct ov5675 *ov5675, + const struct ov5675_reg_list *r_list) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + unsigned int i; + int ret; + + for (i = 0; i < r_list->num_of_regs; i++) { + ret = ov5675_write_reg(ov5675, r_list->regs[i].address, 1, + r_list->regs[i].val); + if (ret) { + dev_err_ratelimited(&client->dev, + "failed to write reg 0x%4.4x. error = %d", + r_list->regs[i].address, ret); + return ret; + } + } + + return 0; +} + +static int ov5675_update_digital_gain(struct ov5675 *ov5675, u32 d_gain) +{ + int ret; + + ret = ov5675_write_reg(ov5675, OV5675_REG_MWB_R_GAIN, + OV5675_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; + + ret = ov5675_write_reg(ov5675, OV5675_REG_MWB_G_GAIN, + OV5675_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; + + return ov5675_write_reg(ov5675, OV5675_REG_MWB_B_GAIN, + OV5675_REG_VALUE_16BIT, d_gain); +} + +static int ov5675_test_pattern(struct ov5675 *ov5675, u32 pattern) +{ + if (pattern) + pattern = (pattern - 1) << OV5675_TEST_PATTERN_BAR_SHIFT | + OV5675_TEST_PATTERN_ENABLE; + + return ov5675_write_reg(ov5675, OV5675_REG_TEST_PATTERN, + OV5675_REG_VALUE_08BIT, pattern); +} + +static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov5675 *ov5675 = container_of(ctrl->handler, + struct ov5675, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + s64 exposure_max; + int ret = 0; + + /* Propagate change of current control to all related controls */ + if (ctrl->id == V4L2_CID_VBLANK) { + /* Update max exposure while meeting expected vblanking */ + exposure_max = (ov5675->cur_mode->height + ctrl->val - + OV5675_EXPOSURE_MAX_MARGIN) / 2; + __v4l2_ctrl_modify_range(ov5675->exposure, + ov5675->exposure->minimum, + exposure_max, ov5675->exposure->step, + exposure_max); + } + + /* V4L2 controls values will be applied only when power is already up */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = ov5675_write_reg(ov5675, OV5675_REG_ANALOG_GAIN, + OV5675_REG_VALUE_16BIT, ctrl->val); + break; + + case V4L2_CID_DIGITAL_GAIN: + ret = ov5675_update_digital_gain(ov5675, ctrl->val); + break; + + case V4L2_CID_EXPOSURE: + /* 3 least significant bits of expsoure are fractional part */ + ret = ov5675_write_reg(ov5675, OV5675_REG_EXPOSURE, + OV5675_REG_VALUE_24BIT, ctrl->val << 3); + break; + + case V4L2_CID_VBLANK: + ret = ov5675_write_reg(ov5675, OV5675_REG_VTS, + OV5675_REG_VALUE_16BIT, + ov5675->cur_mode->height + ctrl->val + + 10); + break; + + case V4L2_CID_TEST_PATTERN: + ret = ov5675_test_pattern(ov5675, ctrl->val); + break; + + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov5675_ctrl_ops = { + .s_ctrl = ov5675_set_ctrl, +}; + +static int ov5675_init_controls(struct ov5675 *ov5675) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + s64 exposure_max, h_blank; + int ret; + + ctrl_hdlr = &ov5675->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); + if (ret) + return ret; + + ctrl_hdlr->lock = &ov5675->mutex; + ov5675->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq_menu_items) - 1, + 0, link_freq_menu_items); + if (ov5675->link_freq) + ov5675->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ov5675->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_PIXEL_RATE, 0, + to_pixel_rate(OV5675_LINK_FREQ_900MBPS), + 1, + to_pixel_rate(OV5675_LINK_FREQ_900MBPS)); + ov5675->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_VBLANK, + ov5675->cur_mode->vts_min - ov5675->cur_mode->height, + OV5675_VTS_MAX - ov5675->cur_mode->height, 1, + ov5675->cur_mode->vts_def - ov5675->cur_mode->height); + h_blank = to_pixels_per_line(ov5675->cur_mode->hts, + ov5675->cur_mode->link_freq_index) - ov5675->cur_mode->width; + ov5675->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_HBLANK, h_blank, h_blank, 1, + h_blank); + if (ov5675->hblank) + ov5675->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + OV5675_ANAL_GAIN_MIN, OV5675_ANAL_GAIN_MAX, + OV5675_ANAL_GAIN_STEP, OV5675_ANAL_GAIN_MIN); + v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + OV5675_DGTL_GAIN_MIN, OV5675_DGTL_GAIN_MAX, + OV5675_DGTL_GAIN_STEP, OV5675_DGTL_GAIN_DEFAULT); + exposure_max = (ov5675->cur_mode->vts_def - + OV5675_EXPOSURE_MAX_MARGIN) / 2; + ov5675->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_EXPOSURE, + OV5675_EXPOSURE_MIN, exposure_max, + OV5675_EXPOSURE_STEP, + exposure_max); + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov5675_test_pattern_menu) - 1, + 0, 0, ov5675_test_pattern_menu); + if (ctrl_hdlr->error) + return ctrl_hdlr->error; + + ov5675->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +static void ov5675_update_pad_format(const struct ov5675_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->width = mode->width; + fmt->height = mode->height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->field = V4L2_FIELD_NONE; +} + +static int ov5675_start_streaming(struct ov5675 *ov5675) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + const struct ov5675_reg_list *reg_list; + int link_freq_index, ret; + + link_freq_index = ov5675->cur_mode->link_freq_index; + reg_list = &link_freq_configs[link_freq_index].reg_list; + ret = ov5675_write_reg_list(ov5675, reg_list); + if (ret) { + dev_err(&client->dev, "failed to set plls"); + return ret; + } + + reg_list = &ov5675->cur_mode->reg_list; + ret = ov5675_write_reg_list(ov5675, reg_list); + if (ret) { + dev_err(&client->dev, "failed to set mode"); + return ret; + } + + ret = __v4l2_ctrl_handler_setup(ov5675->sd.ctrl_handler); + if (ret) + return ret; + + ret = ov5675_write_reg(ov5675, OV5675_REG_MODE_SELECT, + OV5675_REG_VALUE_08BIT, OV5675_MODE_STREAMING); + if (ret) { + dev_err(&client->dev, "failed to set stream"); + return ret; + } + + return 0; +} + +static void ov5675_stop_streaming(struct ov5675 *ov5675) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + + if (ov5675_write_reg(ov5675, OV5675_REG_MODE_SELECT, + OV5675_REG_VALUE_08BIT, OV5675_MODE_STANDBY)) + dev_err(&client->dev, "failed to set stream"); +} + +static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov5675 *ov5675 = to_ov5675(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (ov5675->streaming == enable) + return 0; + + mutex_lock(&ov5675->mutex); + if (enable) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + mutex_unlock(&ov5675->mutex); + return ret; + } + + ret = ov5675_start_streaming(ov5675); + if (ret) { + enable = 0; + ov5675_stop_streaming(ov5675); + pm_runtime_put(&client->dev); + } + } else { + ov5675_stop_streaming(ov5675); + pm_runtime_put(&client->dev); + } + + ov5675->streaming = enable; + mutex_unlock(&ov5675->mutex); + + return ret; +} + +static int __maybe_unused ov5675_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5675 *ov5675 = to_ov5675(sd); + + mutex_lock(&ov5675->mutex); + if (ov5675->streaming) + ov5675_stop_streaming(ov5675); + + mutex_unlock(&ov5675->mutex); + + return 0; +} + +static int __maybe_unused ov5675_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5675 *ov5675 = to_ov5675(sd); + int ret; + + mutex_lock(&ov5675->mutex); + if (ov5675->streaming) { + ret = ov5675_start_streaming(ov5675); + if (ret) { + ov5675->streaming = false; + ov5675_stop_streaming(ov5675); + mutex_unlock(&ov5675->mutex); + return ret; + } + } + + mutex_unlock(&ov5675->mutex); + + return 0; +} + +static int ov5675_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov5675 *ov5675 = to_ov5675(sd); + const struct ov5675_mode *mode; + s32 vblank_def, h_blank; + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), width, + height, fmt->format.width, + fmt->format.height); + + mutex_lock(&ov5675->mutex); + ov5675_update_pad_format(mode, &fmt->format); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; + } else { + ov5675->cur_mode = mode; + __v4l2_ctrl_s_ctrl(ov5675->link_freq, mode->link_freq_index); + __v4l2_ctrl_s_ctrl_int64(ov5675->pixel_rate, + to_pixel_rate(mode->link_freq_index)); + + /* Update limits and set FPS to default */ + vblank_def = mode->vts_def - mode->height; + __v4l2_ctrl_modify_range(ov5675->vblank, + mode->vts_min - mode->height, + OV5675_VTS_MAX - mode->height, 1, + vblank_def); + __v4l2_ctrl_s_ctrl(ov5675->vblank, vblank_def); + h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) - + mode->width; + __v4l2_ctrl_modify_range(ov5675->hblank, h_blank, h_blank, 1, + h_blank); + } + + mutex_unlock(&ov5675->mutex); + + return 0; +} + +static int ov5675_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov5675 *ov5675 = to_ov5675(sd); + + mutex_lock(&ov5675->mutex); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + fmt->format = *v4l2_subdev_get_try_format(&ov5675->sd, cfg, + fmt->pad); + else + ov5675_update_pad_format(ov5675->cur_mode, &fmt->format); + + mutex_unlock(&ov5675->mutex); + + return 0; +} + +static int ov5675_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int ov5675_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int ov5675_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ov5675 *ov5675 = to_ov5675(sd); + + mutex_lock(&ov5675->mutex); + ov5675_update_pad_format(&supported_modes[0], + v4l2_subdev_get_try_format(sd, fh->pad, 0)); + mutex_unlock(&ov5675->mutex); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov5675_video_ops = { + .s_stream = ov5675_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ov5675_pad_ops = { + .set_fmt = ov5675_set_format, + .get_fmt = ov5675_get_format, + .enum_mbus_code = ov5675_enum_mbus_code, + .enum_frame_size = ov5675_enum_frame_size, +}; + +static const struct v4l2_subdev_ops ov5675_subdev_ops = { + .video = &ov5675_video_ops, + .pad = &ov5675_pad_ops, +}; + +static const struct media_entity_operations ov5675_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops ov5675_internal_ops = { + .open = ov5675_open, +}; + +static int ov5675_identify_module(struct ov5675 *ov5675) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + int ret; + u32 val; + + ret = ov5675_read_reg(ov5675, OV5675_REG_CHIP_ID, + OV5675_REG_VALUE_24BIT, &val); + if (ret) + return ret; + + if (val != OV5675_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x", + OV5675_CHIP_ID, val); + return -ENXIO; + } + + return 0; +} + +static int ov5675_check_hwcfg(struct device *dev) +{ + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + u32 mclk; + int ret; + unsigned int i, j; + + if (!fwnode) + return -ENXIO; + + ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); + + if (ret) { + dev_err(dev, "can't get clock frequency"); + return ret; + } + + if (mclk != OV5675_MCLK) { + dev_err(dev, "external clock %d is not supported", mclk); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV5675_DATA_LANES) { + dev_err(dev, "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto check_hwcfg_error; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequencies defined"); + ret = -EINVAL; + goto check_hwcfg_error; + } + + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { + for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { + if (link_freq_menu_items[i] == + bus_cfg.link_frequencies[j]) + break; + } + + if (j == bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequency %lld supported", + link_freq_menu_items[i]); + ret = -EINVAL; + goto check_hwcfg_error; + } + } + +check_hwcfg_error: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int ov5675_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5675 *ov5675 = to_ov5675(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(&client->dev); + mutex_destroy(&ov5675->mutex); + + return 0; +} + +static int ov5675_probe(struct i2c_client *client) +{ + struct ov5675 *ov5675; + int ret; + + ret = ov5675_check_hwcfg(&client->dev); + if (ret) { + dev_err(&client->dev, "failed to check HW configuration: %d", + ret); + return ret; + } + + ov5675 = devm_kzalloc(&client->dev, sizeof(*ov5675), GFP_KERNEL); + if (!ov5675) + return -ENOMEM; + + v4l2_i2c_subdev_init(&ov5675->sd, client, &ov5675_subdev_ops); + ret = ov5675_identify_module(ov5675); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + return ret; + } + + mutex_init(&ov5675->mutex); + ov5675->cur_mode = &supported_modes[0]; + ret = ov5675_init_controls(ov5675); + if (ret) { + dev_err(&client->dev, "failed to init controls: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + + ov5675->sd.internal_ops = &ov5675_internal_ops; + ov5675->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov5675->sd.entity.ops = &ov5675_subdev_entity_ops; + ov5675->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ov5675->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&ov5675->sd.entity, 1, &ov5675->pad); + if (ret) { + dev_err(&client->dev, "failed to init entity pads: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + + ret = v4l2_async_register_subdev_sensor_common(&ov5675->sd); + if (ret < 0) { + dev_err(&client->dev, "failed to register V4L2 subdev: %d", + ret); + goto probe_error_media_entity_cleanup; + } + + /* + * Device is already turned on by i2c-core with ACPI domain PM. + * Enable runtime PM and turn off the device. + */ + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + + return 0; + +probe_error_media_entity_cleanup: + media_entity_cleanup(&ov5675->sd.entity); + +probe_error_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(ov5675->sd.ctrl_handler); + mutex_destroy(&ov5675->mutex); + + return ret; +} + +static const struct dev_pm_ops ov5675_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ov5675_suspend, ov5675_resume) +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id ov5675_acpi_ids[] = { + {"OVTI5675"}, + {} +}; + +MODULE_DEVICE_TABLE(acpi, ov5675_acpi_ids); +#endif + +static struct i2c_driver ov5675_i2c_driver = { + .driver = { + .name = "ov5675", + .pm = &ov5675_pm_ops, + .acpi_match_table = ACPI_PTR(ov5675_acpi_ids), + }, + .probe_new = ov5675_probe, + .remove = ov5675_remove, +}; + +module_i2c_driver(ov5675_i2c_driver); + +MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>"); +MODULE_DESCRIPTION("OmniVision OV5675 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index e65a94353175..34b7046d9702 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -823,9 +823,6 @@ static int ov5695_set_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; -#else - mutex_unlock(&ov5695->mutex); - return -ENOTTY; #endif } else { ov5695->cur_mode = mode; @@ -856,7 +853,7 @@ static int ov5695_get_fmt(struct v4l2_subdev *sd, fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); #else mutex_unlock(&ov5695->mutex); - return -ENOTTY; + return -EINVAL; #endif } else { fmt->format.width = mode->width; diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 53385c277792..b42b289faaef 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -1110,10 +1110,8 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); *mbus_fmt = format->format; - return 0; -#else - return -ENOTTY; #endif + return 0; } ret = ov7670_try_fmt_internal(sd, &format->format, &info->fmt, &info->wsize); @@ -1146,7 +1144,7 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd, format->format = *mbus_fmt; return 0; #else - return -ENOTTY; + return -EINVAL; #endif } else { format->format = info->format; diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 2e9a758736a1..2cc6a678069a 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -1352,8 +1352,7 @@ static const struct v4l2_subdev_ops ov772x_subdev_ops = { * i2c_driver function */ -static int ov772x_probe(struct i2c_client *client, - const struct i2c_device_id *did) +static int ov772x_probe(struct i2c_client *client) { struct ov772x_priv *priv; int ret; @@ -1486,7 +1485,7 @@ static struct i2c_driver ov772x_i2c_driver = { .name = "ov772x", .of_match_table = ov772x_of_match, }, - .probe = ov772x_probe, + .probe_new = ov772x_probe, .remove = ov772x_remove, .id_table = ov772x_id, }; diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 70bb870b1d08..732655fe4ba3 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -827,13 +827,9 @@ static int ov7740_set_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); *mbus_fmt = format->format; - +#endif mutex_unlock(&ov7740->mutex); return 0; -#else - ret = -ENOTTY; - goto error; -#endif } ret = ov7740_try_fmt_internal(sd, &format->format, &ovfmt, &fsize); @@ -868,7 +864,7 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd, format->format = *mbus_fmt; ret = 0; #else - ret = -ENOTTY; + ret = -EINVAL; #endif } else { format->format = ov7740->format; @@ -1066,8 +1062,7 @@ static const struct regmap_config ov7740_regmap_config = { .max_register = OV7740_MAX_REGISTER, }; -static int ov7740_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov7740_probe(struct i2c_client *client) { struct ov7740 *ov7740; struct v4l2_subdev *sd; @@ -1229,7 +1224,7 @@ static struct i2c_driver ov7740_i2c_driver = { .pm = &ov7740_pm_ops, .of_match_table = of_match_ptr(ov7740_of_match), }, - .probe = ov7740_probe, + .probe_new = ov7740_probe, .remove = ov7740_remove, .id_table = ov7740_id, }; diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index cd347d6b7b9d..8655842af275 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -1106,7 +1106,10 @@ static int ov8856_check_hwcfg(struct device *dev) if (!fwnode) return -ENXIO; - fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); + ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); + if (ret) + return ret; + if (mclk != OV8856_MCLK) { dev_err(dev, "external clock %d is not supported", mclk); return -EINVAL; diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 30ab2225fbd0..4fe68aa55789 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -703,6 +703,11 @@ static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain) for (m = 6; m >= 0; m--) if (gain >= (1 << m) * 16) break; + + /* Sanity check: don't adjust the gain with a negative value */ + if (m < 0) + return -EINVAL; + rgain = (gain - ((1 << m) * 16)) / (1 << m); rgain |= (((1 << m) - 1) << 4); @@ -1485,8 +1490,7 @@ out: return ret; } -static int ov965x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov965x_probe(struct i2c_client *client) { const struct ov9650_platform_data *pdata = client->dev.platform_data; struct v4l2_subdev *sd; @@ -1613,7 +1617,7 @@ static struct i2c_driver ov965x_i2c_driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(ov965x_of_match), }, - .probe = ov965x_probe, + .probe_new = ov965x_probe, .remove = ov965x_remove, .id_table = ov965x_id, }; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 7633aebd8c06..5b4c4a3547c9 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1650,8 +1650,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state) return 0; } -static int s5c73m3_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int s5c73m3_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct v4l2_subdev *sd; @@ -1806,7 +1805,7 @@ static struct i2c_driver s5c73m3_i2c_driver = { .of_match_table = of_match_ptr(s5c73m3_of_match), .name = DRIVER_NAME, }, - .probe = s5c73m3_probe, + .probe_new = s5c73m3_probe, .remove = s5c73m3_remove, .id_table = s5c73m3_id, }; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 8e6de06b3e72..cdfe008ba39f 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -1946,8 +1946,7 @@ static int s5k5baf_configure_regulators(struct s5k5baf *state) return ret; } -static int s5k5baf_probe(struct i2c_client *c, - const struct i2c_device_id *id) +static int s5k5baf_probe(struct i2c_client *c) { struct s5k5baf *state; int ret; @@ -2046,7 +2045,7 @@ static struct i2c_driver s5k5baf_i2c_driver = { .of_match_table = s5k5baf_of_match, .name = S5K5BAF_DRIVER_NAME }, - .probe = s5k5baf_probe, + .probe_new = s5k5baf_probe, .remove = s5k5baf_remove, .id_table = s5k5baf_id, }; diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index 3b7721f81be2..bc6cc5a558db 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -275,8 +275,7 @@ static const struct v4l2_subdev_ops s5k6a3_subdev_ops = { .pad = &s5k6a3_pad_ops, }; -static int s5k6a3_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int s5k6a3_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct s5k6a3 *sensor; @@ -378,7 +377,7 @@ static struct i2c_driver s5k6a3_driver = { .of_match_table = of_match_ptr(s5k6a3_of_match), .name = S5K6A3_DRV_NAME, }, - .probe = s5k6a3_probe, + .probe_new = s5k6a3_probe, .remove = s5k6a3_remove, .id_table = s5k6a3_ids, }; diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 2d78e846d822..9adf8e034e7d 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2847,8 +2847,7 @@ out_err: return NULL; } -static int smiapp_probe(struct i2c_client *client, - const struct i2c_device_id *devid) +static int smiapp_probe(struct i2c_client *client) { struct smiapp_sensor *sensor; struct smiapp_hwconfig *hwcfg = smiapp_get_hwconfig(&client->dev); @@ -3172,7 +3171,7 @@ static struct i2c_driver smiapp_i2c_driver = { .name = SMIAPP_NAME, .pm = &smiapp_pm_ops, }, - .probe = smiapp_probe, + .probe_new = smiapp_probe, .remove = smiapp_remove, .id_table = smiapp_id_table, }; diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index bc2e35e5ce61..dbbab75f135e 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -2026,8 +2026,7 @@ static inline int tc358743_probe_of(struct tc358743_state *state) } #endif -static int tc358743_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tc358743_probe(struct i2c_client *client) { static struct v4l2_dv_timings default_timing = V4L2_DV_BT_CEA_640X480P59_94; @@ -2222,7 +2221,7 @@ static struct i2c_driver tc358743_driver = { .name = "tc358743", .of_match_table = of_match_ptr(tc358743_of_match), }, - .probe = tc358743_probe, + .probe_new = tc358743_probe, .remove = tc358743_remove, .id_table = tc358743_id, }; diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index a62ede096636..5e68182001ec 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -2691,7 +2691,13 @@ static int tda1997x_probe(struct i2c_client *client, } ret = 0x34 + ((io_read(sd, REG_SLAVE_ADDR)>>4) & 0x03); - state->client_cec = i2c_new_dummy(client->adapter, ret); + state->client_cec = devm_i2c_new_dummy_device(&client->dev, + client->adapter, ret); + if (IS_ERR(state->client_cec)) { + ret = PTR_ERR(state->client_cec); + goto err_free_mutex; + } + v4l_info(client, "CEC slave address 0x%02x\n", ret); ret = tda1997x_core_init(sd); @@ -2798,7 +2804,6 @@ static int tda1997x_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(&state->hdl); regulator_bulk_disable(TDA1997X_NUM_SUPPLIES, state->supplies); - i2c_unregister_device(state->client_cec); cancel_delayed_work(&state->delayed_work_enable_hpd); mutex_destroy(&state->page_lock); mutex_destroy(&state->lock); diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c index f5ee28058ea2..c52fe84cba1b 100644 --- a/drivers/media/i2c/ths8200.c +++ b/drivers/media/i2c/ths8200.c @@ -436,8 +436,7 @@ static const struct v4l2_subdev_ops ths8200_ops = { .pad = &ths8200_pad_ops, }; -static int ths8200_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ths8200_probe(struct i2c_client *client) { struct ths8200_state *state; struct v4l2_subdev *sd; @@ -502,7 +501,7 @@ static struct i2c_driver ths8200_driver = { .name = "ths8200", .of_match_table = of_match_ptr(ths8200_of_match), }, - .probe = ths8200_probe, + .probe_new = ths8200_probe, .remove = ths8200_remove, .id_table = ths8200_id, }; diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index eaddd977ba40..edad49cebcdf 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1636,11 +1636,13 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) dev_err(decoder->sd.dev, "missing type property in node %pOFn\n", child); + of_node_put(child); goto err_connector; } if (input_type >= TVP5150_INPUT_NUM) { ret = -EINVAL; + of_node_put(child); goto err_connector; } @@ -1651,6 +1653,7 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) dev_err(decoder->sd.dev, "input %s with same type already exists\n", input->name); + of_node_put(child); ret = -EINVAL; goto err_connector; } @@ -1672,6 +1675,7 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) dev_err(decoder->sd.dev, "missing label property in node %pOFn\n", child); + of_node_put(child); goto err_connector; } @@ -1691,8 +1695,7 @@ static const char * const tvp5150_test_patterns[2] = { "Black screen" }; -static int tvp5150_probe(struct i2c_client *c, - const struct i2c_device_id *id) +static int tvp5150_probe(struct i2c_client *c) { struct tvp5150 *core; struct v4l2_subdev *sd; @@ -1841,7 +1844,7 @@ static struct i2c_driver tvp5150_driver = { .of_match_table = of_match_ptr(tvp5150_of_match), .name = "tvp5150", }, - .probe = tvp5150_probe, + .probe_new = tvp5150_probe, .remove = tvp5150_remove, .id_table = tvp5150_id, }; diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 1b8175cab017..de313b1306da 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -930,7 +930,7 @@ done: * Returns zero when successful, -EINVAL if register read fails or * -EIO if i2c access is not available. */ -static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) +static int tvp7002_probe(struct i2c_client *c) { struct tvp7002_config *pdata = tvp7002_get_pdata(c); struct v4l2_subdev *sd; @@ -1075,7 +1075,7 @@ static struct i2c_driver tvp7002_driver = { .of_match_table = of_match_ptr(tvp7002_of_match), .name = TVP7002_MODULE_NAME, }, - .probe = tvp7002_probe, + .probe_new = tvp7002_probe, .remove = tvp7002_remove, .id_table = tvp7002_id, }; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 612d1c0010c1..a359da7773a9 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -503,77 +503,65 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); packed pixel formats must come first */ static const struct bttv_format formats[] = { { - .name = "8 bpp, gray", .fourcc = V4L2_PIX_FMT_GREY, .btformat = BT848_COLOR_FMT_Y8, .depth = 8, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "8 bpp, dithered color", .fourcc = V4L2_PIX_FMT_HI240, .btformat = BT848_COLOR_FMT_RGB8, .depth = 8, .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER, },{ - .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555, .btformat = BT848_COLOR_FMT_RGB15, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "15 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB555X, .btformat = BT848_COLOR_FMT_RGB15, .btswap = 0x03, /* byteswap */ .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "16 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB565, .btformat = BT848_COLOR_FMT_RGB16, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "16 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB565X, .btformat = BT848_COLOR_FMT_RGB16, .btswap = 0x03, /* byteswap */ .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "24 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR24, .btformat = BT848_COLOR_FMT_RGB24, .depth = 24, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "32 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR32, .btformat = BT848_COLOR_FMT_RGB32, .depth = 32, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "32 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB32, .btformat = BT848_COLOR_FMT_RGB32, .btswap = 0x0f, /* byte+word swap */ .depth = 32, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .btformat = BT848_COLOR_FMT_YUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .btformat = BT848_COLOR_FMT_YUY2, .btswap = 0x03, /* byteswap */ .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "4:2:2, planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV422P, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 16, @@ -581,7 +569,6 @@ static const struct bttv_format formats[] = { .hshift = 1, .vshift = 0, },{ - .name = "4:2:0, planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -589,7 +576,6 @@ static const struct bttv_format formats[] = { .hshift = 1, .vshift = 1, },{ - .name = "4:2:0, planar, Y-Cr-Cb", .fourcc = V4L2_PIX_FMT_YVU420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -597,7 +583,6 @@ static const struct bttv_format formats[] = { .hshift = 1, .vshift = 1, },{ - .name = "4:1:1, planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV411P, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 12, @@ -605,7 +590,6 @@ static const struct bttv_format formats[] = { .hshift = 2, .vshift = 0, },{ - .name = "4:1:0, planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -613,7 +597,6 @@ static const struct bttv_format formats[] = { .hshift = 2, .vshift = 2, },{ - .name = "4:1:0, planar, Y-Cr-Cb", .fourcc = V4L2_PIX_FMT_YVU410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -621,7 +604,6 @@ static const struct bttv_format formats[] = { .hshift = 2, .vshift = 2, },{ - .name = "raw scanlines", .fourcc = -1, .btformat = BT848_COLOR_FMT_RAW, .depth = 8, @@ -2500,7 +2482,6 @@ static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f) return -EINVAL; f->pixelformat = formats[i].fourcc; - strscpy(f->description, formats[i].name, sizeof(f->description)); return i; } diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index 9adfac4d5187..492bc85c2700 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -84,7 +84,7 @@ static void ir_enltv_handle_key(struct bttv *btv) data = ir_extract_bits(gpio, ir->mask_keycode); /* Check if it is keyup */ - keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0; + keyup = (gpio & ir->mask_keyup) ? 1UL << 31 : 0; if ((ir->last_gpio & 0x7f) != data) { dprintk("gpio=0x%x code=%d | %s\n", @@ -95,7 +95,7 @@ static void ir_enltv_handle_key(struct bttv *btv) if (keyup) rc_keyup(ir->dev); } else { - if ((ir->last_gpio & 1 << 31) == keyup) + if ((ir->last_gpio & 1UL << 31) == keyup) return; dprintk("(cnt) gpio=0x%x code=%d | %s\n", diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c index 6b59ca337c7f..fc8708047be8 100644 --- a/drivers/media/pci/bt8xx/bttv-risc.c +++ b/drivers/media/pci/bt8xx/bttv-risc.c @@ -699,9 +699,9 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - dprintk("%d: buffer field: %s format: %s size: %dx%d\n", + dprintk("%d: buffer field: %s format: 0x%08x size: %dx%d\n", btv->c.nr, v4l2_field_names[buf->vb.field], - buf->fmt->name, buf->vb.width, buf->vb.height); + buf->fmt->fourcc, buf->vb.width, buf->vb.height); /* packed pixel modes */ if (buf->fmt->flags & FORMAT_FLAGS_PACKED) { @@ -860,9 +860,9 @@ bttv_overlay_risc(struct bttv *btv, struct bttv_buffer *buf) { /* check interleave, bottom+top fields */ - dprintk("%d: overlay fields: %s format: %s size: %dx%d\n", + dprintk("%d: overlay fields: %s format: 0x%08x size: %dx%d\n", btv->c.nr, v4l2_field_names[buf->vb.field], - fmt->name, ov->w.width, ov->w.height); + fmt->fourcc, ov->w.width, ov->w.height); /* calculate geometry */ bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index b159d6ddbfcf..4abf43657846 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -99,7 +99,6 @@ struct bttv_tvnorm { extern const struct bttv_tvnorm bttv_tvnorms[]; struct bttv_format { - char *name; int fourcc; /* video4linux 2 */ int btformat; /* BT848_COLOR_FMT_* */ int btswap; /* BT848_COLOR_CTL_* */ diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c index 64df9d491941..02ebd43e672e 100644 --- a/drivers/media/pci/bt8xx/dvb-bt8xx.c +++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c @@ -393,7 +393,7 @@ static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, }; -static struct dst_config dst_config = { +static const struct dst_config dst_config = { .demod_address = 0x55, }; diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 4885e833c052..0695078ef812 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -186,20 +186,16 @@ void cobalt_pcie_status_show(struct cobalt *cobalt) { struct pci_dev *pci_dev = cobalt->pci_dev; struct pci_dev *pci_bus_dev = cobalt->pci_dev->bus->self; - int offset; - int bus_offset; u32 capa; u16 stat, ctrl; - offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); - bus_offset = pci_find_capability(pci_bus_dev, PCI_CAP_ID_EXP); - if (!offset || !bus_offset) + if (!pci_is_pcie(pci_dev) || !pci_is_pcie(pci_bus_dev)) return; /* Device */ - pci_read_config_dword(pci_dev, offset + PCI_EXP_DEVCAP, &capa); - pci_read_config_word(pci_dev, offset + PCI_EXP_DEVCTL, &ctrl); - pci_read_config_word(pci_dev, offset + PCI_EXP_DEVSTA, &stat); + pcie_capability_read_dword(pci_dev, PCI_EXP_DEVCAP, &capa); + pcie_capability_read_word(pci_dev, PCI_EXP_DEVCTL, &ctrl); + pcie_capability_read_word(pci_dev, PCI_EXP_DEVSTA, &stat); cobalt_info("PCIe device capability 0x%08x: Max payload %d\n", capa, get_payload_size(capa & PCI_EXP_DEVCAP_PAYLOAD)); cobalt_info("PCIe device control 0x%04x: Max payload %d. Max read request %d\n", @@ -209,9 +205,9 @@ void cobalt_pcie_status_show(struct cobalt *cobalt) cobalt_info("PCIe device status 0x%04x\n", stat); /* Link */ - pci_read_config_dword(pci_dev, offset + PCI_EXP_LNKCAP, &capa); - pci_read_config_word(pci_dev, offset + PCI_EXP_LNKCTL, &ctrl); - pci_read_config_word(pci_dev, offset + PCI_EXP_LNKSTA, &stat); + pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &capa); + pcie_capability_read_word(pci_dev, PCI_EXP_LNKCTL, &ctrl); + pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &stat); cobalt_info("PCIe link capability 0x%08x: %s per lane and %u lanes\n", capa, get_link_speed(capa), (capa & PCI_EXP_LNKCAP_MLW) >> 4); @@ -221,15 +217,15 @@ void cobalt_pcie_status_show(struct cobalt *cobalt) (stat & PCI_EXP_LNKSTA_NLW) >> 4); /* Bus */ - pci_read_config_dword(pci_bus_dev, bus_offset + PCI_EXP_LNKCAP, &capa); + pcie_capability_read_dword(pci_bus_dev, PCI_EXP_LNKCAP, &capa); cobalt_info("PCIe bus link capability 0x%08x: %s per lane and %u lanes\n", capa, get_link_speed(capa), (capa & PCI_EXP_LNKCAP_MLW) >> 4); /* Slot */ - pci_read_config_dword(pci_dev, offset + PCI_EXP_SLTCAP, &capa); - pci_read_config_word(pci_dev, offset + PCI_EXP_SLTCTL, &ctrl); - pci_read_config_word(pci_dev, offset + PCI_EXP_SLTSTA, &stat); + pcie_capability_read_dword(pci_dev, PCI_EXP_SLTCAP, &capa); + pcie_capability_read_word(pci_dev, PCI_EXP_SLTCTL, &ctrl); + pcie_capability_read_word(pci_dev, PCI_EXP_SLTSTA, &stat); cobalt_info("PCIe slot capability 0x%08x\n", capa); cobalt_info("PCIe slot control 0x%04x\n", ctrl); cobalt_info("PCIe slot status 0x%04x\n", stat); @@ -238,26 +234,22 @@ void cobalt_pcie_status_show(struct cobalt *cobalt) static unsigned pcie_link_get_lanes(struct cobalt *cobalt) { struct pci_dev *pci_dev = cobalt->pci_dev; - unsigned offset; u16 link; - offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); - if (!offset) + if (!pci_is_pcie(pci_dev)) return 0; - pci_read_config_word(pci_dev, offset + PCI_EXP_LNKSTA, &link); + pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &link); return (link & PCI_EXP_LNKSTA_NLW) >> 4; } static unsigned pcie_bus_link_get_lanes(struct cobalt *cobalt) { struct pci_dev *pci_dev = cobalt->pci_dev->bus->self; - unsigned offset; u32 link; - offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); - if (!offset) + if (!pci_is_pcie(pci_dev)) return 0; - pci_read_config_dword(pci_dev, offset + PCI_EXP_LNKCAP, &link); + pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &link); return (link & PCI_EXP_LNKCAP_MLW) >> 4; } @@ -592,7 +584,7 @@ static int cobalt_subdevs_hsma_init(struct cobalt *cobalt) .cec_clk = 12000000, }; static struct i2c_board_info adv7511_info = { - .type = "adv7511", + .type = "adv7511-v4l2", .addr = 0x39, /* 0x39 or 0x3d */ .platform_data = &adv7511_pdata, }; diff --git a/drivers/media/pci/cobalt/cobalt-driver.h b/drivers/media/pci/cobalt/cobalt-driver.h index 429bee4ef79c..bca68572b324 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.h +++ b/drivers/media/pci/cobalt/cobalt-driver.h @@ -11,6 +11,7 @@ #ifndef COBALT_DRIVER_H #define COBALT_DRIVER_H +#include <linux/bitops.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/spinlock.h> @@ -61,37 +62,37 @@ #define COBALT_CLK 50000000 /* System status register */ -#define COBALT_SYSSTAT_DIP0_MSK (1 << 0) -#define COBALT_SYSSTAT_DIP1_MSK (1 << 1) -#define COBALT_SYSSTAT_HSMA_PRSNTN_MSK (1 << 2) -#define COBALT_SYSSTAT_FLASH_RDYBSYN_MSK (1 << 3) -#define COBALT_SYSSTAT_VI0_5V_MSK (1 << 4) -#define COBALT_SYSSTAT_VI0_INT1_MSK (1 << 5) -#define COBALT_SYSSTAT_VI0_INT2_MSK (1 << 6) -#define COBALT_SYSSTAT_VI0_LOST_DATA_MSK (1 << 7) -#define COBALT_SYSSTAT_VI1_5V_MSK (1 << 8) -#define COBALT_SYSSTAT_VI1_INT1_MSK (1 << 9) -#define COBALT_SYSSTAT_VI1_INT2_MSK (1 << 10) -#define COBALT_SYSSTAT_VI1_LOST_DATA_MSK (1 << 11) -#define COBALT_SYSSTAT_VI2_5V_MSK (1 << 12) -#define COBALT_SYSSTAT_VI2_INT1_MSK (1 << 13) -#define COBALT_SYSSTAT_VI2_INT2_MSK (1 << 14) -#define COBALT_SYSSTAT_VI2_LOST_DATA_MSK (1 << 15) -#define COBALT_SYSSTAT_VI3_5V_MSK (1 << 16) -#define COBALT_SYSSTAT_VI3_INT1_MSK (1 << 17) -#define COBALT_SYSSTAT_VI3_INT2_MSK (1 << 18) -#define COBALT_SYSSTAT_VI3_LOST_DATA_MSK (1 << 19) -#define COBALT_SYSSTAT_VIHSMA_5V_MSK (1 << 20) -#define COBALT_SYSSTAT_VIHSMA_INT1_MSK (1 << 21) -#define COBALT_SYSSTAT_VIHSMA_INT2_MSK (1 << 22) -#define COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK (1 << 23) -#define COBALT_SYSSTAT_VOHSMA_INT1_MSK (1 << 24) -#define COBALT_SYSSTAT_VOHSMA_PLL_LOCKED_MSK (1 << 25) -#define COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK (1 << 26) -#define COBALT_SYSSTAT_AUD_PLL_LOCKED_MSK (1 << 28) -#define COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK (1 << 29) -#define COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK (1 << 30) -#define COBALT_SYSSTAT_PCIE_SMBCLK_MSK (1 << 31) +#define COBALT_SYSSTAT_DIP0_MSK BIT(0) +#define COBALT_SYSSTAT_DIP1_MSK BIT(1) +#define COBALT_SYSSTAT_HSMA_PRSNTN_MSK BIT(2) +#define COBALT_SYSSTAT_FLASH_RDYBSYN_MSK BIT(3) +#define COBALT_SYSSTAT_VI0_5V_MSK BIT(4) +#define COBALT_SYSSTAT_VI0_INT1_MSK BIT(5) +#define COBALT_SYSSTAT_VI0_INT2_MSK BIT(6) +#define COBALT_SYSSTAT_VI0_LOST_DATA_MSK BIT(7) +#define COBALT_SYSSTAT_VI1_5V_MSK BIT(8) +#define COBALT_SYSSTAT_VI1_INT1_MSK BIT(9) +#define COBALT_SYSSTAT_VI1_INT2_MSK BIT(10) +#define COBALT_SYSSTAT_VI1_LOST_DATA_MSK BIT(11) +#define COBALT_SYSSTAT_VI2_5V_MSK BIT(12) +#define COBALT_SYSSTAT_VI2_INT1_MSK BIT(13) +#define COBALT_SYSSTAT_VI2_INT2_MSK BIT(14) +#define COBALT_SYSSTAT_VI2_LOST_DATA_MSK BIT(15) +#define COBALT_SYSSTAT_VI3_5V_MSK BIT(16) +#define COBALT_SYSSTAT_VI3_INT1_MSK BIT(17) +#define COBALT_SYSSTAT_VI3_INT2_MSK BIT(18) +#define COBALT_SYSSTAT_VI3_LOST_DATA_MSK BIT(19) +#define COBALT_SYSSTAT_VIHSMA_5V_MSK BIT(20) +#define COBALT_SYSSTAT_VIHSMA_INT1_MSK BIT(21) +#define COBALT_SYSSTAT_VIHSMA_INT2_MSK BIT(22) +#define COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK BIT(23) +#define COBALT_SYSSTAT_VOHSMA_INT1_MSK BIT(24) +#define COBALT_SYSSTAT_VOHSMA_PLL_LOCKED_MSK BIT(25) +#define COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK BIT(26) +#define COBALT_SYSSTAT_AUD_PLL_LOCKED_MSK BIT(28) +#define COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK BIT(29) +#define COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK BIT(30) +#define COBALT_SYSSTAT_PCIE_SMBCLK_MSK BIT(31) /* Cobalt memory map */ #define COBALT_I2C_0_BASE 0x0 diff --git a/drivers/media/pci/cobalt/cobalt-flash.c b/drivers/media/pci/cobalt/cobalt-flash.c index ef96e0f956d2..1d3c64b4cf6d 100644 --- a/drivers/media/pci/cobalt/cobalt-flash.c +++ b/drivers/media/pci/cobalt/cobalt-flash.c @@ -69,7 +69,7 @@ static void flash_copy_to(struct map_info *map, unsigned long to, pr_info("%s: offset 0x%x: length %zu\n", __func__, dest, len); while (len) { - u16 data = 0xffff; + u16 data; do { data = *src << (8 * (dest & 1)); diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index 39dabd4da60f..c5207501d5e0 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -688,15 +688,12 @@ static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh, { switch (f->index) { case 0: - strscpy(f->description, "YUV 4:2:2", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_YUYV; break; case 1: - strscpy(f->description, "RGB24", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_RGB24; break; case 2: - strscpy(f->description, "RGB32", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_BGR32; break; default: @@ -788,7 +785,6 @@ static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh, pix->sizeimage = pix->bytesperline * pix->height; pix->field = V4L2_FIELD_NONE; - pix->priv = 0; return 0; } @@ -893,11 +889,9 @@ static int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh, { switch (f->index) { case 0: - strscpy(f->description, "YUV 4:2:2", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_YUYV; break; case 1: - strscpy(f->description, "RGB32", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_BGR32; break; default: diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index d9ffc9c359ca..85f3e7307538 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -78,7 +78,7 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal) return 0; } for (i = 0; i < 32; i++) { - if ((1 << i) & set) + if (BIT(i) & set) return 1 << i; } return 0; diff --git a/drivers/media/pci/cx18/cx18-mailbox.c b/drivers/media/pci/cx18/cx18-mailbox.c index 967ae2939099..162480ec68ca 100644 --- a/drivers/media/pci/cx18/cx18-mailbox.c +++ b/drivers/media/pci/cx18/cx18-mailbox.c @@ -6,7 +6,7 @@ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ -#include <stdarg.h> +#include <linux/bitops.h> #include "cx18-driver.h" #include "cx18-io.h" diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 82f96a4091ac..2327fe612610 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1339,7 +1339,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, "MPEG", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; return 0; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index b254473db9a3..8098b15493de 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -67,7 +67,6 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); #define FORMAT_FLAGS_PACKED 0x01 static struct cx23885_fmt formats[] = { { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .flags = FORMAT_FLAGS_PACKED, @@ -411,9 +410,9 @@ static int buffer_prepare(struct vb2_buffer *vb) default: BUG(); } - dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp 0x%08x - dma=0x%08lx\n", buf, buf->vb.vb2_buf.index, - dev->width, dev->height, dev->fmt->depth, dev->fmt->name, + dev->width, dev->height, dev->fmt->depth, dev->fmt->fourcc, (unsigned long)buf->risc.dma); return 0; } @@ -647,8 +646,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (unlikely(f->index >= ARRAY_SIZE(formats))) return -EINVAL; - strscpy(f->description, formats[f->index].name, - sizeof(f->description)); f->pixelformat = formats[f->index].fourcc; return 0; diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 9da66fdd5a0d..a95a2e4c6a0d 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -127,7 +127,6 @@ V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) struct cx23885_fmt { - char *name; u32 fourcc; /* v4l2 format id */ int depth; int flags; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index de7641170478..a10261da0db6 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -35,12 +35,10 @@ MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); static const struct cx25821_fmt formats[] = { { - .name = "4:1:1, packed, Y41P", .fourcc = V4L2_PIX_FMT_Y41P, .depth = 12, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .flags = FORMAT_FLAGS_PACKED, @@ -215,9 +213,9 @@ static int cx25821_buffer_prepare(struct vb2_buffer *vb) break; } - dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp 0x%08x - dma=0x%08lx\n", buf, buf->vb.vb2_buf.index, chan->width, chan->height, - chan->fmt->depth, chan->fmt->name, + chan->fmt->depth, chan->fmt->fourcc, (unsigned long)buf->risc.dma); return ret; @@ -311,7 +309,6 @@ static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (unlikely(f->index >= ARRAY_SIZE(formats))) return -EINVAL; - strscpy(f->description, formats[f->index].name, sizeof(f->description)); f->pixelformat = formats[f->index].fourcc; return 0; diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 47dbaae78509..017307984094 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -83,7 +83,6 @@ #define VID_CHANNEL_NUM 8 struct cx25821_fmt { - char *name; u32 fourcc; /* v4l2 format id */ int depth; int flags; diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 200d68827073..d3da7f4297af 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -805,9 +805,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, "MPEG", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; - f->flags = V4L2_FMT_FLAG_COMPRESSED; return 0; } diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index e59a74514c7c..dcc0f02aeb70 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -69,62 +69,52 @@ MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); static const struct cx8800_fmt formats[] = { { - .name = "8 bpp, gray", .fourcc = V4L2_PIX_FMT_GREY, .cxformat = ColorFormatY8, .depth = 8, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555, .cxformat = ColorFormatRGB15, .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "15 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB555X, .cxformat = ColorFormatRGB15 | ColorFormatBSWAP, .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "16 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB565, .cxformat = ColorFormatRGB16, .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "16 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB565X, .cxformat = ColorFormatRGB16 | ColorFormatBSWAP, .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "24 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR24, .cxformat = ColorFormatRGB24, .depth = 24, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "32 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR32, .cxformat = ColorFormatRGB32, .depth = 32, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "32 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB32, .cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP, .depth = 32, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .cxformat = ColorFormatYUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .cxformat = ColorFormatYUY2 | ColorFormatBSWAP, .depth = 16, @@ -489,9 +479,9 @@ static int buffer_prepare(struct vb2_buffer *vb) break; } dprintk(2, - "[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.vb2_buf.index, - core->width, core->height, dev->fmt->depth, dev->fmt->name, + "[%p/%d] %s - %dx%d %dbpp 0x%08x - dma=0x%08lx\n", + buf, buf->vb.vb2_buf.index, __func__, + core->width, core->height, dev->fmt->depth, dev->fmt->fourcc, (unsigned long)buf->risc.dma); return 0; } @@ -829,7 +819,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (unlikely(f->index >= ARRAY_SIZE(formats))) return -EINVAL; - strscpy(f->description, formats[f->index].name, sizeof(f->description)); f->pixelformat = formats[f->index].fourcc; return 0; diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index a70a50dc3edf..744a22328ebc 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -99,7 +99,6 @@ static inline unsigned int norm_maxh(v4l2_std_id norm) /* static data */ struct cx8800_fmt { - const char *name; u32 fourcc; /* v4l2 format id */ int depth; int flags; diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index b4cdda50e742..7480f0d3ad0f 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -306,7 +306,6 @@ static int dt3155_enum_fmt_vid_cap(struct file *filp, if (f->index) return -EINVAL; f->pixelformat = V4L2_PIX_FMT_GREY; - strscpy(f->description, "8-bit Greyscale", sizeof(f->description)); return 0; } diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index c1d133e17e4b..1adfdc7ab0db 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1475,57 +1475,66 @@ static const struct v4l2_async_notifier_operations cio2_async_ops = { .complete = cio2_notifier_complete, }; -static int cio2_fwnode_parse(struct device *dev, - struct v4l2_fwnode_endpoint *vep, - struct v4l2_async_subdev *asd) +static int cio2_parse_firmware(struct cio2_device *cio2) { - struct sensor_async_subdev *s_asd = - container_of(asd, struct sensor_async_subdev, asd); + unsigned int i; + int ret; - if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) { - dev_err(dev, "Only CSI2 bus type is currently supported\n"); - return -EINVAL; - } + for (i = 0; i < CIO2_NUM_PORTS; i++) { + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct sensor_async_subdev *s_asd = NULL; + struct fwnode_handle *ep; - s_asd->csi2.port = vep->base.port; - s_asd->csi2.lanes = vep->bus.mipi_csi2.num_data_lanes; + ep = fwnode_graph_get_endpoint_by_id( + dev_fwnode(&cio2->pci_dev->dev), i, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); - return 0; -} + if (!ep) + continue; -static int cio2_notifier_init(struct cio2_device *cio2) -{ - int ret; + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + if (ret) + goto err_parse; - v4l2_async_notifier_init(&cio2->notifier); + s_asd = kzalloc(sizeof(*s_asd), GFP_KERNEL); + if (!s_asd) { + ret = -ENOMEM; + goto err_parse; + } - ret = v4l2_async_notifier_parse_fwnode_endpoints( - &cio2->pci_dev->dev, &cio2->notifier, - sizeof(struct sensor_async_subdev), - cio2_fwnode_parse); - if (ret < 0) - return ret; + s_asd->csi2.port = vep.base.port; + s_asd->csi2.lanes = vep.bus.mipi_csi2.num_data_lanes; - if (list_empty(&cio2->notifier.asd_list)) - return -ENODEV; /* no endpoint */ + ret = v4l2_async_notifier_add_fwnode_remote_subdev( + &cio2->notifier, ep, &s_asd->asd); + if (ret) + goto err_parse; + + fwnode_handle_put(ep); + + continue; +err_parse: + fwnode_handle_put(ep); + kfree(s_asd); + return ret; + } + + /* + * Proceed even without sensors connected to allow the device to + * suspend. + */ cio2->notifier.ops = &cio2_async_ops; ret = v4l2_async_notifier_register(&cio2->v4l2_dev, &cio2->notifier); - if (ret) { + if (ret) dev_err(&cio2->pci_dev->dev, "failed to register async notifier : %d\n", ret); - v4l2_async_notifier_cleanup(&cio2->notifier); - } return ret; } -static void cio2_notifier_exit(struct cio2_device *cio2) -{ - v4l2_async_notifier_unregister(&cio2->notifier); - v4l2_async_notifier_cleanup(&cio2->notifier); -} - /**************** Queue initialization ****************/ static const struct media_entity_operations cio2_media_ops = { .link_validate = v4l2_subdev_link_validate, @@ -1809,17 +1818,18 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, if (r) goto fail_v4l2_device_unregister; + v4l2_async_notifier_init(&cio2->notifier); + /* Register notifier for subdevices we care */ - r = cio2_notifier_init(cio2); - /* Proceed without sensors connected to allow the device to suspend. */ - if (r && r != -ENODEV) - goto fail_cio2_queue_exit; + r = cio2_parse_firmware(cio2); + if (r) + goto fail_clean_notifier; r = devm_request_irq(&pci_dev->dev, pci_dev->irq, cio2_irq, IRQF_SHARED, CIO2_NAME, cio2); if (r) { dev_err(&pci_dev->dev, "failed to request IRQ (%d)\n", r); - goto fail; + goto fail_clean_notifier; } pm_runtime_put_noidle(&pci_dev->dev); @@ -1827,9 +1837,9 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, return 0; -fail: - cio2_notifier_exit(cio2); -fail_cio2_queue_exit: +fail_clean_notifier: + v4l2_async_notifier_unregister(&cio2->notifier); + v4l2_async_notifier_cleanup(&cio2->notifier); cio2_queues_exit(cio2); fail_v4l2_device_unregister: v4l2_device_unregister(&cio2->v4l2_dev); @@ -1848,7 +1858,8 @@ static void cio2_pci_remove(struct pci_dev *pci_dev) struct cio2_device *cio2 = pci_get_drvdata(pci_dev); media_device_unregister(&cio2->media_dev); - cio2_notifier_exit(cio2); + v4l2_async_notifier_unregister(&cio2->notifier); + v4l2_async_notifier_cleanup(&cio2->notifier); cio2_queues_exit(cio2); cio2_fbpt_exit_dummy(cio2); v4l2_device_unregister(&cio2->v4l2_dev); @@ -2000,8 +2011,7 @@ static int __maybe_unused cio2_suspend(struct device *dev) static int __maybe_unused cio2_resume(struct device *dev) { - struct pci_dev *pci_dev = to_pci_dev(dev); - struct cio2_device *cio2 = pci_get_drvdata(pci_dev); + struct cio2_device *cio2 = dev_get_drvdata(dev); int r = 0; struct cio2_queue *q = cio2->cur_queue; diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index dd727098daf4..3f3f40ea890b 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -910,7 +910,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) /* check which i2c devices are actually found */ for (i = 0; i < 32; i++) { - u32 device = 1 << i; + u32 device = BIT(i); if (!(device & hw)) continue; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 5595f6a274e7..137853944e46 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -73,8 +73,8 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal) return 0; } for (i = 0; i < 32; i++) { - if ((1 << i) & set) - return 1 << i; + if (BIT(i) & set) + return BIT(i); } return 0; } diff --git a/drivers/media/pci/ivtv/ivtv-irq.h b/drivers/media/pci/ivtv/ivtv-irq.h index 7d2f45e2b83c..b8b0703a1c82 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.h +++ b/drivers/media/pci/ivtv/ivtv-irq.h @@ -10,20 +10,20 @@ #ifndef IVTV_IRQ_H #define IVTV_IRQ_H -#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) -#define IVTV_IRQ_ENC_EOS (0x1 << 30) -#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) -#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) -#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) -#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25) -#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) -#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) -#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) -#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) -#define IVTV_IRQ_DMA_ERR (0x1 << 18) -#define IVTV_IRQ_DMA_WRITE (0x1 << 17) -#define IVTV_IRQ_DMA_READ (0x1 << 16) -#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) +#define IVTV_IRQ_ENC_START_CAP BIT(31) +#define IVTV_IRQ_ENC_EOS BIT(30) +#define IVTV_IRQ_ENC_VBI_CAP BIT(29) +#define IVTV_IRQ_ENC_VIM_RST BIT(28) +#define IVTV_IRQ_ENC_DMA_COMPLETE BIT(27) +#define IVTV_IRQ_ENC_PIO_COMPLETE BIT(25) +#define IVTV_IRQ_DEC_AUD_MODE_CHG BIT(24) +#define IVTV_IRQ_DEC_DATA_REQ BIT(22) +#define IVTV_IRQ_DEC_DMA_COMPLETE BIT(20) +#define IVTV_IRQ_DEC_VBI_RE_INSERT BIT(19) +#define IVTV_IRQ_DMA_ERR BIT(18) +#define IVTV_IRQ_DMA_WRITE BIT(17) +#define IVTV_IRQ_DMA_READ BIT(16) +#define IVTV_IRQ_DEC_VSYNC BIT(10) /* IRQ Masks */ #define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\ diff --git a/drivers/media/pci/ivtv/ivtv-mailbox.c b/drivers/media/pci/ivtv/ivtv-mailbox.c index 8393675c3f46..d3fdaaa903f1 100644 --- a/drivers/media/pci/ivtv/ivtv-mailbox.c +++ b/drivers/media/pci/ivtv/ivtv-mailbox.c @@ -10,8 +10,6 @@ #include "ivtv-driver.h" #include "ivtv-mailbox.h" -#include <stdarg.h> - /* Firmware mailbox flags*/ #define IVTV_MBOX_FIRMWARE_DONE 0x00000004 #define IVTV_MBOX_DRIVER_DONE 0x00000002 diff --git a/drivers/media/pci/mantis/mantis_reg.h b/drivers/media/pci/mantis/mantis_reg.h index 67a80e42b5c7..a1e66ef6ac2f 100644 --- a/drivers/media/pci/mantis/mantis_reg.h +++ b/drivers/media/pci/mantis/mantis_reg.h @@ -14,44 +14,44 @@ #define MANTIS_INT_MASK 0x04 #define MANTIS_INT_RISCSTAT (0x0f << 28) -#define MANTIS_INT_RISCEN (0x01 << 27) -#define MANTIS_INT_I2CRACK (0x01 << 26) +#define MANTIS_INT_RISCEN BIT(27) +#define MANTIS_INT_I2CRACK BIT(26) /* #define MANTIS_INT_GPIF (0xff << 12) */ -#define MANTIS_INT_PCMCIA7 (0x01 << 19) -#define MANTIS_INT_PCMCIA6 (0x01 << 18) -#define MANTIS_INT_PCMCIA5 (0x01 << 17) -#define MANTIS_INT_PCMCIA4 (0x01 << 16) -#define MANTIS_INT_PCMCIA3 (0x01 << 15) -#define MANTIS_INT_PCMCIA2 (0x01 << 14) -#define MANTIS_INT_PCMCIA1 (0x01 << 13) -#define MANTIS_INT_PCMCIA0 (0x01 << 12) -#define MANTIS_INT_IRQ1 (0x01 << 11) -#define MANTIS_INT_IRQ0 (0x01 << 10) -#define MANTIS_INT_OCERR (0x01 << 8) -#define MANTIS_INT_PABORT (0x01 << 7) -#define MANTIS_INT_RIPERR (0x01 << 6) -#define MANTIS_INT_PPERR (0x01 << 5) -#define MANTIS_INT_FTRGT (0x01 << 3) -#define MANTIS_INT_RISCI (0x01 << 1) -#define MANTIS_INT_I2CDONE (0x01 << 0) +#define MANTIS_INT_PCMCIA7 BIT(19) +#define MANTIS_INT_PCMCIA6 BIT(18) +#define MANTIS_INT_PCMCIA5 BIT(17) +#define MANTIS_INT_PCMCIA4 BIT(16) +#define MANTIS_INT_PCMCIA3 BIT(15) +#define MANTIS_INT_PCMCIA2 BIT(14) +#define MANTIS_INT_PCMCIA1 BIT(13) +#define MANTIS_INT_PCMCIA0 BIT(12) +#define MANTIS_INT_IRQ1 BIT(11) +#define MANTIS_INT_IRQ0 BIT(10) +#define MANTIS_INT_OCERR BIT(8) +#define MANTIS_INT_PABORT BIT(7) +#define MANTIS_INT_RIPERR BIT(6) +#define MANTIS_INT_PPERR BIT(5) +#define MANTIS_INT_FTRGT BIT(3) +#define MANTIS_INT_RISCI BIT(1) +#define MANTIS_INT_I2CDONE BIT(0) /* DMA */ #define MANTIS_DMA_CTL 0x08 #define MANTIS_GPIF_RD (0xff << 24) #define MANTIS_GPIF_WR (0xff << 16) -#define MANTIS_CPU_DO (0x01 << 10) -#define MANTIS_DRV_DO (0x01 << 9) -#define MANTIS_I2C_RD (0x01 << 7) -#define MANTIS_I2C_WR (0x01 << 6) -#define MANTIS_DCAP_MODE (0x01 << 5) +#define MANTIS_CPU_DO BIT(10) +#define MANTIS_DRV_DO BIT(9) +#define MANTIS_I2C_RD BIT(7) +#define MANTIS_I2C_WR BIT(6) +#define MANTIS_DCAP_MODE BIT(5) #define MANTIS_FIFO_TP_4 (0x00 << 3) #define MANTIS_FIFO_TP_8 (0x01 << 3) #define MANTIS_FIFO_TP_16 (0x02 << 3) -#define MANTIS_FIFO_EN (0x01 << 2) -#define MANTIS_DCAP_EN (0x01 << 1) -#define MANTIS_RISC_EN (0x01 << 0) +#define MANTIS_FIFO_EN BIT(2) +#define MANTIS_DCAP_EN BIT(1) +#define MANTIS_RISC_EN BIT(0) /* DEBUG */ #define MANTIS_DEBUGREG 0x0c @@ -68,8 +68,8 @@ #define MANTIS_I2C_RATE_2 (0x01 << 6) #define MANTIS_I2C_RATE_3 (0x02 << 6) #define MANTIS_I2C_RATE_4 (0x03 << 6) -#define MANTIS_I2C_STOP (0x01 << 5) -#define MANTIS_I2C_PGMODE (0x01 << 3) +#define MANTIS_I2C_STOP BIT(5) +#define MANTIS_I2C_PGMODE BIT(3) /* DATA */ #define MANTIS_CMD_DATA_R1 0x20 @@ -85,77 +85,77 @@ #define MANTIS_CMD_DATA_4 (0xff << 0) #define MANTIS_CONTROL 0x28 -#define MANTIS_DET (0x01 << 7) -#define MANTIS_DAT_CF_EN (0x01 << 6) +#define MANTIS_DET BIT(7) +#define MANTIS_DAT_CF_EN BIT(6) #define MANTIS_ACS (0x03 << 4) -#define MANTIS_VCCEN (0x01 << 3) -#define MANTIS_BYPASS (0x01 << 2) -#define MANTIS_MRST (0x01 << 1) -#define MANTIS_CRST_INT (0x01 << 0) +#define MANTIS_VCCEN BIT(3) +#define MANTIS_BYPASS BIT(2) +#define MANTIS_MRST BIT(1) +#define MANTIS_CRST_INT BIT(0) #define MANTIS_GPIF_CFGSLA 0x84 #define MANTIS_GPIF_WAITSMPL (0x07 << 28) -#define MANTIS_GPIF_BYTEADDRSUB (0x01 << 25) -#define MANTIS_GPIF_WAITPOL (0x01 << 24) +#define MANTIS_GPIF_BYTEADDRSUB BIT(25) +#define MANTIS_GPIF_WAITPOL BIT(24) #define MANTIS_GPIF_NCDELAY (0x07 << 20) #define MANTIS_GPIF_RW2CSDELAY (0x07 << 16) -#define MANTIS_GPIF_SLFTIMEDMODE (0x01 << 15) +#define MANTIS_GPIF_SLFTIMEDMODE BIT(15) #define MANTIS_GPIF_SLFTIMEDDELY (0x7f << 8) #define MANTIS_GPIF_DEVTYPE (0x07 << 4) -#define MANTIS_GPIF_BIGENDIAN (0x01 << 3) +#define MANTIS_GPIF_BIGENDIAN BIT(3) #define MANTIS_GPIF_FETCHCMD (0x03 << 1) -#define MANTIS_GPIF_HWORDDEV (0x01 << 0) +#define MANTIS_GPIF_HWORDDEV BIT(0) #define MANTIS_GPIF_WSTOPER 0x90 -#define MANTIS_GPIF_WSTOPERWREN3 (0x01 << 31) -#define MANTIS_GPIF_PARBOOTN (0x01 << 29) +#define MANTIS_GPIF_WSTOPERWREN3 BIT(31) +#define MANTIS_GPIF_PARBOOTN BIT(29) #define MANTIS_GPIF_WSTOPERSLID3 (0x1f << 24) -#define MANTIS_GPIF_WSTOPERWREN2 (0x01 << 23) +#define MANTIS_GPIF_WSTOPERWREN2 BIT(23) #define MANTIS_GPIF_WSTOPERSLID2 (0x1f << 16) -#define MANTIS_GPIF_WSTOPERWREN1 (0x01 << 15) +#define MANTIS_GPIF_WSTOPERWREN1 BIT(15) #define MANTIS_GPIF_WSTOPERSLID1 (0x1f << 8) -#define MANTIS_GPIF_WSTOPERWREN0 (0x01 << 7) +#define MANTIS_GPIF_WSTOPERWREN0 BIT(7) #define MANTIS_GPIF_WSTOPERSLID0 (0x1f << 0) #define MANTIS_GPIF_CS2RW 0x94 -#define MANTIS_GPIF_CS2RWWREN3 (0x01 << 31) +#define MANTIS_GPIF_CS2RWWREN3 BIT(31) #define MANTIS_GPIF_CS2RWDELY3 (0x3f << 24) -#define MANTIS_GPIF_CS2RWWREN2 (0x01 << 23) +#define MANTIS_GPIF_CS2RWWREN2 BIT(23) #define MANTIS_GPIF_CS2RWDELY2 (0x3f << 16) -#define MANTIS_GPIF_CS2RWWREN1 (0x01 << 15) +#define MANTIS_GPIF_CS2RWWREN1 BIT(15) #define MANTIS_GPIF_CS2RWDELY1 (0x3f << 8) -#define MANTIS_GPIF_CS2RWWREN0 (0x01 << 7) +#define MANTIS_GPIF_CS2RWWREN0 BIT(7) #define MANTIS_GPIF_CS2RWDELY0 (0x3f << 0) #define MANTIS_GPIF_IRQCFG 0x98 -#define MANTIS_GPIF_IRQPOL (0x01 << 8) -#define MANTIS_MASK_WRACK (0x01 << 7) -#define MANTIS_MASK_BRRDY (0x01 << 6) -#define MANTIS_MASK_OVFLW (0x01 << 5) -#define MANTIS_MASK_OTHERR (0x01 << 4) -#define MANTIS_MASK_WSTO (0x01 << 3) -#define MANTIS_MASK_EXTIRQ (0x01 << 2) -#define MANTIS_MASK_PLUGIN (0x01 << 1) -#define MANTIS_MASK_PLUGOUT (0x01 << 0) +#define MANTIS_GPIF_IRQPOL BIT(8) +#define MANTIS_MASK_WRACK BIT(7) +#define MANTIS_MASK_BRRDY BIT(6) +#define MANTIS_MASK_OVFLW BIT(5) +#define MANTIS_MASK_OTHERR BIT(4) +#define MANTIS_MASK_WSTO BIT(3) +#define MANTIS_MASK_EXTIRQ BIT(2) +#define MANTIS_MASK_PLUGIN BIT(1) +#define MANTIS_MASK_PLUGOUT BIT(0) #define MANTIS_GPIF_STATUS 0x9c -#define MANTIS_SBUF_KILLOP (0x01 << 15) -#define MANTIS_SBUF_OPDONE (0x01 << 14) -#define MANTIS_SBUF_EMPTY (0x01 << 13) -#define MANTIS_GPIF_DETSTAT (0x01 << 9) -#define MANTIS_GPIF_INTSTAT (0x01 << 8) -#define MANTIS_GPIF_WRACK (0x01 << 7) -#define MANTIS_GPIF_BRRDY (0x01 << 6) -#define MANTIS_SBUF_OVFLW (0x01 << 5) -#define MANTIS_GPIF_OTHERR (0x01 << 4) -#define MANTIS_SBUF_WSTO (0x01 << 3) -#define MANTIS_GPIF_EXTIRQ (0x01 << 2) -#define MANTIS_CARD_PLUGIN (0x01 << 1) -#define MANTIS_CARD_PLUGOUT (0x01 << 0) +#define MANTIS_SBUF_KILLOP BIT(15) +#define MANTIS_SBUF_OPDONE BIT(14) +#define MANTIS_SBUF_EMPTY BIT(13) +#define MANTIS_GPIF_DETSTAT BIT(9) +#define MANTIS_GPIF_INTSTAT BIT(8) +#define MANTIS_GPIF_WRACK BIT(7) +#define MANTIS_GPIF_BRRDY BIT(6) +#define MANTIS_SBUF_OVFLW BIT(5) +#define MANTIS_GPIF_OTHERR BIT(4) +#define MANTIS_SBUF_WSTO BIT(3) +#define MANTIS_GPIF_EXTIRQ BIT(2) +#define MANTIS_CARD_PLUGIN BIT(1) +#define MANTIS_CARD_PLUGOUT BIT(0) #define MANTIS_GPIF_BRADDR 0xa0 -#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) -#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) +#define MANTIS_GPIF_PCMCIAREG BIT(27) +#define MANTIS_GPIF_PCMCIAIOM BIT(26) #define MANTIS_GPIF_BR_ADDR (0xfffffff << 0) #define MANTIS_GPIF_BRBYTES 0xa4 @@ -167,9 +167,9 @@ #define MANTIS_CARD_RESET 0xac #define MANTIS_GPIF_ADDR 0xb0 -#define MANTIS_GPIF_HIFRDWRN (0x01 << 31) -#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) -#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) +#define MANTIS_GPIF_HIFRDWRN BIT(31) +#define MANTIS_GPIF_PCMCIAREG BIT(27) +#define MANTIS_GPIF_PCMCIAIOM BIT(26) #define MANTIS_GPIF_HIFADDR (0xfffffff << 0) #define MANTIS_GPIF_DOUT 0xb4 diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index 8218810c899e..0e61c81356ef 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1104,12 +1104,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, if (f->index == 0) { /* standard YUV 422 capture */ f->flags = 0; - strscpy(f->description, "YUV422", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_YUYV; } else { /* compressed MJPEG capture */ - f->flags = V4L2_FMT_FLAG_COMPRESSED; - strscpy(f->description, "MJPEG", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MJPEG; } diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index b75ab7d29226..af15ca1c501b 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -854,8 +854,6 @@ static int create_ring_buffer(struct pci_dev *pci_dev, if (!Head) return -ENOMEM; - memset(Head, 0, MemSize); - PARingBufferCur = PARingBufferHead; Cur = Head; @@ -907,8 +905,6 @@ static int AllocateRingBuffers(struct pci_dev *pci_dev, if (SCListMem == NULL) return -ENOMEM; - memset(SCListMem, 0, SCListMemSize); - pRingBuffer->SCListMem = SCListMem; pRingBuffer->PASCListMem = PASCListMem; pRingBuffer->SCListMemSize = SCListMemSize; diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index e51c80bc4646..72b191cfeb54 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -1217,8 +1217,7 @@ static void pt1_i2c_init(struct pt1 *pt1) static int pt1_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct pt1 *pt1 = pci_get_drvdata(pdev); + struct pt1 *pt1 = dev_get_drvdata(dev); pt1_init_streams(pt1); pt1_disable_ram(pt1); @@ -1230,8 +1229,7 @@ static int pt1_suspend(struct device *dev) static int pt1_resume(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct pt1 *pt1 = pci_get_drvdata(pdev); + struct pt1 *pt1 = dev_get_drvdata(dev); int ret; int i; diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index 7a7afae4c84c..c0bc86793355 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c @@ -626,8 +626,7 @@ static void pt3_cleanup_adapter(struct pt3_board *pt3, int index) static int pt3_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct pt3_board *pt3 = pci_get_drvdata(pdev); + struct pt3_board *pt3 = dev_get_drvdata(dev); int i; struct pt3_adapter *adap; @@ -646,8 +645,7 @@ static int pt3_suspend(struct device *dev) static int pt3_resume(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct pt3_board *pt3 = pci_get_drvdata(pdev); + struct pt3_board *pt3 = dev_get_drvdata(dev); int i, ret; struct pt3_adapter *adap; diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c index eb8377a95023..f359cd5c006a 100644 --- a/drivers/media/pci/saa7134/saa7134-dvb.c +++ b/drivers/media/pci/saa7134/saa7134-dvb.c @@ -1264,6 +1264,20 @@ static int dvb_init(struct saa7134_dev *dev) &medion_cardbus, &dev->i2c_adap); if (fe0->dvb.frontend) { + /* + * The TV tuner on this board is actually NOT + * behind the demod i2c gate. + * However, the demod EEPROM is indeed there and it + * conflicts with the SAA7134 chip config EEPROM + * if the i2c gate is open (since they have same + * bus addresses) resulting in card PCI SVID / SSID + * being garbage after a reboot from time to time. + * + * Let's just leave the gate permanently closed - + * saa7134_i2c_eeprom_md7134_gate() will close it for + * us at probe time if it was open for some reason. + */ + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &dev->i2c_adap, medion_cardbus.tuner_address, TUNER_PHILIPS_FMD1216ME_MK3); diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 1a41a56afec6..cb65d345fd3e 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -91,9 +91,7 @@ static int empress_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, "MPEG TS", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; - f->flags = V4L2_FMT_FLAG_COMPRESSED; return 0; } diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index 493b1858815f..04e85765373e 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c @@ -342,7 +342,11 @@ static const struct i2c_client saa7134_client_template = { /* ----------------------------------------------------------- */ -/* On Medion 7134 reading EEPROM needs DVB-T demod i2c gate open */ +/* + * On Medion 7134 reading the SAA7134 chip config EEPROM needs DVB-T + * demod i2c gate closed due to an address clash between this EEPROM + * and the demod one. + */ static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev) { u8 subaddr = 0x7, dmdregval; @@ -359,14 +363,14 @@ static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev) ret = i2c_transfer(&dev->i2c_adap, i2cgatemsg_r, 2); if ((ret == 2) && (dmdregval & 0x2)) { - pr_debug("%s: DVB-T demod i2c gate was left closed\n", + pr_debug("%s: DVB-T demod i2c gate was left open\n", dev->name); data[0] = subaddr; data[1] = (dmdregval & ~0x2); if (i2c_transfer(&dev->i2c_adap, i2cgatemsg_w, 1) != 1) - pr_err("%s: EEPROM i2c gate open failure\n", - dev->name); + pr_err("%s: EEPROM i2c gate close failure\n", + dev->name); } } diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c index 5beff534d5e1..79e1afb71075 100644 --- a/drivers/media/pci/saa7134/saa7134-tvaudio.c +++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c @@ -319,7 +319,6 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) __s32 left,right,value; if (!(dev->tvnorm->id & scan->std)) { - value = 0; audio_dbg(1, "skipping %d.%03d MHz [%4s]\n", scan->carr / 1000, scan->carr % 1000, scan->name); return 0; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 606df51bb636..342cabf48064 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -90,70 +90,58 @@ static int video_out[][9] = { static struct saa7134_format formats[] = { { - .name = "8 bpp gray", .fourcc = V4L2_PIX_FMT_GREY, .depth = 8, .pm = 0x06, },{ - .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555, .depth = 16, .pm = 0x13 | 0x80, },{ - .name = "15 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB555X, .depth = 16, .pm = 0x13 | 0x80, .bswap = 1, },{ - .name = "16 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB565, .depth = 16, .pm = 0x10 | 0x80, },{ - .name = "16 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB565X, .depth = 16, .pm = 0x10 | 0x80, .bswap = 1, },{ - .name = "24 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR24, .depth = 24, .pm = 0x11, },{ - .name = "24 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB24, .depth = 24, .pm = 0x11, .bswap = 1, },{ - .name = "32 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR32, .depth = 32, .pm = 0x12, },{ - .name = "32 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB32, .depth = 32, .pm = 0x12, .bswap = 1, .wswap = 1, },{ - .name = "4:2:2 packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .pm = 0x00, .bswap = 1, .yuv = 1, },{ - .name = "4:2:2 packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16, .pm = 0x00, .yuv = 1, },{ - .name = "4:2:2 planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV422P, .depth = 16, .pm = 0x09, @@ -162,7 +150,6 @@ static struct saa7134_format formats[] = { .hshift = 1, .vshift = 0, },{ - .name = "4:2:0 planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV420, .depth = 12, .pm = 0x0a, @@ -171,7 +158,6 @@ static struct saa7134_format formats[] = { .hshift = 1, .vshift = 1, },{ - .name = "4:2:0 planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YVU420, .depth = 12, .pm = 0x0a, @@ -720,10 +706,10 @@ static int start_preview(struct saa7134_dev *dev) return err; dev->ovfield = dev->win.field; - video_dbg("start_preview %dx%d+%d+%d %s field=%s\n", - dev->win.w.width, dev->win.w.height, - dev->win.w.left, dev->win.w.top, - dev->ovfmt->name, v4l2_field_names[dev->ovfield]); + video_dbg("%s %dx%d+%d+%d 0x%08x field=%s\n", __func__, + dev->win.w.width, dev->win.w.height, + dev->win.w.left, dev->win.w.top, + dev->ovfmt->fourcc, v4l2_field_names[dev->ovfield]); /* setup window + clipping */ set_size(dev, TASK_B, dev->win.w.width, dev->win.w.height, @@ -1780,9 +1766,6 @@ static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index >= FORMATS) return -EINVAL; - strscpy(f->description, formats[f->index].name, - sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; return 0; @@ -1799,9 +1782,6 @@ static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv, if ((f->index >= FORMATS) || formats[f->index].planar) return -EINVAL; - strscpy(f->description, formats[f->index].name, - sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; return 0; diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 6324f174c6f9..77c325e64a97 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -98,7 +98,6 @@ struct saa7134_tvaudio { }; struct saa7134_format { - char *name; unsigned int fourcc; unsigned int depth; unsigned int pm; diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index dca20a3d98e2..f96226930670 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -292,6 +292,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER); if (ret < 0) { pr_err("cannot register capture v4l2 device. skipping.\n"); + saa7146_vv_release(dev); + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); return ret; } diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 43fdaa2d32bd..3fca7257a720 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -503,7 +503,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, "MPEG", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; return 0; diff --git a/drivers/media/pci/solo6x10/solo6x10-gpio.c b/drivers/media/pci/solo6x10/solo6x10-gpio.c index 5caeca8b5dd0..526d67cf9942 100644 --- a/drivers/media/pci/solo6x10/solo6x10-gpio.c +++ b/drivers/media/pci/solo6x10/solo6x10-gpio.c @@ -39,13 +39,13 @@ static void solo_gpio_mode(struct solo_dev *solo_dev, ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1); for (port = 0; port < 16; port++) { - if (!((1 << (port + 16)) & port_mask)) + if (!((1UL << (port + 16)) & port_mask)) continue; if (!mode) - ret &= ~(1 << port); + ret &= ~(1UL << port); else - ret |= 1 << port; + ret |= 1UL << port; } /* Enable GPIO[31:16] */ diff --git a/drivers/media/pci/solo6x10/solo6x10-regs.h b/drivers/media/pci/solo6x10/solo6x10-regs.h index d88cc02d01d3..804505d01b25 100644 --- a/drivers/media/pci/solo6x10/solo6x10-regs.h +++ b/drivers/media/pci/solo6x10/solo6x10-regs.h @@ -12,6 +12,8 @@ #ifndef __SOLO6X10_REGISTERS_H #define __SOLO6X10_REGISTERS_H +#include <linux/bitops.h> + #include "solo6x10-offsets.h" /* Global 6010 system configuration */ @@ -32,17 +34,17 @@ #define SOLO_DMA_CTRL_REFRESH_CYCLE(n) ((n)<<8) /* 0=16/32MB, 1=32/64MB, 2=64/128MB, 3=128/256MB */ #define SOLO_DMA_CTRL_SDRAM_SIZE(n) ((n)<<6) -#define SOLO_DMA_CTRL_SDRAM_CLK_INVERT (1<<5) -#define SOLO_DMA_CTRL_STROBE_SELECT (1<<4) -#define SOLO_DMA_CTRL_READ_DATA_SELECT (1<<3) -#define SOLO_DMA_CTRL_READ_CLK_SELECT (1<<2) +#define SOLO_DMA_CTRL_SDRAM_CLK_INVERT BIT(5) +#define SOLO_DMA_CTRL_STROBE_SELECT BIT(4) +#define SOLO_DMA_CTRL_READ_DATA_SELECT BIT(3) +#define SOLO_DMA_CTRL_READ_CLK_SELECT BIT(2) #define SOLO_DMA_CTRL_LATENCY(n) ((n)<<0) /* Some things we set in this are undocumented. Why Softlogic?!?! */ #define SOLO_DMA_CTRL1 0x0008 #define SOLO_SYS_VCLK 0x000C -#define SOLO_VCLK_INVERT (1<<22) +#define SOLO_VCLK_INVERT BIT(22) /* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */ #define SOLO_VCLK_SELECT(n) ((n)<<20) #define SOLO_VCLK_VIN1415_DELAY(n) ((n)<<14) @@ -56,22 +58,22 @@ #define SOLO_IRQ_STAT 0x0010 #define SOLO_IRQ_MASK 0x0014 -#define SOLO_IRQ_P2M(n) (1<<((n)+17)) -#define SOLO_IRQ_GPIO (1<<16) -#define SOLO_IRQ_VIDEO_LOSS (1<<15) -#define SOLO_IRQ_VIDEO_IN (1<<14) -#define SOLO_IRQ_MOTION (1<<13) -#define SOLO_IRQ_ATA_CMD (1<<12) -#define SOLO_IRQ_ATA_DIR (1<<11) -#define SOLO_IRQ_PCI_ERR (1<<10) -#define SOLO_IRQ_PS2_1 (1<<9) -#define SOLO_IRQ_PS2_0 (1<<8) -#define SOLO_IRQ_SPI (1<<7) -#define SOLO_IRQ_IIC (1<<6) -#define SOLO_IRQ_UART(n) (1<<((n) + 4)) -#define SOLO_IRQ_G723 (1<<3) -#define SOLO_IRQ_DECODER (1<<1) -#define SOLO_IRQ_ENCODER (1<<0) +#define SOLO_IRQ_P2M(n) BIT((n) + 17) +#define SOLO_IRQ_GPIO BIT(16) +#define SOLO_IRQ_VIDEO_LOSS BIT(15) +#define SOLO_IRQ_VIDEO_IN BIT(14) +#define SOLO_IRQ_MOTION BIT(13) +#define SOLO_IRQ_ATA_CMD BIT(12) +#define SOLO_IRQ_ATA_DIR BIT(11) +#define SOLO_IRQ_PCI_ERR BIT(10) +#define SOLO_IRQ_PS2_1 BIT(9) +#define SOLO_IRQ_PS2_0 BIT(8) +#define SOLO_IRQ_SPI BIT(7) +#define SOLO_IRQ_IIC BIT(6) +#define SOLO_IRQ_UART(n) BIT((n) + 4) +#define SOLO_IRQ_G723 BIT(3) +#define SOLO_IRQ_DECODER BIT(1) +#define SOLO_IRQ_ENCODER BIT(0) #define SOLO_CHIP_OPTION 0x001C #define SOLO_CHIP_ID_MASK 0x00000007 @@ -79,11 +81,11 @@ #define SOLO_PLL_CONFIG 0x0020 /* 6110 Only */ #define SOLO_EEPROM_CTRL 0x0060 -#define SOLO_EEPROM_ACCESS_EN (1<<7) -#define SOLO_EEPROM_CS (1<<3) -#define SOLO_EEPROM_CLK (1<<2) -#define SOLO_EEPROM_DO (1<<1) -#define SOLO_EEPROM_DI (1<<0) +#define SOLO_EEPROM_ACCESS_EN BIT(7) +#define SOLO_EEPROM_CS BIT(3) +#define SOLO_EEPROM_CLK BIT(2) +#define SOLO_EEPROM_DO BIT(1) +#define SOLO_EEPROM_DI BIT(0) #define SOLO_EEPROM_ENABLE (SOLO_EEPROM_ACCESS_EN | SOLO_EEPROM_CS) #define SOLO_PCI_ERR 0x0070 @@ -102,13 +104,13 @@ #define SOLO_P2M_CONFIG(n) (0x0080 + ((n)*0x20)) #define SOLO_P2M_DMA_INTERVAL(n) ((n)<<6)/* N*32 clocks */ -#define SOLO_P2M_CSC_BYTE_REORDER (1<<5) /* BGR -> RGB */ +#define SOLO_P2M_CSC_BYTE_REORDER BIT(5) /* BGR -> RGB */ /* 0:r=[14:10] g=[9:5] b=[4:0], 1:r=[15:11] g=[10:5] b=[4:0] */ -#define SOLO_P2M_CSC_16BIT_565 (1<<4) -#define SOLO_P2M_UV_SWAP (1<<3) -#define SOLO_P2M_PCI_MASTER_MODE (1<<2) -#define SOLO_P2M_DESC_INTR_OPT (1<<1) /* 1:Empty, 0:Each */ -#define SOLO_P2M_DESC_MODE (1<<0) +#define SOLO_P2M_CSC_16BIT_565 BIT(4) +#define SOLO_P2M_UV_SWAP BIT(3) +#define SOLO_P2M_PCI_MASTER_MODE BIT(2) +#define SOLO_P2M_DESC_INTR_OPT BIT(1) /* 1:Empty, 0:Each */ +#define SOLO_P2M_DESC_MODE BIT(0) #define SOLO_P2M_DES_ADR(n) (0x0084 + ((n)*0x20)) @@ -116,7 +118,7 @@ #define SOLO_P2M_UPDATE_ID(n) ((n)<<0) #define SOLO_P2M_STATUS(n) (0x008C + ((n)*0x20)) -#define SOLO_P2M_COMMAND_DONE (1<<8) +#define SOLO_P2M_COMMAND_DONE BIT(8) #define SOLO_P2M_CURRENT_ID(stat) (0xff & (stat)) #define SOLO_P2M_CONTROL(n) (0x0090 + ((n)*0x20)) @@ -129,13 +131,13 @@ #define SOLO_P2M_BURST_128 2 #define SOLO_P2M_BURST_64 3 #define SOLO_P2M_BURST_32 4 -#define SOLO_P2M_CSC_16BIT (1<<6) /* 0:24bit, 1:16bit */ +#define SOLO_P2M_CSC_16BIT BIT(6) /* 0:24bit, 1:16bit */ /* 0:Y[0]<-0(OFF), 1:Y[0]<-1(ON), 2:Y[0]<-G[0], 3:Y[0]<-Bit[15] */ #define SOLO_P2M_ALPHA_MODE(n) ((n)<<4) -#define SOLO_P2M_CSC_ON (1<<3) -#define SOLO_P2M_INTERRUPT_REQ (1<<2) -#define SOLO_P2M_WRITE (1<<1) -#define SOLO_P2M_TRANS_ON (1<<0) +#define SOLO_P2M_CSC_ON BIT(3) +#define SOLO_P2M_INTERRUPT_REQ BIT(2) +#define SOLO_P2M_WRITE BIT(1) +#define SOLO_P2M_TRANS_ON BIT(0) #define SOLO_P2M_EXT_CFG(n) (0x0094 + ((n)*0x20)) #define SOLO_P2M_EXT_INC(n) ((n)<<20) @@ -157,9 +159,9 @@ #define SOLO_VI_PROG_MASK(n) ((n)<<0) #define SOLO_VI_FMT_CFG 0x0114 -#define SOLO_VI_FMT_CHECK_VCOUNT (1<<31) -#define SOLO_VI_FMT_CHECK_HCOUNT (1<<30) -#define SOLO_VI_FMT_TEST_SIGNAL (1<<28) +#define SOLO_VI_FMT_CHECK_VCOUNT BIT(31) +#define SOLO_VI_FMT_CHECK_HCOUNT BIT(30) +#define SOLO_VI_FMT_TEST_SIGNAL BIT(28) #define SOLO_VI_PAGE_SW 0x0118 #define SOLO_FI_INV_DISP_LIVE(n) ((n)<<8) @@ -171,7 +173,7 @@ #define SOLO_VI_ACT_I_P 0x011C #define SOLO_VI_ACT_I_S 0x0120 #define SOLO_VI_ACT_P 0x0124 -#define SOLO_VI_FI_INVERT (1<<31) +#define SOLO_VI_FI_INVERT BIT(31) #define SOLO_VI_H_START(n) ((n)<<21) #define SOLO_VI_V_START(n) ((n)<<11) #define SOLO_VI_V_STOP(n) ((n)<<0) @@ -184,8 +186,8 @@ #define DISP_PAGE(stat) ((stat) & 0x07) #define SOLO_VI_PB_CONFIG 0x0130 -#define SOLO_VI_PB_USER_MODE (1<<1) -#define SOLO_VI_PB_PAL (1<<0) +#define SOLO_VI_PB_USER_MODE BIT(1) +#define SOLO_VI_PB_PAL BIT(0) #define SOLO_VI_PB_RANGE_HV 0x0134 #define SOLO_VI_PB_HSIZE(h) ((h)<<12) #define SOLO_VI_PB_VSIZE(v) ((v)<<0) @@ -226,35 +228,35 @@ #define SOLO_VI_MOT_CTRL 0x0264 #define SOLO_VI_MOTION_FRAME_COUNT(n) ((n)<<24) #define SOLO_VI_MOTION_SAMPLE_LENGTH(n) ((n)<<16) -#define SOLO_VI_MOTION_INTR_START_STOP (1<<15) -#define SOLO_VI_MOTION_FREEZE_DATA (1<<14) +#define SOLO_VI_MOTION_INTR_START_STOP BIT(15) +#define SOLO_VI_MOTION_FREEZE_DATA BIT(14) #define SOLO_VI_MOTION_SAMPLE_COUNT(n) ((n)<<0) #define SOLO_VI_MOT_CLEAR 0x0268 #define SOLO_VI_MOT_STATUS 0x026C #define SOLO_VI_MOTION_CNT(n) ((n)<<0) #define SOLO_VI_MOTION_BORDER 0x0270 #define SOLO_VI_MOTION_BAR 0x0274 -#define SOLO_VI_MOTION_Y_SET (1<<29) -#define SOLO_VI_MOTION_Y_ADD (1<<28) -#define SOLO_VI_MOTION_CB_SET (1<<27) -#define SOLO_VI_MOTION_CB_ADD (1<<26) -#define SOLO_VI_MOTION_CR_SET (1<<25) -#define SOLO_VI_MOTION_CR_ADD (1<<24) +#define SOLO_VI_MOTION_Y_SET BIT(29) +#define SOLO_VI_MOTION_Y_ADD BIT(28) +#define SOLO_VI_MOTION_CB_SET BIT(27) +#define SOLO_VI_MOTION_CB_ADD BIT(26) +#define SOLO_VI_MOTION_CR_SET BIT(25) +#define SOLO_VI_MOTION_CR_ADD BIT(24) #define SOLO_VI_MOTION_Y_VALUE(v) ((v)<<16) #define SOLO_VI_MOTION_CB_VALUE(v) ((v)<<8) #define SOLO_VI_MOTION_CR_VALUE(v) ((v)<<0) #define SOLO_VO_FMT_ENC 0x0300 -#define SOLO_VO_SCAN_MODE_PROGRESSIVE (1<<31) -#define SOLO_VO_FMT_TYPE_PAL (1<<30) +#define SOLO_VO_SCAN_MODE_PROGRESSIVE BIT(31) +#define SOLO_VO_FMT_TYPE_PAL BIT(30) #define SOLO_VO_FMT_TYPE_NTSC 0 -#define SOLO_VO_USER_SET (1<<29) +#define SOLO_VO_USER_SET BIT(29) -#define SOLO_VO_FI_CHANGE (1<<20) -#define SOLO_VO_USER_COLOR_SET_VSYNC (1<<19) -#define SOLO_VO_USER_COLOR_SET_HSYNC (1<<18) -#define SOLO_VO_USER_COLOR_SET_NAH (1<<17) -#define SOLO_VO_USER_COLOR_SET_NAV (1<<16) +#define SOLO_VO_FI_CHANGE BIT(20) +#define SOLO_VO_USER_COLOR_SET_VSYNC BIT(19) +#define SOLO_VO_USER_COLOR_SET_HSYNC BIT(18) +#define SOLO_VO_USER_COLOR_SET_NAH BIT(17) +#define SOLO_VO_USER_COLOR_SET_NAV BIT(16) #define SOLO_VO_NA_COLOR_Y(Y) ((Y)<<8) #define SOLO_VO_NA_COLOR_CB(CB) (((CB)/16)<<4) #define SOLO_VO_NA_COLOR_CR(CR) (((CR)/16)<<0) @@ -270,32 +272,32 @@ #define SOLO_VO_V_STOP(n) ((n)<<0) #define SOLO_VO_RANGE_HV 0x030C -#define SOLO_VO_SYNC_INVERT (1<<24) -#define SOLO_VO_HSYNC_INVERT (1<<23) -#define SOLO_VO_VSYNC_INVERT (1<<22) +#define SOLO_VO_SYNC_INVERT BIT(24) +#define SOLO_VO_HSYNC_INVERT BIT(23) +#define SOLO_VO_VSYNC_INVERT BIT(22) #define SOLO_VO_H_LEN(n) ((n)<<11) #define SOLO_VO_V_LEN(n) ((n)<<0) #define SOLO_VO_DISP_CTRL 0x0310 -#define SOLO_VO_DISP_ON (1<<31) +#define SOLO_VO_DISP_ON BIT(31) #define SOLO_VO_DISP_ERASE_COUNT(n) ((n&0xf)<<24) -#define SOLO_VO_DISP_DOUBLE_SCAN (1<<22) -#define SOLO_VO_DISP_SINGLE_PAGE (1<<21) +#define SOLO_VO_DISP_DOUBLE_SCAN BIT(22) +#define SOLO_VO_DISP_SINGLE_PAGE BIT(21) #define SOLO_VO_DISP_BASE(n) (((n)>>16) & 0xffff) #define SOLO_VO_DISP_ERASE 0x0314 -#define SOLO_VO_DISP_ERASE_ON (1<<0) +#define SOLO_VO_DISP_ERASE_ON BIT(0) #define SOLO_VO_ZOOM_CTRL 0x0318 -#define SOLO_VO_ZOOM_VER_ON (1<<24) -#define SOLO_VO_ZOOM_HOR_ON (1<<23) -#define SOLO_VO_ZOOM_V_COMP (1<<22) +#define SOLO_VO_ZOOM_VER_ON BIT(24) +#define SOLO_VO_ZOOM_HOR_ON BIT(23) +#define SOLO_VO_ZOOM_V_COMP BIT(22) #define SOLO_VO_ZOOM_SX(h) (((h)/2)<<11) #define SOLO_VO_ZOOM_SY(v) (((v)/2)<<0) #define SOLO_VO_FREEZE_CTRL 0x031C -#define SOLO_VO_FREEZE_ON (1<<1) -#define SOLO_VO_FREEZE_INTERPOLATION (1<<0) +#define SOLO_VO_FREEZE_ON BIT(1) +#define SOLO_VO_FREEZE_INTERPOLATION BIT(0) #define SOLO_VO_BKG_COLOR 0x0320 #define SOLO_BG_Y(y) ((y)<<16) @@ -334,8 +336,8 @@ #define SOLO_VO_EXPANSION(id) (0x0250+((id)*4)) #define SOLO_OSG_CONFIG 0x03E0 -#define SOLO_VO_OSG_ON (1<<31) -#define SOLO_VO_OSG_COLOR_MUTE (1<<28) +#define SOLO_VO_OSG_ON BIT(31) +#define SOLO_VO_OSG_COLOR_MUTE BIT(28) #define SOLO_VO_OSG_ALPHA_RATE(n) ((n)<<22) #define SOLO_VO_OSG_ALPHA_BG_RATE(n) ((n)<<16) #define SOLO_VO_OSG_BASE(offset) (((offset)>>16)&0xffff) @@ -345,8 +347,8 @@ #define SOLO_OSG_ERASE_OFF (0x00) #define SOLO_VO_OSG_BLINK 0x03E8 -#define SOLO_VO_OSG_BLINK_ON (1<<1) -#define SOLO_VO_OSG_BLINK_INTREVAL18 (1<<0) +#define SOLO_VO_OSG_BLINK_ON BIT(1) +#define SOLO_VO_OSG_BLINK_INTREVAL18 BIT(0) #define SOLO_CAP_BASE 0x0400 #define SOLO_CAP_MAX_PAGE(n) ((n)<<16) @@ -374,19 +376,19 @@ #define SOLO_VE_CFG0 0x0610 -#define SOLO_VE_TWO_PAGE_MODE (1<<31) +#define SOLO_VE_TWO_PAGE_MODE BIT(31) #define SOLO_VE_INTR_CTRL(n) ((n)<<24) #define SOLO_VE_BLOCK_SIZE(n) ((n)<<16) #define SOLO_VE_BLOCK_BASE(n) ((n)<<0) #define SOLO_VE_CFG1 0x0614 #define SOLO_VE_BYTE_ALIGN(n) ((n)<<24) -#define SOLO_VE_INSERT_INDEX (1<<18) +#define SOLO_VE_INSERT_INDEX BIT(18) #define SOLO_VE_MOTION_MODE(n) ((n)<<16) #define SOLO_VE_MOTION_BASE(n) ((n)<<0) #define SOLO_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 Only */ #define SOLO_VE_JPEG_SIZE_H(n) ((n)<<20) /* 6110 Only */ -#define SOLO_VE_INSERT_INDEX_JPEG (1<<19) /* 6110 Only */ +#define SOLO_VE_INSERT_INDEX_JPEG BIT(19) /* 6110 Only */ #define SOLO_VE_WMRK_POLY 0x061C #define SOLO_VE_VMRK_INIT_KEY 0x0620 @@ -394,8 +396,8 @@ #define SOLO_VE_ENCRYP_POLY 0x0628 #define SOLO_VE_ENCRYP_INIT 0x062C #define SOLO_VE_ATTR 0x0630 -#define SOLO_VE_LITTLE_ENDIAN (1<<31) -#define SOLO_COMP_ATTR_RN (1<<30) +#define SOLO_VE_LITTLE_ENDIAN BIT(31) +#define SOLO_COMP_ATTR_RN BIT(30) #define SOLO_COMP_ATTR_FCODE(n) ((n)<<27) #define SOLO_COMP_TIME_INC(n) ((n)<<25) #define SOLO_COMP_TIME_WIDTH(n) ((n)<<21) @@ -416,9 +418,9 @@ #define SOLO_VE_OSD_BASE 0x0694 #define SOLO_VE_OSD_CLR 0x0698 #define SOLO_VE_OSD_OPT 0x069C -#define SOLO_VE_OSD_V_DOUBLE (1<<16) /* 6110 Only */ -#define SOLO_VE_OSD_H_SHADOW (1<<15) -#define SOLO_VE_OSD_V_SHADOW (1<<14) +#define SOLO_VE_OSD_V_DOUBLE BIT(16) /* 6110 Only */ +#define SOLO_VE_OSD_H_SHADOW BIT(15) +#define SOLO_VE_OSD_V_SHADOW BIT(14) #define SOLO_VE_OSD_H_OFFSET(n) ((n & 0x7f)<<7) #define SOLO_VE_OSD_V_OFFSET(n) (n & 0x7f) @@ -435,18 +437,18 @@ #define SOLO_VE_JPEG_QUE(n) (0x0A04+((n)*8)) #define SOLO_VD_CFG0 0x0900 -#define SOLO_VD_CFG_NO_WRITE_NO_WINDOW (1<<24) -#define SOLO_VD_CFG_BUSY_WIAT_CODE (1<<23) -#define SOLO_VD_CFG_BUSY_WIAT_REF (1<<22) -#define SOLO_VD_CFG_BUSY_WIAT_RES (1<<21) -#define SOLO_VD_CFG_BUSY_WIAT_MS (1<<20) -#define SOLO_VD_CFG_SINGLE_MODE (1<<18) -#define SOLO_VD_CFG_SCAL_MANUAL (1<<17) -#define SOLO_VD_CFG_USER_PAGE_CTRL (1<<16) -#define SOLO_VD_CFG_LITTLE_ENDIAN (1<<15) -#define SOLO_VD_CFG_START_FI (1<<14) -#define SOLO_VD_CFG_ERR_LOCK (1<<13) -#define SOLO_VD_CFG_ERR_INT_ENA (1<<12) +#define SOLO_VD_CFG_NO_WRITE_NO_WINDOW BIT(24) +#define SOLO_VD_CFG_BUSY_WIAT_CODE BIT(23) +#define SOLO_VD_CFG_BUSY_WIAT_REF BIT(22) +#define SOLO_VD_CFG_BUSY_WIAT_RES BIT(21) +#define SOLO_VD_CFG_BUSY_WIAT_MS BIT(20) +#define SOLO_VD_CFG_SINGLE_MODE BIT(18) +#define SOLO_VD_CFG_SCAL_MANUAL BIT(17) +#define SOLO_VD_CFG_USER_PAGE_CTRL BIT(16) +#define SOLO_VD_CFG_LITTLE_ENDIAN BIT(15) +#define SOLO_VD_CFG_START_FI BIT(14) +#define SOLO_VD_CFG_ERR_LOCK BIT(13) +#define SOLO_VD_CFG_ERR_INT_ENA BIT(12) #define SOLO_VD_CFG_TIME_WIDTH(n) ((n)<<8) #define SOLO_VD_CFG_DCT_INTERVAL(n) ((n)<<0) @@ -459,37 +461,37 @@ #define SOLO_VD_CODE_ADR 0x090C #define SOLO_VD_CTRL 0x0910 -#define SOLO_VD_OPER_ON (1<<31) +#define SOLO_VD_OPER_ON BIT(31) #define SOLO_VD_MAX_ITEM(n) ((n)<<0) #define SOLO_VD_STATUS0 0x0920 -#define SOLO_VD_STATUS0_INTR_ACK (1<<22) -#define SOLO_VD_STATUS0_INTR_EMPTY (1<<21) -#define SOLO_VD_STATUS0_INTR_ERR (1<<20) +#define SOLO_VD_STATUS0_INTR_ACK BIT(22) +#define SOLO_VD_STATUS0_INTR_EMPTY BIT(21) +#define SOLO_VD_STATUS0_INTR_ERR BIT(20) #define SOLO_VD_STATUS1 0x0924 #define SOLO_VD_IDX0 0x0930 -#define SOLO_VD_IDX_INTERLACE (1<<30) +#define SOLO_VD_IDX_INTERLACE BIT(30) #define SOLO_VD_IDX_CHANNEL(n) ((n)<<24) #define SOLO_VD_IDX_SIZE(n) ((n)<<0) #define SOLO_VD_IDX1 0x0934 #define SOLO_VD_IDX_SRC_SCALE(n) ((n)<<28) #define SOLO_VD_IDX_WINDOW(n) ((n)<<24) -#define SOLO_VD_IDX_DEINTERLACE (1<<16) +#define SOLO_VD_IDX_DEINTERLACE BIT(16) #define SOLO_VD_IDX_H_BLOCK(n) ((n)<<8) #define SOLO_VD_IDX_V_BLOCK(n) ((n)<<0) #define SOLO_VD_IDX2 0x0938 -#define SOLO_VD_IDX_REF_BASE_SIDE (1<<31) +#define SOLO_VD_IDX_REF_BASE_SIDE BIT(31) #define SOLO_VD_IDX_REF_BASE(n) (((n)>>16)&0xffff) #define SOLO_VD_IDX3 0x093C #define SOLO_VD_IDX_DISP_SCALE(n) ((n)<<28) -#define SOLO_VD_IDX_INTERLACE_WR (1<<27) -#define SOLO_VD_IDX_INTERPOL (1<<26) -#define SOLO_VD_IDX_HOR2X (1<<25) +#define SOLO_VD_IDX_INTERLACE_WR BIT(27) +#define SOLO_VD_IDX_INTERPOL BIT(26) +#define SOLO_VD_IDX_HOR2X BIT(25) #define SOLO_VD_IDX_OFFSET_X(n) ((n)<<12) #define SOLO_VD_IDX_OFFSET_Y(n) ((n)<<0) @@ -511,21 +513,21 @@ #define SOLO_IIC_CFG 0x0B20 -#define SOLO_IIC_ENABLE (1<<8) +#define SOLO_IIC_ENABLE BIT(8) #define SOLO_IIC_PRESCALE(n) ((n)<<0) #define SOLO_IIC_CTRL 0x0B24 -#define SOLO_IIC_AUTO_CLEAR (1<<20) -#define SOLO_IIC_STATE_RX_ACK (1<<19) -#define SOLO_IIC_STATE_BUSY (1<<18) -#define SOLO_IIC_STATE_SIG_ERR (1<<17) -#define SOLO_IIC_STATE_TRNS (1<<16) +#define SOLO_IIC_AUTO_CLEAR BIT(20) +#define SOLO_IIC_STATE_RX_ACK BIT(19) +#define SOLO_IIC_STATE_BUSY BIT(18) +#define SOLO_IIC_STATE_SIG_ERR BIT(17) +#define SOLO_IIC_STATE_TRNS BIT(16) #define SOLO_IIC_CH_SET(n) ((n)<<5) -#define SOLO_IIC_ACK_EN (1<<4) -#define SOLO_IIC_START (1<<3) -#define SOLO_IIC_STOP (1<<2) -#define SOLO_IIC_READ (1<<1) -#define SOLO_IIC_WRITE (1<<0) +#define SOLO_IIC_ACK_EN BIT(4) +#define SOLO_IIC_START BIT(3) +#define SOLO_IIC_STOP BIT(2) +#define SOLO_IIC_READ BIT(1) +#define SOLO_IIC_WRITE BIT(0) #define SOLO_IIC_TXD 0x0B28 #define SOLO_IIC_RXD 0x0B2C @@ -535,15 +537,15 @@ */ #define SOLO_UART_CONTROL(n) (0x0BA0 + ((n)*0x20)) #define SOLO_UART_CLK_DIV(n) ((n)<<24) -#define SOLO_MODEM_CTRL_EN (1<<20) -#define SOLO_PARITY_ERROR_DROP (1<<18) -#define SOLO_IRQ_ERR_EN (1<<17) -#define SOLO_IRQ_RX_EN (1<<16) -#define SOLO_IRQ_TX_EN (1<<15) -#define SOLO_RX_EN (1<<14) -#define SOLO_TX_EN (1<<13) -#define SOLO_UART_HALF_DUPLEX (1<<12) -#define SOLO_UART_LOOPBACK (1<<11) +#define SOLO_MODEM_CTRL_EN BIT(20) +#define SOLO_PARITY_ERROR_DROP BIT(18) +#define SOLO_IRQ_ERR_EN BIT(17) +#define SOLO_IRQ_RX_EN BIT(16) +#define SOLO_IRQ_TX_EN BIT(15) +#define SOLO_RX_EN BIT(14) +#define SOLO_TX_EN BIT(13) +#define SOLO_UART_HALF_DUPLEX BIT(12) +#define SOLO_UART_LOOPBACK BIT(11) #define SOLO_BAUDRATE_230400 ((0<<9)|(0<<6)) #define SOLO_BAUDRATE_115200 ((0<<9)|(1<<6)) @@ -569,12 +571,12 @@ #define SOLO_UART_PARITY_ODD (3<<0) #define SOLO_UART_STATUS(n) (0x0BA4 + ((n)*0x20)) -#define SOLO_UART_CTS (1<<15) -#define SOLO_UART_RX_BUSY (1<<14) -#define SOLO_UART_OVERRUN (1<<13) -#define SOLO_UART_FRAME_ERR (1<<12) -#define SOLO_UART_PARITY_ERR (1<<11) -#define SOLO_UART_TX_BUSY (1<<5) +#define SOLO_UART_CTS BIT(15) +#define SOLO_UART_RX_BUSY BIT(14) +#define SOLO_UART_OVERRUN BIT(13) +#define SOLO_UART_FRAME_ERR BIT(12) +#define SOLO_UART_PARITY_ERR BIT(11) +#define SOLO_UART_TX_BUSY BIT(5) #define SOLO_UART_RX_BUFF_CNT(stat) (((stat)>>6) & 0x1f) #define SOLO_UART_RX_BUFF_SIZE 8 @@ -582,9 +584,9 @@ #define SOLO_UART_TX_BUFF_SIZE 8 #define SOLO_UART_TX_DATA(n) (0x0BA8 + ((n)*0x20)) -#define SOLO_UART_TX_DATA_PUSH (1<<8) +#define SOLO_UART_TX_DATA_PUSH BIT(8) #define SOLO_UART_RX_DATA(n) (0x0BAC + ((n)*0x20)) -#define SOLO_UART_RX_DATA_POP (1<<8) +#define SOLO_UART_RX_DATA_POP BIT(8) #define SOLO_TIMER_CLOCK_NUM 0x0be0 #define SOLO_TIMER_USEC 0x0be8 @@ -592,19 +594,19 @@ #define SOLO_TIMER_USEC_LSB 0x0d20 /* 6110 Only */ #define SOLO_AUDIO_CONTROL 0x0D00 -#define SOLO_AUDIO_ENABLE (1<<31) -#define SOLO_AUDIO_MASTER_MODE (1<<30) -#define SOLO_AUDIO_I2S_MODE (1<<29) -#define SOLO_AUDIO_I2S_LR_SWAP (1<<27) -#define SOLO_AUDIO_I2S_8BIT (1<<26) +#define SOLO_AUDIO_ENABLE BIT(31) +#define SOLO_AUDIO_MASTER_MODE BIT(30) +#define SOLO_AUDIO_I2S_MODE BIT(29) +#define SOLO_AUDIO_I2S_LR_SWAP BIT(27) +#define SOLO_AUDIO_I2S_8BIT BIT(26) #define SOLO_AUDIO_I2S_MULTI(n) ((n)<<24) -#define SOLO_AUDIO_MIX_9TO0 (1<<23) +#define SOLO_AUDIO_MIX_9TO0 BIT(23) #define SOLO_AUDIO_DEC_9TO0_VOL(n) ((n)<<20) -#define SOLO_AUDIO_MIX_19TO10 (1<<19) +#define SOLO_AUDIO_MIX_19TO10 BIT(19) #define SOLO_AUDIO_DEC_19TO10_VOL(n) ((n)<<16) #define SOLO_AUDIO_MODE(n) ((n)<<0) #define SOLO_AUDIO_SAMPLE 0x0D04 -#define SOLO_AUDIO_EE_MODE_ON (1<<30) +#define SOLO_AUDIO_EE_MODE_ON BIT(30) #define SOLO_AUDIO_EE_ENC_CH(ch) ((ch)<<25) #define SOLO_AUDIO_BITRATE(n) ((n)<<16) #define SOLO_AUDIO_CLK_DIV(n) ((n)<<0) diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 609100a46ff8..476d7f3b32d6 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -822,25 +822,18 @@ static int solo_enc_enum_fmt_cap(struct file *file, void *priv, switch (dev_type) { case SOLO_DEV_6010: f->pixelformat = V4L2_PIX_FMT_MPEG4; - strscpy(f->description, "MPEG-4 part 2", - sizeof(f->description)); break; case SOLO_DEV_6110: f->pixelformat = V4L2_PIX_FMT_H264; - strscpy(f->description, "H.264", sizeof(f->description)); break; } break; case 1: f->pixelformat = V4L2_PIX_FMT_MJPEG; - strscpy(f->description, "MJPEG", sizeof(f->description)); break; default: return -EINVAL; } - - f->flags = V4L2_FMT_FLAG_COMPRESSED; - return 0; } @@ -886,7 +879,6 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv, pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->sizeimage = FRAME_BUF_SIZE; pix->bytesperline = 0; - pix->priv = 0; return 0; } @@ -941,7 +933,6 @@ static int solo_enc_get_fmt_cap(struct file *file, void *priv, V4L2_FIELD_NONE; pix->sizeimage = FRAME_BUF_SIZE; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - pix->priv = 0; return 0; } diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index a968f75920b5..78792067e920 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -458,8 +458,6 @@ static int solo_enum_fmt_cap(struct file *file, void *priv, return -EINVAL; f->pixelformat = V4L2_PIX_FMT_UYVY; - strscpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description)); - return 0; } @@ -479,7 +477,6 @@ static int solo_try_fmt_cap(struct file *file, void *priv, pix->field = V4L2_FIELD_INTERLACED; pix->pixelformat = V4L2_PIX_FMT_UYVY; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - pix->priv = 0; return 0; } @@ -509,7 +506,6 @@ static int solo_get_fmt_cap(struct file *file, void *priv, pix->sizeimage = solo_image_size(solo_dev); pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->bytesperline = solo_bytesperline(solo_dev); - pix->priv = 0; return 0; } diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index e52e29814378..fd3de3bb0c89 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -560,9 +560,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, "4:2:2, packed, UYVY", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_UYVY; - f->flags = 0; return 0; } diff --git a/drivers/media/pci/ttpci/av7110_hw.c b/drivers/media/pci/ttpci/av7110_hw.c index 8c2442a11f07..e8a8ec5405e2 100644 --- a/drivers/media/pci/ttpci/av7110_hw.c +++ b/drivers/media/pci/ttpci/av7110_hw.c @@ -14,7 +14,6 @@ /* for debugging ARM communication: */ //#define COM_DEBUG -#include <stdarg.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/string.h> diff --git a/drivers/media/pci/ttpci/av7110_ir.c b/drivers/media/pci/ttpci/av7110_ir.c index 432789a3c312..a851ba328e4a 100644 --- a/drivers/media/pci/ttpci/av7110_ir.c +++ b/drivers/media/pci/ttpci/av7110_ir.c @@ -37,12 +37,10 @@ void av7110_ir_handler(struct av7110 *av7110, u32 ircom) proto = RC_PROTO_RC5; break; - case IR_RCMM: /* RCMM: ? bits device address, ? bits command */ - command = ircom & 0xff; - addr = (ircom >> 8) & 0x1f; - scancode = ircom; + case IR_RCMM: /* RCMM: 32 bits scancode */ + scancode = ircom & ~0x8000; toggle = ircom & 0x8000; - proto = RC_PROTO_UNKNOWN; + proto = RC_PROTO_RCMM32; break; case IR_RC5_EXT: @@ -83,9 +81,9 @@ static int change_protocol(struct rc_dev *rcdev, u64 *rc_type) struct av7110 *av7110 = rcdev->priv; u32 ir_config; - if (*rc_type & RC_PROTO_BIT_UNKNOWN) { + if (*rc_type & RC_PROTO_BIT_RCMM32) { ir_config = IR_RCMM; - *rc_type = RC_PROTO_UNKNOWN; + *rc_type = RC_PROTO_BIT_RCMM32; } else if (*rc_type & RC_PROTO_BIT_RC5) { if (FW_VERSION(av7110->arm_app) >= 0x2620) ir_config = IR_RC5_EXT; @@ -133,7 +131,7 @@ int av7110_ir_init(struct av7110 *av7110) } rcdev->dev.parent = &pci->dev; - rcdev->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_UNKNOWN; + rcdev->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RCMM32; rcdev->change_protocol = change_protocol; rcdev->map_name = RC_MAP_HAUPPAUGE; rcdev->priv = av7110; diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 8e0952d65ad4..2fb82d50c53e 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -34,53 +34,43 @@ */ static const struct tw68_format formats[] = { { - .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555, .depth = 16, .twformat = ColorFormatRGB15, }, { - .name = "15 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB555X, .depth = 16, .twformat = ColorFormatRGB15 | ColorFormatBSWAP, }, { - .name = "16 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB565, .depth = 16, .twformat = ColorFormatRGB16, }, { - .name = "16 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB565X, .depth = 16, .twformat = ColorFormatRGB16 | ColorFormatBSWAP, }, { - .name = "24 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR24, .depth = 24, .twformat = ColorFormatRGB24, }, { - .name = "24 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB24, .depth = 24, .twformat = ColorFormatRGB24 | ColorFormatBSWAP, }, { - .name = "32 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR32, .depth = 32, .twformat = ColorFormatRGB32, }, { - .name = "32 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB32, .depth = 32, .twformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP, }, { - .name = "4:2:2 packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .twformat = ColorFormatYUY2, }, { - .name = "4:2:2 packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16, .twformat = ColorFormatYUY2 | ColorFormatBSWAP, @@ -592,7 +582,6 @@ static int tw68_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.priv = 0; return 0; } @@ -774,9 +763,6 @@ static int tw68_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index >= FORMATS) return -EINVAL; - strscpy(f->description, formats[f->index].name, - sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; return 0; diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h index 7021290d726a..a1f422d6e600 100644 --- a/drivers/media/pci/tw68/tw68.h +++ b/drivers/media/pci/tw68/tw68.h @@ -85,7 +85,6 @@ struct tw68_tvnorm { }; struct tw68_format { - char *name; u32 fourcc; u32 depth; u32 twformat; diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 8a19654b393a..83a785010753 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -16,7 +16,7 @@ source "drivers/media/platform/marvell-ccic/Kconfig" config VIDEO_VIA_CAMERA tristate "VIAFB camera controller support" depends on FB_VIA - select VIDEOBUF_DMA_SG + select VIDEOBUF2_DMA_SG select VIDEO_OV7670 help Driver support for the integrated camera controller in VIA @@ -121,7 +121,7 @@ config VIDEO_S3C_CAMIF config VIDEO_STM32_DCMI tristate "STM32 Digital Camera Memory Interface (DCMI) support" - depends on VIDEO_V4L2 && OF + depends on VIDEO_V4L2 && OF && MEDIA_CONTROLLER depends on ARCH_STM32 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE @@ -146,7 +146,7 @@ source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig" source "drivers/media/platform/rcar-vin/Kconfig" source "drivers/media/platform/atmel/Kconfig" -source "drivers/media/platform/sunxi/sun6i-csi/Kconfig" +source "drivers/media/platform/sunxi/Kconfig" config VIDEO_TI_CAL tristate "TI CAL (Camera Adaptation Layer) driver" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 7cbbd925124c..6ee7eb0d36f4 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -100,4 +100,4 @@ obj-y += meson/ obj-y += cros-ec-cec/ -obj-$(CONFIG_VIDEO_SUN6I_CSI) += sunxi/sun6i-csi/ +obj-y += sunxi/ diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index fe7b937eb5f2..2b42ba1f5949 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -76,7 +76,6 @@ struct bus_format { /* * struct vpfe_fmt - VPFE media bus format information - * @name: V4L2 format description * @code: V4L2 media bus format code * @shifted: V4L2 media bus format code for the same pixel layout but * shifted to be 8 bits per pixel. =0 if format is not shiftable. @@ -86,7 +85,6 @@ struct bus_format { * @supported: Indicates format supported by subdev */ struct vpfe_fmt { - const char *name; u32 fourcc; u32 code; struct bus_format l; @@ -97,7 +95,6 @@ struct vpfe_fmt { static struct vpfe_fmt formats[] = { { - .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, .code = MEDIA_BUS_FMT_YUYV8_2X8, .l.width = 10, @@ -106,7 +103,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 2, .supported = false, }, { - .name = "YUV 4:2:2 packed, CbYCrY", .fourcc = V4L2_PIX_FMT_UYVY, .code = MEDIA_BUS_FMT_UYVY8_2X8, .l.width = 10, @@ -115,7 +111,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 2, .supported = false, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_YVYU, .code = MEDIA_BUS_FMT_YVYU8_2X8, .l.width = 10, @@ -124,7 +119,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 2, .supported = false, }, { - .name = "YUV 4:2:2 packed, CrYCbY", .fourcc = V4L2_PIX_FMT_VYUY, .code = MEDIA_BUS_FMT_VYUY8_2X8, .l.width = 10, @@ -133,7 +127,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 2, .supported = false, }, { - .name = "RAW8 BGGR", .fourcc = V4L2_PIX_FMT_SBGGR8, .code = MEDIA_BUS_FMT_SBGGR8_1X8, .l.width = 10, @@ -142,7 +135,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 1, .supported = false, }, { - .name = "RAW8 GBRG", .fourcc = V4L2_PIX_FMT_SGBRG8, .code = MEDIA_BUS_FMT_SGBRG8_1X8, .l.width = 10, @@ -151,7 +143,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 1, .supported = false, }, { - .name = "RAW8 GRBG", .fourcc = V4L2_PIX_FMT_SGRBG8, .code = MEDIA_BUS_FMT_SGRBG8_1X8, .l.width = 10, @@ -160,7 +151,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 1, .supported = false, }, { - .name = "RAW8 RGGB", .fourcc = V4L2_PIX_FMT_SRGGB8, .code = MEDIA_BUS_FMT_SRGGB8_1X8, .l.width = 10, @@ -169,7 +159,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 1, .supported = false, }, { - .name = "RGB565 (LE)", .fourcc = V4L2_PIX_FMT_RGB565, .code = MEDIA_BUS_FMT_RGB565_2X8_LE, .l.width = 10, @@ -178,7 +167,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 2, .supported = false, }, { - .name = "RGB565 (BE)", .fourcc = V4L2_PIX_FMT_RGB565X, .code = MEDIA_BUS_FMT_RGB565_2X8_BE, .l.width = 10, @@ -1412,10 +1400,6 @@ static int vpfe_querycap(struct file *file, void *priv, strscpy(cap->card, "TI AM437x VPFE", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", vpfe->v4l2_dev.name); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1540,12 +1524,10 @@ static int vpfe_enum_fmt(struct file *file, void *priv, if (!fmt) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; - f->type = vpfe->fmt.type; - vpfe_dbg(1, vpfe, "vpfe_enum_format: mbus index: %d code: %x pixelformat: %s [%s]\n", - f->index, fmt->code, print_fourcc(fmt->fourcc), fmt->name); + vpfe_dbg(1, vpfe, "vpfe_enum_format: mbus index: %d code: %x pixelformat: %s\n", + f->index, fmt->code, print_fourcc(fmt->fourcc)); return 0; } @@ -2393,6 +2375,8 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) vdev->vfl_dir = VFL_DIR_RX; vdev->queue = q; vdev->lock = &vpfe->lock; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; video_set_drvdata(vdev, vpfe); err = video_register_device(&vpfe->video_dev, VFL_TYPE_GRABBER, -1); if (err) { @@ -2505,10 +2489,9 @@ vpfe_get_pdata(struct vpfe_device *vpfe) pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev( &vpfe->notifier, of_fwnode_handle(rem), sizeof(struct v4l2_async_subdev)); - if (IS_ERR(pdata->asd[i])) { - of_node_put(rem); + of_node_put(rem); + if (IS_ERR(pdata->asd[i])) goto cleanup; - } } of_node_put(endpoint); @@ -2557,7 +2540,6 @@ static int vpfe_probe(struct platform_device *pdev) ret = platform_get_irq(pdev, 0); if (ret <= 0) { - dev_err(&pdev->dev, "No IRQ resource\n"); ret = -ENODEV; goto probe_out_cleanup; } diff --git a/drivers/media/platform/am437x/am437x-vpfe.h b/drivers/media/platform/am437x/am437x-vpfe.h index 17d7aa426788..4678285f34c6 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.h +++ b/drivers/media/platform/am437x/am437x-vpfe.h @@ -65,12 +65,6 @@ struct vpfe_hw_if_param { #define VPFE_MAX_SUBDEV 1 #define VPFE_MAX_INPUTS 1 -struct vpfe_pixel_format { - struct v4l2_fmtdesc fmtdesc; - /* bytes per pixel */ - int bpp; -}; - struct vpfe_std_info { int active_pixels; int active_lines; diff --git a/drivers/media/platform/am437x/am437x-vpfe_regs.h b/drivers/media/platform/am437x/am437x-vpfe_regs.h index 4a0ed29723e8..0746c48ec23f 100644 --- a/drivers/media/platform/am437x/am437x-vpfe_regs.h +++ b/drivers/media/platform/am437x/am437x-vpfe_regs.h @@ -66,13 +66,13 @@ #define VPFE_PIX_FMT_MASK 3 #define VPFE_PIX_FMT_SHIFT 12 #define VPFE_VP2SDR_DISABLE 0xfffbffff -#define VPFE_WEN_ENABLE (1 << 17) +#define VPFE_WEN_ENABLE BIT(17) #define VPFE_SDR2RSZ_DISABLE 0xfff7ffff -#define VPFE_VDHDEN_ENABLE (1 << 16) -#define VPFE_LPF_ENABLE (1 << 14) -#define VPFE_ALAW_ENABLE (1 << 3) +#define VPFE_VDHDEN_ENABLE BIT(16) +#define VPFE_LPF_ENABLE BIT(14) +#define VPFE_ALAW_ENABLE BIT(3) #define VPFE_ALAW_GAMMA_WD_MASK 7 -#define VPFE_BLK_CLAMP_ENABLE (1 << 31) +#define VPFE_BLK_CLAMP_ENABLE BIT(31) #define VPFE_BLK_SGAIN_MASK 0x1f #define VPFE_BLK_ST_PXL_MASK 0x7fff #define VPFE_BLK_ST_PXL_SHIFT 10 @@ -85,8 +85,8 @@ #define VPFE_BLK_COMP_GB_COMP_SHIFT 8 #define VPFE_BLK_COMP_GR_COMP_SHIFT 16 #define VPFE_BLK_COMP_R_COMP_SHIFT 24 -#define VPFE_LATCH_ON_VSYNC_DISABLE (1 << 15) -#define VPFE_DATA_PACK_ENABLE (1 << 11) +#define VPFE_LATCH_ON_VSYNC_DISABLE BIT(15) +#define VPFE_DATA_PACK_ENABLE BIT(11) #define VPFE_HORZ_INFO_SPH_SHIFT 16 #define VPFE_VERT_START_SLV0_SHIFT 16 #define VPFE_VDINT_VDINT0_SHIFT 16 @@ -114,15 +114,15 @@ #define VPFE_SYN_FLDMODE_MASK 1 #define VPFE_SYN_FLDMODE_SHIFT 7 #define VPFE_REC656IF_BT656_EN 3 -#define VPFE_SYN_MODE_VD_POL_NEGATIVE (1 << 2) +#define VPFE_SYN_MODE_VD_POL_NEGATIVE BIT(2) #define VPFE_CCDCFG_Y8POS_SHIFT 11 -#define VPFE_CCDCFG_BW656_10BIT (1 << 5) +#define VPFE_CCDCFG_BW656_10BIT BIT(5) #define VPFE_SDOFST_FIELD_INTERLEAVED 0x249 #define VPFE_NO_CULLING 0xffff00ff -#define VPFE_VDINT0 (1 << 0) -#define VPFE_VDINT1 (1 << 1) -#define VPFE_VDINT2 (1 << 2) -#define VPFE_DMA_CNTL_OVERFLOW (1 << 31) +#define VPFE_VDINT0 BIT(0) +#define VPFE_VDINT1 BIT(1) +#define VPFE_VDINT2 BIT(2) +#define VPFE_DMA_CNTL_OVERFLOW BIT(31) #define VPFE_CONFIG_PCLK_INV_SHIFT 0 #define VPFE_CONFIG_PCLK_INV_MASK 1 diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index f899ac3b4a61..eb12f3793062 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -630,7 +630,7 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) } if (hsync_counter < 0 || vsync_counter < 0) { - u32 ctrl; + u32 ctrl = 0; if (hsync_counter < 0) { ctrl = VE_CTRL_HSYNC_POL; @@ -650,7 +650,8 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) V4L2_DV_VSYNC_POS_POL; } - aspeed_video_update(video, VE_CTRL, 0, ctrl); + if (ctrl) + aspeed_video_update(video, VE_CTRL, 0, ctrl); } } @@ -1624,6 +1625,7 @@ static int aspeed_video_init(struct aspeed_video *video) if (!aspeed_video_alloc_buf(video, &video->jpeg, VE_JPEG_HEADER_SIZE)) { dev_err(dev, "Failed to allocate DMA for JPEG header\n"); + rc = -ENOMEM; goto err_release_reserved_mem; } diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index d7d94c1a39d3..428f117caa59 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -493,7 +493,7 @@ static void stop_streaming(struct vb2_queue *vq) spin_unlock_irq(&isi->irqlock); if (!isi->enable_preview_path) { - timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; + timeout = jiffies + (FRAME_INTERVAL_MILLI_SEC * HZ) / 1000; /* Wait until the end of the current frame. */ while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && time_before(jiffies, timeout)) diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c index 266df14da2d5..78381651238d 100644 --- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -160,11 +160,8 @@ static int atmel_isc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - dev_err(dev, "failed to get irq: %d\n", ret); - return ret; - } + if (irq < 0) + return irq; ret = devm_request_irq(dev, irq, isc_interrupt, 0, ATMEL_ISC_NAME, isc); diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c index 5042d053b94e..e4d08acfbb49 100644 --- a/drivers/media/platform/cadence/cdns-csi2tx.c +++ b/drivers/media/platform/cadence/cdns-csi2tx.c @@ -2,7 +2,7 @@ /* * Driver for Cadence MIPI-CSI2 TX Controller * - * Copyright (C) 2017-2018 Cadence Design Systems Inc. + * Copyright (C) 2017-2019 Cadence Design Systems Inc. */ #include <linux/clk.h> @@ -52,6 +52,17 @@ #define CSI2TX_STREAM_IF_CFG_REG(n) (0x100 + (n) * 4) #define CSI2TX_STREAM_IF_CFG_FILL_LEVEL(n) ((n) & 0x1f) +/* CSI2TX V2 Registers */ +#define CSI2TX_V2_DPHY_CFG_REG 0x28 +#define CSI2TX_V2_DPHY_CFG_RESET BIT(16) +#define CSI2TX_V2_DPHY_CFG_CLOCK_MODE BIT(10) +#define CSI2TX_V2_DPHY_CFG_MODE_MASK GENMASK(9, 8) +#define CSI2TX_V2_DPHY_CFG_MODE_LPDT (2 << 8) +#define CSI2TX_V2_DPHY_CFG_MODE_HS (1 << 8) +#define CSI2TX_V2_DPHY_CFG_MODE_ULPS (0 << 8) +#define CSI2TX_V2_DPHY_CFG_CLK_ENABLE BIT(4) +#define CSI2TX_V2_DPHY_CFG_LANE_ENABLE(n) BIT(n) + #define CSI2TX_LANES_MAX 4 #define CSI2TX_STREAMS_MAX 4 @@ -70,6 +81,13 @@ struct csi2tx_fmt { u32 bpp; }; +struct csi2tx_priv; + +/* CSI2TX Variant Operations */ +struct csi2tx_vops { + void (*dphy_setup)(struct csi2tx_priv *csi2tx); +}; + struct csi2tx_priv { struct device *dev; unsigned int count; @@ -82,6 +100,8 @@ struct csi2tx_priv { void __iomem *base; + struct csi2tx_vops *vops; + struct clk *esc_clk; struct clk *p_clk; struct clk *pixel_clk[CSI2TX_STREAMS_MAX]; @@ -209,53 +229,92 @@ static const struct v4l2_subdev_pad_ops csi2tx_pad_ops = { .set_fmt = csi2tx_set_pad_format, }; -static void csi2tx_reset(struct csi2tx_priv *csi2tx) +/* Set Wake Up value in the D-PHY */ +static void csi2tx_dphy_set_wakeup(struct csi2tx_priv *csi2tx) { - writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG); - - udelay(10); + writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32), + csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG); } -static int csi2tx_start(struct csi2tx_priv *csi2tx) +/* + * Finishes the D-PHY initialization + * reg dphy cfg value to be used + */ +static void csi2tx_dphy_init_finish(struct csi2tx_priv *csi2tx, u32 reg) { - struct media_entity *entity = &csi2tx->subdev.entity; - struct media_link *link; unsigned int i; - u32 reg; - csi2tx_reset(csi2tx); + udelay(10); - writel(CSI2TX_CONFIG_CFG_REQ, csi2tx->base + CSI2TX_CONFIG_REG); + /* Enable our (clock and data) lanes */ + reg |= CSI2TX_DPHY_CFG_CLK_ENABLE; + for (i = 0; i < csi2tx->num_lanes; i++) + reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i] - 1); + writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG); udelay(10); - /* Configure our PPI interface with the D-PHY */ - writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32), - csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG); + /* Switch to HS mode */ + reg &= ~CSI2TX_DPHY_CFG_MODE_MASK; + writel(reg | CSI2TX_DPHY_CFG_MODE_HS, + csi2tx->base + CSI2TX_DPHY_CFG_REG); +} + +/* Configures D-PHY in CSIv1.3 */ +static void csi2tx_dphy_setup(struct csi2tx_priv *csi2tx) +{ + u32 reg; + unsigned int i; + + csi2tx_dphy_set_wakeup(csi2tx); /* Put our lanes (clock and data) out of reset */ reg = CSI2TX_DPHY_CFG_CLK_RESET | CSI2TX_DPHY_CFG_MODE_LPDT; for (i = 0; i < csi2tx->num_lanes; i++) - reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i]); + reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i] - 1); writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG); - udelay(10); + csi2tx_dphy_init_finish(csi2tx, reg); +} - /* Enable our (clock and data) lanes */ - reg |= CSI2TX_DPHY_CFG_CLK_ENABLE; - for (i = 0; i < csi2tx->num_lanes; i++) - reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i]); - writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG); +/* Configures D-PHY in CSIv2 */ +static void csi2tx_v2_dphy_setup(struct csi2tx_priv *csi2tx) +{ + u32 reg; + + csi2tx_dphy_set_wakeup(csi2tx); + + /* Put our lanes (clock and data) out of reset */ + reg = CSI2TX_V2_DPHY_CFG_RESET | CSI2TX_V2_DPHY_CFG_MODE_LPDT; + writel(reg, csi2tx->base + CSI2TX_V2_DPHY_CFG_REG); + + csi2tx_dphy_init_finish(csi2tx, reg); +} + +static void csi2tx_reset(struct csi2tx_priv *csi2tx) +{ + writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG); udelay(10); +} - /* Switch to HS mode */ - reg &= ~CSI2TX_DPHY_CFG_MODE_MASK; - writel(reg | CSI2TX_DPHY_CFG_MODE_HS, - csi2tx->base + CSI2TX_DPHY_CFG_REG); +static int csi2tx_start(struct csi2tx_priv *csi2tx) +{ + struct media_entity *entity = &csi2tx->subdev.entity; + struct media_link *link; + unsigned int i; + + csi2tx_reset(csi2tx); + + writel(CSI2TX_CONFIG_CFG_REQ, csi2tx->base + CSI2TX_CONFIG_REG); udelay(10); + if (csi2tx->vops && csi2tx->vops->dphy_setup) { + csi2tx->vops->dphy_setup(csi2tx); + udelay(10); + } + /* * Create a static mapping between the CSI virtual channels * and the input streams. @@ -434,7 +493,7 @@ static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx) { struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 }; struct device_node *ep; - int ret; + int ret, i; ep = of_graph_get_endpoint_by_regs(csi2tx->dev->of_node, 0, 0); if (!ep) @@ -461,6 +520,15 @@ static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx) goto out; } + for (i = 0; i < csi2tx->num_lanes; i++) { + if (v4l2_ep.bus.mipi_csi2.data_lanes[i] < 1) { + dev_err(csi2tx->dev, "Invalid lane[%d] number: %u\n", + i, v4l2_ep.bus.mipi_csi2.data_lanes[i]); + ret = -EINVAL; + goto out; + } + } + memcpy(csi2tx->lanes, v4l2_ep.bus.mipi_csi2.data_lanes, sizeof(csi2tx->lanes)); @@ -469,9 +537,35 @@ out: return ret; } +static const struct csi2tx_vops csi2tx_vops = { + .dphy_setup = csi2tx_dphy_setup, +}; + +static const struct csi2tx_vops csi2tx_v2_vops = { + .dphy_setup = csi2tx_v2_dphy_setup, +}; + +static const struct of_device_id csi2tx_of_table[] = { + { + .compatible = "cdns,csi2tx", + .data = &csi2tx_vops + }, + { + .compatible = "cdns,csi2tx-1.3", + .data = &csi2tx_vops + }, + { + .compatible = "cdns,csi2tx-2.1", + .data = &csi2tx_v2_vops + }, + { } +}; +MODULE_DEVICE_TABLE(of, csi2tx_of_table); + static int csi2tx_probe(struct platform_device *pdev) { struct csi2tx_priv *csi2tx; + const struct of_device_id *of_id; unsigned int i; int ret; @@ -486,6 +580,9 @@ static int csi2tx_probe(struct platform_device *pdev) if (ret) goto err_free_priv; + of_id = of_match_node(csi2tx_of_table, pdev->dev.of_node); + csi2tx->vops = (struct csi2tx_vops *)of_id->data; + v4l2_subdev_init(&csi2tx->subdev, &csi2tx_subdev_ops); csi2tx->subdev.owner = THIS_MODULE; csi2tx->subdev.dev = &pdev->dev; @@ -543,12 +640,6 @@ static int csi2tx_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id csi2tx_of_table[] = { - { .compatible = "cdns,csi2tx" }, - { }, -}; -MODULE_DEVICE_TABLE(of, csi2tx_of_table); - static struct platform_driver csi2tx_driver = { .probe = csi2tx_probe, .remove = csi2tx_remove, diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 01428de2596e..73222c0615c0 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -390,9 +390,6 @@ static int coda_querycap(struct file *file, void *priv, strscpy(cap->card, coda_product_name(ctx->dev->devtype->product), sizeof(cap->card)); strscpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -2699,6 +2696,7 @@ static int coda_register_device(struct coda_dev *dev, int i) vfd->lock = &dev->dev_mutex; vfd->v4l2_dev = &dev->v4l2_dev; vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; video_set_drvdata(vfd, dev); /* Not applicable, use the selection API instead */ diff --git a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c index 068df9888dbf..76ab83f55cc0 100644 --- a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c +++ b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c @@ -206,10 +206,10 @@ static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops, */ struct cec_dmi_match { - char *sys_vendor; - char *product_name; - char *devname; - char *conn; + const char *sys_vendor; + const char *product_name; + const char *devname; + const char *conn; }; static const struct cec_dmi_match cec_dmi_match_table[] = { @@ -217,8 +217,8 @@ static const struct cec_dmi_match cec_dmi_match_table[] = { { "Google", "Fizz", "0000:00:02.0", "Port B" }, }; -static int cros_ec_cec_get_notifier(struct device *dev, - struct cec_notifier **notify) +static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, + const char **conn) { int i; @@ -233,26 +233,25 @@ static int cros_ec_cec_get_notifier(struct device *dev, d = bus_find_device_by_name(&pci_bus_type, NULL, m->devname); if (!d) - return -EPROBE_DEFER; - - *notify = cec_notifier_get_conn(d, m->conn); + return ERR_PTR(-EPROBE_DEFER); put_device(d); - return 0; + *conn = m->conn; + return d; } } /* Hardware support must be added in the cec_dmi_match_table */ dev_warn(dev, "CEC notifier not configured for this hardware\n"); - return -ENODEV; + return ERR_PTR(-ENODEV); } #else -static int cros_ec_cec_get_notifier(struct device *dev, - struct cec_notifier **notify) +static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, + const char **conn) { - return -ENODEV; + return ERR_PTR(-ENODEV); } #endif @@ -262,8 +261,14 @@ static int cros_ec_cec_probe(struct platform_device *pdev) struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); struct cros_ec_device *cros_ec = ec_dev->ec_dev; struct cros_ec_cec *cros_ec_cec; + struct device *hdmi_dev; + const char *conn = NULL; int ret; + hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn); + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); + cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec), GFP_KERNEL); if (!cros_ec_cec) @@ -272,10 +277,6 @@ static int cros_ec_cec_probe(struct platform_device *pdev) platform_set_drvdata(pdev, cros_ec_cec); cros_ec_cec->cros_ec = cros_ec; - ret = cros_ec_cec_get_notifier(&pdev->dev, &cros_ec_cec->notify); - if (ret) - return ret; - ret = device_init_wakeup(&pdev->dev, 1); if (ret) { dev_err(&pdev->dev, "failed to initialize wakeup\n"); @@ -283,29 +284,39 @@ static int cros_ec_cec_probe(struct platform_device *pdev) } cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec, - DRV_NAME, CEC_CAP_DEFAULTS, 1); + DRV_NAME, + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, 1); if (IS_ERR(cros_ec_cec->adap)) return PTR_ERR(cros_ec_cec->adap); + cros_ec_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, conn, + cros_ec_cec->adap); + if (!cros_ec_cec->notify) { + ret = -ENOMEM; + goto out_probe_adapter; + } + /* Get CEC events from the EC. */ cros_ec_cec->notifier.notifier_call = cros_ec_cec_event; ret = blocking_notifier_chain_register(&cros_ec->event_notifier, &cros_ec_cec->notifier); if (ret) { dev_err(&pdev->dev, "failed to register notifier\n"); - cec_delete_adapter(cros_ec_cec->adap); - return ret; + goto out_probe_notify; } ret = cec_register_adapter(cros_ec_cec->adap, &pdev->dev); - if (ret < 0) { - cec_delete_adapter(cros_ec_cec->adap); - return ret; - } - - cec_register_cec_notifier(cros_ec_cec->adap, cros_ec_cec->notify); + if (ret < 0) + goto out_probe_notify; return 0; + +out_probe_notify: + cec_notifier_cec_adap_unregister(cros_ec_cec->notify); +out_probe_adapter: + cec_delete_adapter(cros_ec_cec->adap); + return ret; } static int cros_ec_cec_remove(struct platform_device *pdev) @@ -323,11 +334,9 @@ static int cros_ec_cec_remove(struct platform_device *pdev) return ret; } + cec_notifier_cec_adap_unregister(cros_ec_cec->notify); cec_unregister_adapter(cros_ec_cec->adap); - if (cros_ec_cec->notify) - cec_notifier_put(cros_ec_cec->notify); - return 0; } diff --git a/drivers/media/platform/davinci/dm644x_ccdc_regs.h b/drivers/media/platform/davinci/dm644x_ccdc_regs.h index 3ae301320313..c4894f6a254e 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc_regs.h +++ b/drivers/media/platform/davinci/dm644x_ccdc_regs.h @@ -66,13 +66,13 @@ #define CCDC_PIX_FMT_MASK 3 #define CCDC_PIX_FMT_SHIFT 12 #define CCDC_VP2SDR_DISABLE 0xFFFBFFFF -#define CCDC_WEN_ENABLE (1 << 17) +#define CCDC_WEN_ENABLE BIT(17) #define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF -#define CCDC_VDHDEN_ENABLE (1 << 16) -#define CCDC_LPF_ENABLE (1 << 14) -#define CCDC_ALAW_ENABLE (1 << 3) +#define CCDC_VDHDEN_ENABLE BIT(16) +#define CCDC_LPF_ENABLE BIT(14) +#define CCDC_ALAW_ENABLE BIT(3) #define CCDC_ALAW_GAMMA_WD_MASK 7 -#define CCDC_BLK_CLAMP_ENABLE (1 << 31) +#define CCDC_BLK_CLAMP_ENABLE BIT(31) #define CCDC_BLK_SGAIN_MASK 0x1F #define CCDC_BLK_ST_PXL_MASK 0x7FFF #define CCDC_BLK_ST_PXL_SHIFT 10 @@ -85,11 +85,11 @@ #define CCDC_BLK_COMP_GB_COMP_SHIFT 8 #define CCDC_BLK_COMP_GR_COMP_SHIFT 16 #define CCDC_BLK_COMP_R_COMP_SHIFT 24 -#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) -#define CCDC_FPC_ENABLE (1 << 15) +#define CCDC_LATCH_ON_VSYNC_DISABLE BIT(15) +#define CCDC_FPC_ENABLE BIT(15) #define CCDC_FPC_DISABLE 0 #define CCDC_FPC_FPC_NUM_MASK 0x7FFF -#define CCDC_DATA_PACK_ENABLE (1 << 11) +#define CCDC_DATA_PACK_ENABLE BIT(11) #define CCDC_FMTCFG_VPIN_MASK 7 #define CCDC_FMTCFG_VPIN_SHIFT 12 #define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF @@ -132,9 +132,9 @@ #define CCDC_SYN_FLDMODE_MASK 1 #define CCDC_SYN_FLDMODE_SHIFT 7 #define CCDC_REC656IF_BT656_EN 3 -#define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2) +#define CCDC_SYN_MODE_VD_POL_NEGATIVE BIT(2) #define CCDC_CCDCFG_Y8POS_SHIFT 11 -#define CCDC_CCDCFG_BW656_10BIT (1 << 5) +#define CCDC_CCDCFG_BW656_10BIT BIT(5) #define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 #define CCDC_NO_CULLING 0xffff00ff #endif diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 000b191c42d8..ae419958e420 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -19,10 +19,6 @@ #include <asm/pgtable.h> -#ifdef CONFIG_ARCH_DAVINCI -#include <mach/cputype.h> -#endif - #include <media/v4l2-dev.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> @@ -633,8 +629,6 @@ static int vpbe_display_querycap(struct file *file, void *priv, struct vpbe_layer *layer = video_drvdata(file); struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpbe_dev->pdev)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", @@ -792,7 +786,6 @@ static int vpbe_display_enum_fmt(struct file *file, void *priv, { struct vpbe_layer *layer = video_drvdata(file); struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - unsigned int index = 0; v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_FMT, layer id = %d\n", @@ -803,19 +796,10 @@ static int vpbe_display_enum_fmt(struct file *file, void *priv, } /* Fill in the information about format */ - index = fmt->index; - memset(fmt, 0, sizeof(*fmt)); - fmt->index = index; - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - if (index == 0) { - strscpy(fmt->description, "YUV 4:2:2 - UYVY", - sizeof(fmt->description)); + if (fmt->index == 0) fmt->pixelformat = V4L2_PIX_FMT_UYVY; - } else { - strscpy(fmt->description, "Y/CbCr 4:2:0", - sizeof(fmt->description)); + else fmt->pixelformat = V4L2_PIX_FMT_NV12; - } return 0; } @@ -1319,6 +1303,7 @@ static int init_vpbe_layer(int i, struct vpbe_display *disp_dev, vbd->v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev; vbd->lock = &vpbe_display_layer->opslock; vbd->vfl_dir = VFL_DIR_TX; + vbd->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; if (disp_dev->vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c index 491842ef33c5..91b571a0ac2c 100644 --- a/drivers/media/platform/davinci/vpbe_osd.c +++ b/drivers/media/platform/davinci/vpbe_osd.c @@ -16,11 +16,6 @@ #include <linux/clk.h> #include <linux/slab.h> -#ifdef CONFIG_ARCH_DAVINCI -#include <mach/cputype.h> -#include <mach/hardware.h> -#endif - #include <media/davinci/vpss.h> #include <media/v4l2-device.h> #include <media/davinci/vpbe_types.h> diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index 425f91f07165..8caa084e5704 100644 --- a/drivers/media/platform/davinci/vpbe_venc.c +++ b/drivers/media/platform/davinci/vpbe_venc.c @@ -14,11 +14,6 @@ #include <linux/videodev2.h> #include <linux/slab.h> -#ifdef CONFIG_ARCH_DAVINCI -#include <mach/hardware.h> -#include <mach/mux.h> -#endif - #include <linux/platform_data/i2c-davinci.h> #include <linux/io.h> diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 295fbf1a49cf..916ed743d716 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -119,57 +119,27 @@ static const struct vpfe_standard vpfe_standards[] = { /* Used when raw Bayer image from ccdc is directly captured to SDRAM */ static const struct vpfe_pixel_format vpfe_pix_fmts[] = { { - .fmtdesc = { - .index = 0, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb 8bit A-Law compr.", - .pixelformat = V4L2_PIX_FMT_SBGGR8, - }, + .pixelformat = V4L2_PIX_FMT_SBGGR8, .bpp = 1, }, { - .fmtdesc = { - .index = 1, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb - 16bit", - .pixelformat = V4L2_PIX_FMT_SBGGR16, - }, + .pixelformat = V4L2_PIX_FMT_SBGGR16, .bpp = 2, }, { - .fmtdesc = { - .index = 2, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb 8bit DPCM compr.", - .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, - }, + .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, .bpp = 1, }, { - .fmtdesc = { - .index = 3, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "YCbCr 4:2:2 Interleaved UYVY", - .pixelformat = V4L2_PIX_FMT_UYVY, - }, + .pixelformat = V4L2_PIX_FMT_UYVY, .bpp = 2, }, { - .fmtdesc = { - .index = 4, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "YCbCr 4:2:2 Interleaved YUYV", - .pixelformat = V4L2_PIX_FMT_YUYV, - }, + .pixelformat = V4L2_PIX_FMT_YUYV, .bpp = 2, }, { - .fmtdesc = { - .index = 5, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Y/CbCr 4:2:0 - Semi planar", - .pixelformat = V4L2_PIX_FMT_NV12, - }, + .pixelformat = V4L2_PIX_FMT_NV12, .bpp = 1, }, }; @@ -183,7 +153,7 @@ static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) int i; for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) { - if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat) + if (pix_format == vpfe_pix_fmts[i].pixelformat) return &vpfe_pix_fmts[i]; } return NULL; @@ -782,7 +752,7 @@ static const struct vpfe_pixel_format * temp = 0; found = 0; while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) { - if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) { + if (vpfe_pix_fmt->pixelformat == pix) { found = 1; break; } @@ -877,8 +847,6 @@ static int vpfe_querycap(struct file *file, void *priv, v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); strscpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); strscpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); @@ -901,7 +869,6 @@ static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, { struct vpfe_device *vpfe_dev = video_drvdata(file); const struct vpfe_pixel_format *pix_fmt; - int temp_index; u32 pix; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n"); @@ -912,9 +879,7 @@ static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, /* Fill in the information about format */ pix_fmt = vpfe_lookup_pix_format(pix); if (pix_fmt) { - temp_index = fmt->index; - *fmt = pix_fmt->fmtdesc; - fmt->index = temp_index; + fmt->pixelformat = fmt->pixelformat; return 0; } return -EINVAL; @@ -1785,6 +1750,7 @@ static int vpfe_probe(struct platform_device *pdev) vfd->ioctl_ops = &vpfe_ioctl_ops; vfd->tvnorms = 0; vfd->v4l2_dev = &vpfe_dev->v4l2_dev; + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; snprintf(vfd->name, sizeof(vfd->name), "%s_V%d.%d.%d", CAPTURE_DRV_NAME, diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index f0f7ef638c56..71f4fe882d13 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -938,17 +938,10 @@ static int vpif_enum_fmt_vid_cap(struct file *file, void *priv, } /* Fill in the information about format */ - if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) { - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strscpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb", - sizeof(fmt->description)); + if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) fmt->pixelformat = V4L2_PIX_FMT_SBGGR8; - } else { - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strscpy(fmt->description, "YCbCr4:2:2 Semi-Planar", - sizeof(fmt->description)); + else fmt->pixelformat = V4L2_PIX_FMT_NV16; - } return 0; } @@ -979,7 +972,6 @@ static int vpif_try_fmt_vid_cap(struct file *file, void *priv, pixfmt->bytesperline = common->fmt.fmt.pix.width * 2; pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; } - pixfmt->priv = 0; dev_dbg(vpif_dev, "%s: %d x %d; pitch=%d pixelformat=0x%08x, field=%d, size=%d\n", __func__, pixfmt->width, pixfmt->height, @@ -1085,8 +1077,6 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_capture_config *config = vpif_dev->platform_data; - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(vpif_dev)); @@ -1473,6 +1463,7 @@ static int vpif_probe_complete(void) vdev->vfl_dir = VFL_DIR_RX; vdev->queue = q; vdev->lock = &common->lock; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; video_set_drvdata(&ch->video_dev, ch); err = video_register_device(vdev, VFL_TYPE_GRABBER, (j ? 1 : 0)); @@ -1511,6 +1502,7 @@ static struct vpif_capture_config * vpif_capture_get_pdata(struct platform_device *pdev) { struct device_node *endpoint = NULL; + struct device_node *rem = NULL; struct vpif_capture_config *pdata; struct vpif_subdev_info *sdinfo; struct vpif_capture_chan_config *chan; @@ -1541,7 +1533,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) for (i = 0; i < VPIF_CAPTURE_NUM_CHANNELS; i++) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; - struct device_node *rem; unsigned int flags; int err; @@ -1554,7 +1545,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) if (!rem) { dev_dbg(&pdev->dev, "Remote device at %pOF not found\n", endpoint); - of_node_put(endpoint); goto done; } @@ -1564,11 +1554,8 @@ vpif_capture_get_pdata(struct platform_device *pdev) VPIF_CAPTURE_NUM_CHANNELS, sizeof(*chan->inputs), GFP_KERNEL); - if (!chan->inputs) { - of_node_put(rem); - of_node_put(endpoint); + if (!chan->inputs) goto err_cleanup; - } chan->input_count++; chan->inputs[i].input.type = V4L2_INPUT_TYPE_CAMERA; @@ -1577,7 +1564,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) err = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), &bus_cfg); - of_node_put(endpoint); if (err) { dev_err(&pdev->dev, "Could not parse the endpoint\n"); of_node_put(rem); @@ -1601,13 +1587,14 @@ vpif_capture_get_pdata(struct platform_device *pdev) pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev( &vpif_obj.notifier, of_fwnode_handle(rem), sizeof(struct v4l2_async_subdev)); - if (IS_ERR(pdata->asd[i])) { - of_node_put(rem); + if (IS_ERR(pdata->asd[i])) goto err_cleanup; - } + + of_node_put(rem); } done: + of_node_put(endpoint); pdata->asd_sizes[0] = i; pdata->subdev_count = i; pdata->card_name = "DA850/OMAP-L138 Video Capture"; @@ -1615,6 +1602,8 @@ done: return pdata; err_cleanup: + of_node_put(rem); + of_node_put(endpoint); v4l2_async_notifier_cleanup(&vpif_obj.notifier); return NULL; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index a69897c68a50..abbdbac08e6f 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -584,8 +584,6 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_display_config *config = vpif_dev->platform_data; - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(vpif_dev)); @@ -601,11 +599,7 @@ static int vpif_enum_fmt_vid_out(struct file *file, void *priv, return -EINVAL; /* Fill in the information about format */ - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - strscpy(fmt->description, "YCbCr4:2:2 YC Planar", - sizeof(fmt->description)); fmt->pixelformat = V4L2_PIX_FMT_YUV422P; - fmt->flags = 0; return 0; } @@ -1218,6 +1212,7 @@ static int vpif_probe_complete(void) vdev->vfl_dir = VFL_DIR_TX; vdev->queue = q; vdev->lock = &common->lock; + vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; video_set_drvdata(&ch->video_dev, ch); err = video_register_device(vdev, VFL_TYPE_GRABBER, (j ? 3 : 2)); diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 854869f0024e..f6650b45bc3d 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -27,21 +27,18 @@ static const struct gsc_fmt gsc_formats[] = { { - .name = "RGB565", .pixelformat = V4L2_PIX_FMT_RGB565X, .depth = { 16 }, .color = GSC_RGB, .num_planes = 1, .num_comp = 1, }, { - .name = "BGRX-8-8-8-8, 32 bpp", .pixelformat = V4L2_PIX_FMT_BGR32, .depth = { 32 }, .color = GSC_RGB, .num_planes = 1, .num_comp = 1, }, { - .name = "YUV 4:2:2 packed, YCbYCr", .pixelformat = V4L2_PIX_FMT_YUYV, .depth = { 16 }, .color = GSC_YUV422, @@ -51,7 +48,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_comp = 1, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, }, { - .name = "YUV 4:2:2 packed, CbYCrY", .pixelformat = V4L2_PIX_FMT_UYVY, .depth = { 16 }, .color = GSC_YUV422, @@ -61,7 +57,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_comp = 1, .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, }, { - .name = "YUV 4:2:2 packed, CrYCbY", .pixelformat = V4L2_PIX_FMT_VYUY, .depth = { 16 }, .color = GSC_YUV422, @@ -71,7 +66,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_comp = 1, .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .pixelformat = V4L2_PIX_FMT_YVYU, .depth = { 16 }, .color = GSC_YUV422, @@ -81,7 +75,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_comp = 1, .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, }, { - .name = "YUV 4:4:4 planar, YCbYCr", .pixelformat = V4L2_PIX_FMT_YUV32, .depth = { 32 }, .color = GSC_YUV444, @@ -90,7 +83,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 1, }, { - .name = "YUV 4:2:2 planar, Y/Cb/Cr", .pixelformat = V4L2_PIX_FMT_YUV422P, .depth = { 16 }, .color = GSC_YUV422, @@ -99,7 +91,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 3, }, { - .name = "YUV 4:2:2 planar, Y/CbCr", .pixelformat = V4L2_PIX_FMT_NV16, .depth = { 16 }, .color = GSC_YUV422, @@ -108,7 +99,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 2, }, { - .name = "YUV 4:2:2 non-contig, Y/CbCr", .pixelformat = V4L2_PIX_FMT_NV16M, .depth = { 8, 8 }, .color = GSC_YUV422, @@ -117,7 +107,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 2, .num_comp = 2, }, { - .name = "YUV 4:2:2 planar, Y/CrCb", .pixelformat = V4L2_PIX_FMT_NV61, .depth = { 16 }, .color = GSC_YUV422, @@ -126,7 +115,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 2, }, { - .name = "YUV 4:2:2 non-contig, Y/CrCb", .pixelformat = V4L2_PIX_FMT_NV61M, .depth = { 8, 8 }, .color = GSC_YUV422, @@ -135,7 +123,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 2, .num_comp = 2, }, { - .name = "YUV 4:2:0 planar, YCbCr", .pixelformat = V4L2_PIX_FMT_YUV420, .depth = { 12 }, .color = GSC_YUV420, @@ -144,7 +131,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 3, }, { - .name = "YUV 4:2:0 planar, YCrCb", .pixelformat = V4L2_PIX_FMT_YVU420, .depth = { 12 }, .color = GSC_YUV420, @@ -154,7 +140,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_comp = 3, }, { - .name = "YUV 4:2:0 planar, Y/CbCr", .pixelformat = V4L2_PIX_FMT_NV12, .depth = { 12 }, .color = GSC_YUV420, @@ -163,7 +148,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 2, }, { - .name = "YUV 4:2:0 planar, Y/CrCb", .pixelformat = V4L2_PIX_FMT_NV21, .depth = { 12 }, .color = GSC_YUV420, @@ -172,7 +156,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 2, }, { - .name = "YUV 4:2:0 non-contig. 2p, Y/CrCb", .pixelformat = V4L2_PIX_FMT_NV21M, .depth = { 8, 4 }, .color = GSC_YUV420, @@ -181,7 +164,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 2, .num_comp = 2, }, { - .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr", .pixelformat = V4L2_PIX_FMT_NV12M, .depth = { 8, 4 }, .color = GSC_YUV420, @@ -190,7 +172,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 2, .num_comp = 2, }, { - .name = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr", .pixelformat = V4L2_PIX_FMT_YUV420M, .depth = { 8, 2, 2 }, .color = GSC_YUV420, @@ -199,7 +180,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 3, .num_comp = 3, }, { - .name = "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb", .pixelformat = V4L2_PIX_FMT_YVU420M, .depth = { 8, 2, 2 }, .color = GSC_YUV420, @@ -208,7 +188,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 3, .num_comp = 3, }, { - .name = "YUV 4:2:0 n.c. 2p, Y/CbCr tiled", .pixelformat = V4L2_PIX_FMT_NV12MT_16X16, .depth = { 8, 4 }, .color = GSC_YUV420, @@ -335,7 +314,6 @@ int gsc_enum_fmt(struct v4l2_fmtdesc *f) if (!fmt) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->pixelformat; return 0; diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index 772183b090c2..8e5a9acb78aa 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -103,7 +103,6 @@ enum gsc_yuv_fmt { /** * struct gsc_fmt - the driver's internal color format data * @mbus_code: Media Bus pixel code, -1 if not applicable - * @name: format description * @pixelformat: the fourcc code for this format, 0 if not applicable * @yorder: Y/C order * @corder: Chrominance order control @@ -114,7 +113,6 @@ enum gsc_yuv_fmt { */ struct gsc_fmt { u32 mbus_code; - char *name; u32 pixelformat; u32 color; u32 yorder; diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 66510365dd5d..121d609ff856 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -738,10 +738,7 @@ static int fimc_cap_enum_fmt(struct file *file, void *priv, f->index); if (!fmt) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; - if (fmt->fourcc == MEDIA_BUS_FMT_JPEG_1X8) - f->flags |= V4L2_FMT_FLAG_COMPRESSED; return 0; } diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index 7006f54bfee2..cde60fbb23a8 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -36,7 +36,6 @@ static char *fimc_clocks[MAX_FIMC_CLOCKS] = { static struct fimc_fmt fimc_formats[] = { { - .name = "RGB565", .fourcc = V4L2_PIX_FMT_RGB565, .depth = { 16 }, .color = FIMC_FMT_RGB565, @@ -44,7 +43,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M, }, { - .name = "BGR666", .fourcc = V4L2_PIX_FMT_BGR666, .depth = { 32 }, .color = FIMC_FMT_RGB666, @@ -52,7 +50,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M, }, { - .name = "BGRA8888, 32 bpp", .fourcc = V4L2_PIX_FMT_BGR32, .depth = { 32 }, .color = FIMC_FMT_RGB888, @@ -60,7 +57,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M | FMT_HAS_ALPHA, }, { - .name = "ARGB1555", .fourcc = V4L2_PIX_FMT_RGB555, .depth = { 16 }, .color = FIMC_FMT_RGB555, @@ -68,7 +64,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, }, { - .name = "ARGB4444", .fourcc = V4L2_PIX_FMT_RGB444, .depth = { 16 }, .color = FIMC_FMT_RGB444, @@ -76,11 +71,9 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, }, { - .name = "YUV 4:4:4", .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, .flags = FMT_FLAGS_WRITEBACK, }, { - .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, .depth = { 16 }, .color = FIMC_FMT_YCBYCR422, @@ -89,7 +82,6 @@ static struct fimc_fmt fimc_formats[] = { .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 packed, CbYCrY", .fourcc = V4L2_PIX_FMT_UYVY, .depth = { 16 }, .color = FIMC_FMT_CBYCRY422, @@ -98,7 +90,6 @@ static struct fimc_fmt fimc_formats[] = { .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 packed, CrYCbY", .fourcc = V4L2_PIX_FMT_VYUY, .depth = { 16 }, .color = FIMC_FMT_CRYCBY422, @@ -107,7 +98,6 @@ static struct fimc_fmt fimc_formats[] = { .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_YVYU, .depth = { 16 }, .color = FIMC_FMT_YCRYCB422, @@ -116,7 +106,6 @@ static struct fimc_fmt fimc_formats[] = { .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 planar, Y/Cb/Cr", .fourcc = V4L2_PIX_FMT_YUV422P, .depth = { 16 }, .color = FIMC_FMT_YCBYCR422, @@ -124,7 +113,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 3, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:2 planar, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV16, .depth = { 16 }, .color = FIMC_FMT_YCBYCR422, @@ -132,7 +120,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:2 planar, Y/CrCb", .fourcc = V4L2_PIX_FMT_NV61, .depth = { 16 }, .color = FIMC_FMT_YCRYCB422, @@ -140,7 +127,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 planar, YCbCr", .fourcc = V4L2_PIX_FMT_YUV420, .depth = { 12 }, .color = FIMC_FMT_YCBCR420, @@ -148,7 +134,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 3, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 planar, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV12, .depth = { 12 }, .color = FIMC_FMT_YCBCR420, @@ -156,7 +141,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV12M, .color = FIMC_FMT_YCBCR420, .depth = { 8, 4 }, @@ -164,7 +148,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr", .fourcc = V4L2_PIX_FMT_YUV420M, .color = FIMC_FMT_YCBCR420, .depth = { 8, 2, 2 }, @@ -172,7 +155,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 3, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 non-contig. 2p, tiled", .fourcc = V4L2_PIX_FMT_NV12MT, .color = FIMC_FMT_YCBCR420, .depth = { 8, 4 }, @@ -180,7 +162,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "JPEG encoded data", .fourcc = V4L2_PIX_FMT_JPEG, .color = FIMC_FMT_JPEG, .depth = { 8 }, @@ -189,7 +170,6 @@ static struct fimc_fmt fimc_formats[] = { .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, }, { - .name = "S5C73MX interleaved UYVY/JPEG", .fourcc = V4L2_PIX_FMT_S5C_UYVY_JPG, .color = FIMC_FMT_YUYV_JPEG, .depth = { 8 }, diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index e043d55133a3..64148b7e0d98 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -341,7 +341,6 @@ static int fimc_is_alloc_cpu_memory(struct fimc_is *is) return -ENOMEM; is->memory.size = FIMC_IS_CPU_MEM_SIZE; - memset(is->memory.vaddr, 0, is->memory.size); dev_info(dev, "FIMC-IS CPU memory base: %#x\n", (u32)is->memory.paddr); @@ -806,6 +805,7 @@ static int fimc_is_probe(struct platform_device *pdev) return -ENODEV; is->pmu_regs = of_iomap(node, 0); + of_node_put(node); if (!is->pmu_regs) return -ENOMEM; diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index a75f932a289a..378cc302e1f8 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -362,7 +362,6 @@ static int isp_video_enum_fmt(struct file *file, void *priv, if (WARN_ON(fmt == NULL)) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 907b83e6649d..cde0d254ec1c 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -33,21 +33,18 @@ module_param_named(debug_isp, fimc_isp_debug, int, S_IRUGO | S_IWUSR); static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = { { - .name = "RAW8 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG8, .depth = { 8 }, .color = FIMC_FMT_RAW8, .memplanes = 1, .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, }, { - .name = "RAW10 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG10, .depth = { 10 }, .color = FIMC_FMT_RAW10, .memplanes = 1, .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, }, { - .name = "RAW12 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG12, .depth = { 12 }, .color = FIMC_FMT_RAW12, diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.h b/drivers/media/platform/exynos4-is/fimc-lite-reg.h index 48f2cf1148b8..c5656e902750 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.h @@ -6,6 +6,8 @@ #ifndef FIMC_LITE_REG_H_ #define FIMC_LITE_REG_H_ +#include <linux/bitops.h> + #include "fimc-lite.h" /* Camera Source size */ @@ -27,27 +29,27 @@ /* User defined formats. x = 0...15 */ #define FLITE_REG_CIGCTRL_USER(x) ((0x30 + x - 1) << 24) #define FLITE_REG_CIGCTRL_FMT_MASK (0x3f << 24) -#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE (1 << 21) -#define FLITE_REG_CIGCTRL_ODMA_DISABLE (1 << 20) -#define FLITE_REG_CIGCTRL_SWRST_REQ (1 << 19) -#define FLITE_REG_CIGCTRL_SWRST_RDY (1 << 18) -#define FLITE_REG_CIGCTRL_SWRST (1 << 17) -#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR (1 << 15) -#define FLITE_REG_CIGCTRL_INVPOLPCLK (1 << 14) -#define FLITE_REG_CIGCTRL_INVPOLVSYNC (1 << 13) -#define FLITE_REG_CIGCTRL_INVPOLHREF (1 << 12) +#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE BIT(21) +#define FLITE_REG_CIGCTRL_ODMA_DISABLE BIT(20) +#define FLITE_REG_CIGCTRL_SWRST_REQ BIT(19) +#define FLITE_REG_CIGCTRL_SWRST_RDY BIT(18) +#define FLITE_REG_CIGCTRL_SWRST BIT(17) +#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR BIT(15) +#define FLITE_REG_CIGCTRL_INVPOLPCLK BIT(14) +#define FLITE_REG_CIGCTRL_INVPOLVSYNC BIT(13) +#define FLITE_REG_CIGCTRL_INVPOLHREF BIT(12) /* Interrupts mask bits (1 disables an interrupt) */ -#define FLITE_REG_CIGCTRL_IRQ_LASTEN (1 << 8) -#define FLITE_REG_CIGCTRL_IRQ_ENDEN (1 << 7) -#define FLITE_REG_CIGCTRL_IRQ_STARTEN (1 << 6) -#define FLITE_REG_CIGCTRL_IRQ_OVFEN (1 << 5) +#define FLITE_REG_CIGCTRL_IRQ_LASTEN BIT(8) +#define FLITE_REG_CIGCTRL_IRQ_ENDEN BIT(7) +#define FLITE_REG_CIGCTRL_IRQ_STARTEN BIT(6) +#define FLITE_REG_CIGCTRL_IRQ_OVFEN BIT(5) #define FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK (0xf << 5) -#define FLITE_REG_CIGCTRL_SELCAM_MIPI (1 << 3) +#define FLITE_REG_CIGCTRL_SELCAM_MIPI BIT(3) /* Image Capture Enable */ #define FLITE_REG_CIIMGCPT 0x08 -#define FLITE_REG_CIIMGCPT_IMGCPTEN (1 << 31) -#define FLITE_REG_CIIMGCPT_CPT_FREN (1 << 25) +#define FLITE_REG_CIIMGCPT_IMGCPTEN BIT(31) +#define FLITE_REG_CIIMGCPT_CPT_FREN BIT(25) #define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT (1 << 18) #define FLITE_REG_CIIMGCPT_CPT_MOD_FREN (0 << 18) @@ -56,10 +58,10 @@ /* Camera Window Offset */ #define FLITE_REG_CIWDOFST 0x10 -#define FLITE_REG_CIWDOFST_WINOFSEN (1 << 31) -#define FLITE_REG_CIWDOFST_CLROVIY (1 << 31) -#define FLITE_REG_CIWDOFST_CLROVFICB (1 << 15) -#define FLITE_REG_CIWDOFST_CLROVFICR (1 << 14) +#define FLITE_REG_CIWDOFST_WINOFSEN BIT(31) +#define FLITE_REG_CIWDOFST_CLROVIY BIT(31) +#define FLITE_REG_CIWDOFST_CLROVFICB BIT(15) +#define FLITE_REG_CIWDOFST_CLROVFICR BIT(14) #define FLITE_REG_CIWDOFST_OFST_MASK ((0x1fff << 16) | 0x1fff) /* Camera Window Offset2 */ @@ -67,8 +69,8 @@ /* Camera Output DMA Format */ #define FLITE_REG_CIODMAFMT 0x18 -#define FLITE_REG_CIODMAFMT_RAW_CON (1 << 15) -#define FLITE_REG_CIODMAFMT_PACK12 (1 << 14) +#define FLITE_REG_CIODMAFMT_RAW_CON BIT(15) +#define FLITE_REG_CIODMAFMT_PACK12 BIT(14) #define FLITE_REG_CIODMAFMT_YCBYCR (0 << 4) #define FLITE_REG_CIODMAFMT_YCRYCB (1 << 4) #define FLITE_REG_CIODMAFMT_CBYCRY (2 << 4) @@ -88,34 +90,34 @@ /* Camera Status */ #define FLITE_REG_CISTATUS 0x40 -#define FLITE_REG_CISTATUS_MIPI_VVALID (1 << 22) -#define FLITE_REG_CISTATUS_MIPI_HVALID (1 << 21) -#define FLITE_REG_CISTATUS_MIPI_DVALID (1 << 20) -#define FLITE_REG_CISTATUS_ITU_VSYNC (1 << 14) -#define FLITE_REG_CISTATUS_ITU_HREFF (1 << 13) -#define FLITE_REG_CISTATUS_OVFIY (1 << 10) -#define FLITE_REG_CISTATUS_OVFICB (1 << 9) -#define FLITE_REG_CISTATUS_OVFICR (1 << 8) -#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW (1 << 7) -#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND (1 << 6) -#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART (1 << 5) -#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND (1 << 4) -#define FLITE_REG_CISTATUS_IRQ_CAM (1 << 0) +#define FLITE_REG_CISTATUS_MIPI_VVALID BIT(22) +#define FLITE_REG_CISTATUS_MIPI_HVALID BIT(21) +#define FLITE_REG_CISTATUS_MIPI_DVALID BIT(20) +#define FLITE_REG_CISTATUS_ITU_VSYNC BIT(14) +#define FLITE_REG_CISTATUS_ITU_HREFF BIT(13) +#define FLITE_REG_CISTATUS_OVFIY BIT(10) +#define FLITE_REG_CISTATUS_OVFICB BIT(9) +#define FLITE_REG_CISTATUS_OVFICR BIT(8) +#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW BIT(7) +#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND BIT(6) +#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART BIT(5) +#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND BIT(4) +#define FLITE_REG_CISTATUS_IRQ_CAM BIT(0) #define FLITE_REG_CISTATUS_IRQ_MASK (0xf << 4) /* Camera Status2 */ #define FLITE_REG_CISTATUS2 0x44 -#define FLITE_REG_CISTATUS2_LASTCAPEND (1 << 1) -#define FLITE_REG_CISTATUS2_FRMEND (1 << 0) +#define FLITE_REG_CISTATUS2_LASTCAPEND BIT(1) +#define FLITE_REG_CISTATUS2_FRMEND BIT(0) /* Qos Threshold */ #define FLITE_REG_CITHOLD 0xf0 -#define FLITE_REG_CITHOLD_W_QOS_EN (1 << 30) +#define FLITE_REG_CITHOLD_W_QOS_EN BIT(30) /* Camera General Purpose */ #define FLITE_REG_CIGENERAL 0xfc /* b0: 1 - camera B, 0 - camera A */ -#define FLITE_REG_CIGENERAL_CAM_B (1 << 0) +#define FLITE_REG_CIGENERAL_CAM_B BIT(0) #define FLITE_REG_CIFCNTSEQ 0x100 #define FLITE_REG_CIOSAN(x) (0x200 + (4 * (x))) diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index c1f0aee02e5e..e87c6a09205b 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -39,7 +39,6 @@ module_param(debug, int, 0644); static const struct fimc_fmt fimc_lite_formats[] = { { - .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, .colorspace = V4L2_COLORSPACE_JPEG, .depth = { 16 }, @@ -48,7 +47,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .flags = FMT_FLAGS_YUV, }, { - .name = "YUV 4:2:2 packed, CbYCrY", .fourcc = V4L2_PIX_FMT_UYVY, .colorspace = V4L2_COLORSPACE_JPEG, .depth = { 16 }, @@ -57,7 +55,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .flags = FMT_FLAGS_YUV, }, { - .name = "YUV 4:2:2 packed, CrYCbY", .fourcc = V4L2_PIX_FMT_VYUY, .colorspace = V4L2_COLORSPACE_JPEG, .depth = { 16 }, @@ -66,7 +63,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, .flags = FMT_FLAGS_YUV, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_YVYU, .colorspace = V4L2_COLORSPACE_JPEG, .depth = { 16 }, @@ -75,7 +71,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, .flags = FMT_FLAGS_YUV, }, { - .name = "RAW8 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG8, .colorspace = V4L2_COLORSPACE_SRGB, .depth = { 8 }, @@ -84,7 +79,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, .flags = FMT_FLAGS_RAW_BAYER, }, { - .name = "RAW10 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG10, .colorspace = V4L2_COLORSPACE_SRGB, .depth = { 16 }, @@ -93,7 +87,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, .flags = FMT_FLAGS_RAW_BAYER, }, { - .name = "RAW12 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG12, .colorspace = V4L2_COLORSPACE_SRGB, .depth = { 16 }, @@ -667,7 +660,6 @@ static int fimc_lite_enum_fmt(struct file *file, void *priv, return -EINVAL; fmt = &fimc_lite_formats[f->index]; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 62e876fc3555..c70c2cbe3eb1 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -247,7 +247,6 @@ static int fimc_m2m_enum_fmt(struct file *file, void *priv, if (!fmt) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; } diff --git a/drivers/media/platform/exynos4-is/fimc-reg.h b/drivers/media/platform/exynos4-is/fimc-reg.h index 03ba6c2bc84b..b81826d04936 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-reg.h @@ -8,12 +8,14 @@ #ifndef FIMC_REG_H_ #define FIMC_REG_H_ +#include <linux/bitops.h> + #include "fimc-core.h" /* Input source format */ #define FIMC_REG_CISRCFMT 0x00 -#define FIMC_REG_CISRCFMT_ITU601_8BIT (1 << 31) -#define FIMC_REG_CISRCFMT_ITU601_16BIT (1 << 29) +#define FIMC_REG_CISRCFMT_ITU601_8BIT BIT(31) +#define FIMC_REG_CISRCFMT_ITU601_16BIT BIT(29) #define FIMC_REG_CISRCFMT_ORDER422_YCBYCR (0 << 14) #define FIMC_REG_CISRCFMT_ORDER422_YCRYCB (1 << 14) #define FIMC_REG_CISRCFMT_ORDER422_CBYCRY (2 << 14) @@ -21,45 +23,45 @@ /* Window offset */ #define FIMC_REG_CIWDOFST 0x04 -#define FIMC_REG_CIWDOFST_OFF_EN (1 << 31) -#define FIMC_REG_CIWDOFST_CLROVFIY (1 << 30) -#define FIMC_REG_CIWDOFST_CLROVRLB (1 << 29) +#define FIMC_REG_CIWDOFST_OFF_EN BIT(31) +#define FIMC_REG_CIWDOFST_CLROVFIY BIT(30) +#define FIMC_REG_CIWDOFST_CLROVRLB BIT(29) #define FIMC_REG_CIWDOFST_HOROFF_MASK (0x7ff << 16) -#define FIMC_REG_CIWDOFST_CLROVFICB (1 << 15) -#define FIMC_REG_CIWDOFST_CLROVFICR (1 << 14) +#define FIMC_REG_CIWDOFST_CLROVFICB BIT(15) +#define FIMC_REG_CIWDOFST_CLROVFICR BIT(14) #define FIMC_REG_CIWDOFST_VEROFF_MASK (0xfff << 0) /* Global control */ #define FIMC_REG_CIGCTRL 0x08 -#define FIMC_REG_CIGCTRL_SWRST (1 << 31) -#define FIMC_REG_CIGCTRL_CAMRST_A (1 << 30) -#define FIMC_REG_CIGCTRL_SELCAM_ITU_A (1 << 29) +#define FIMC_REG_CIGCTRL_SWRST BIT(31) +#define FIMC_REG_CIGCTRL_CAMRST_A BIT(30) +#define FIMC_REG_CIGCTRL_SELCAM_ITU_A BIT(29) #define FIMC_REG_CIGCTRL_TESTPAT_NORMAL (0 << 27) #define FIMC_REG_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27) #define FIMC_REG_CIGCTRL_TESTPAT_HOR_INC (2 << 27) #define FIMC_REG_CIGCTRL_TESTPAT_VER_INC (3 << 27) #define FIMC_REG_CIGCTRL_TESTPAT_MASK (3 << 27) #define FIMC_REG_CIGCTRL_TESTPAT_SHIFT 27 -#define FIMC_REG_CIGCTRL_INVPOLPCLK (1 << 26) -#define FIMC_REG_CIGCTRL_INVPOLVSYNC (1 << 25) -#define FIMC_REG_CIGCTRL_INVPOLHREF (1 << 24) -#define FIMC_REG_CIGCTRL_IRQ_OVFEN (1 << 22) -#define FIMC_REG_CIGCTRL_HREF_MASK (1 << 21) -#define FIMC_REG_CIGCTRL_IRQ_LEVEL (1 << 20) -#define FIMC_REG_CIGCTRL_IRQ_CLR (1 << 19) -#define FIMC_REG_CIGCTRL_IRQ_ENABLE (1 << 16) -#define FIMC_REG_CIGCTRL_SHDW_DISABLE (1 << 12) +#define FIMC_REG_CIGCTRL_INVPOLPCLK BIT(26) +#define FIMC_REG_CIGCTRL_INVPOLVSYNC BIT(25) +#define FIMC_REG_CIGCTRL_INVPOLHREF BIT(24) +#define FIMC_REG_CIGCTRL_IRQ_OVFEN BIT(22) +#define FIMC_REG_CIGCTRL_HREF_MASK BIT(21) +#define FIMC_REG_CIGCTRL_IRQ_LEVEL BIT(20) +#define FIMC_REG_CIGCTRL_IRQ_CLR BIT(19) +#define FIMC_REG_CIGCTRL_IRQ_ENABLE BIT(16) +#define FIMC_REG_CIGCTRL_SHDW_DISABLE BIT(12) /* 0 - selects Writeback A (LCD), 1 - selects Writeback B (LCD/ISP) */ -#define FIMC_REG_CIGCTRL_SELWB_A (1 << 10) -#define FIMC_REG_CIGCTRL_CAM_JPEG (1 << 8) -#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A (1 << 7) -#define FIMC_REG_CIGCTRL_CAMIF_SELWB (1 << 6) +#define FIMC_REG_CIGCTRL_SELWB_A BIT(10) +#define FIMC_REG_CIGCTRL_CAM_JPEG BIT(8) +#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A BIT(7) +#define FIMC_REG_CIGCTRL_CAMIF_SELWB BIT(6) /* 0 - ITU601; 1 - ITU709 */ -#define FIMC_REG_CIGCTRL_CSC_ITU601_709 (1 << 5) -#define FIMC_REG_CIGCTRL_INVPOLHSYNC (1 << 4) -#define FIMC_REG_CIGCTRL_SELCAM_MIPI (1 << 3) -#define FIMC_REG_CIGCTRL_INVPOLFIELD (1 << 1) -#define FIMC_REG_CIGCTRL_INTERLACE (1 << 0) +#define FIMC_REG_CIGCTRL_CSC_ITU601_709 BIT(5) +#define FIMC_REG_CIGCTRL_INVPOLHSYNC BIT(4) +#define FIMC_REG_CIGCTRL_SELCAM_MIPI BIT(3) +#define FIMC_REG_CIGCTRL_INVPOLFIELD BIT(1) +#define FIMC_REG_CIGCTRL_INTERLACE BIT(0) /* Window offset 2 */ #define FIMC_REG_CIWDOFST2 0x14 @@ -73,7 +75,7 @@ /* Target image format */ #define FIMC_REG_CITRGFMT 0x48 -#define FIMC_REG_CITRGFMT_INROT90 (1 << 31) +#define FIMC_REG_CITRGFMT_INROT90 BIT(31) #define FIMC_REG_CITRGFMT_YCBCR420 (0 << 29) #define FIMC_REG_CITRGFMT_YCBCR422 (1 << 29) #define FIMC_REG_CITRGFMT_YCBCR422_1P (2 << 29) @@ -86,7 +88,7 @@ #define FIMC_REG_CITRGFMT_FLIP_Y_MIRROR (2 << 14) #define FIMC_REG_CITRGFMT_FLIP_180 (3 << 14) #define FIMC_REG_CITRGFMT_FLIP_MASK (3 << 14) -#define FIMC_REG_CITRGFMT_OUTROT90 (1 << 13) +#define FIMC_REG_CITRGFMT_OUTROT90 BIT(13) #define FIMC_REG_CITRGFMT_VSIZE_MASK (0xfff << 0) /* Output DMA control */ @@ -96,7 +98,7 @@ #define FIMC_REG_CIOCTRL_ORDER422_YCRYCB (1 << 0) #define FIMC_REG_CIOCTRL_ORDER422_CBYCRY (2 << 0) #define FIMC_REG_CIOCTRL_ORDER422_CRYCBY (3 << 0) -#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE (1 << 2) +#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE BIT(2) #define FIMC_REG_CIOCTRL_YCBCR_3PLANE (0 << 3) #define FIMC_REG_CIOCTRL_YCBCR_2PLANE (1 << 3) #define FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK (1 << 3) @@ -116,14 +118,14 @@ /* Main scaler control */ #define FIMC_REG_CISCCTRL 0x58 -#define FIMC_REG_CISCCTRL_SCALERBYPASS (1 << 31) -#define FIMC_REG_CISCCTRL_SCALEUP_H (1 << 30) -#define FIMC_REG_CISCCTRL_SCALEUP_V (1 << 29) -#define FIMC_REG_CISCCTRL_CSCR2Y_WIDE (1 << 28) -#define FIMC_REG_CISCCTRL_CSCY2R_WIDE (1 << 27) -#define FIMC_REG_CISCCTRL_LCDPATHEN_FIFO (1 << 26) -#define FIMC_REG_CISCCTRL_INTERLACE (1 << 25) -#define FIMC_REG_CISCCTRL_SCALERSTART (1 << 15) +#define FIMC_REG_CISCCTRL_SCALERBYPASS BIT(31) +#define FIMC_REG_CISCCTRL_SCALEUP_H BIT(30) +#define FIMC_REG_CISCCTRL_SCALEUP_V BIT(29) +#define FIMC_REG_CISCCTRL_CSCR2Y_WIDE BIT(28) +#define FIMC_REG_CISCCTRL_CSCY2R_WIDE BIT(27) +#define FIMC_REG_CISCCTRL_LCDPATHEN_FIFO BIT(26) +#define FIMC_REG_CISCCTRL_INTERLACE BIT(25) +#define FIMC_REG_CISCCTRL_SCALERSTART BIT(15) #define FIMC_REG_CISCCTRL_INRGB_FMT_RGB565 (0 << 13) #define FIMC_REG_CISCCTRL_INRGB_FMT_RGB666 (1 << 13) #define FIMC_REG_CISCCTRL_INRGB_FMT_RGB888 (2 << 13) @@ -132,8 +134,8 @@ #define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11) #define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11) #define FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK (3 << 11) -#define FIMC_REG_CISCCTRL_RGB_EXT (1 << 10) -#define FIMC_REG_CISCCTRL_ONE2ONE (1 << 9) +#define FIMC_REG_CISCCTRL_RGB_EXT BIT(10) +#define FIMC_REG_CISCCTRL_ONE2ONE BIT(9) #define FIMC_REG_CISCCTRL_MHRATIO(x) ((x) << 16) #define FIMC_REG_CISCCTRL_MVRATIO(x) ((x) << 0) #define FIMC_REG_CISCCTRL_MHRATIO_MASK (0x1ff << 16) @@ -147,39 +149,39 @@ /* General status */ #define FIMC_REG_CISTATUS 0x64 -#define FIMC_REG_CISTATUS_OVFIY (1 << 31) -#define FIMC_REG_CISTATUS_OVFICB (1 << 30) -#define FIMC_REG_CISTATUS_OVFICR (1 << 29) -#define FIMC_REG_CISTATUS_VSYNC (1 << 28) +#define FIMC_REG_CISTATUS_OVFIY BIT(31) +#define FIMC_REG_CISTATUS_OVFICB BIT(30) +#define FIMC_REG_CISTATUS_OVFICR BIT(29) +#define FIMC_REG_CISTATUS_VSYNC BIT(28) #define FIMC_REG_CISTATUS_FRAMECNT_MASK (3 << 26) #define FIMC_REG_CISTATUS_FRAMECNT_SHIFT 26 -#define FIMC_REG_CISTATUS_WINOFF_EN (1 << 25) -#define FIMC_REG_CISTATUS_IMGCPT_EN (1 << 22) -#define FIMC_REG_CISTATUS_IMGCPT_SCEN (1 << 21) -#define FIMC_REG_CISTATUS_VSYNC_A (1 << 20) -#define FIMC_REG_CISTATUS_VSYNC_B (1 << 19) -#define FIMC_REG_CISTATUS_OVRLB (1 << 18) -#define FIMC_REG_CISTATUS_FRAME_END (1 << 17) -#define FIMC_REG_CISTATUS_LASTCAPT_END (1 << 16) -#define FIMC_REG_CISTATUS_VVALID_A (1 << 15) -#define FIMC_REG_CISTATUS_VVALID_B (1 << 14) +#define FIMC_REG_CISTATUS_WINOFF_EN BIT(25) +#define FIMC_REG_CISTATUS_IMGCPT_EN BIT(22) +#define FIMC_REG_CISTATUS_IMGCPT_SCEN BIT(21) +#define FIMC_REG_CISTATUS_VSYNC_A BIT(20) +#define FIMC_REG_CISTATUS_VSYNC_B BIT(19) +#define FIMC_REG_CISTATUS_OVRLB BIT(18) +#define FIMC_REG_CISTATUS_FRAME_END BIT(17) +#define FIMC_REG_CISTATUS_LASTCAPT_END BIT(16) +#define FIMC_REG_CISTATUS_VVALID_A BIT(15) +#define FIMC_REG_CISTATUS_VVALID_B BIT(14) /* Indexes to the last and the currently processed buffer. */ #define FIMC_REG_CISTATUS2 0x68 /* Image capture control */ #define FIMC_REG_CIIMGCPT 0xc0 -#define FIMC_REG_CIIMGCPT_IMGCPTEN (1 << 31) -#define FIMC_REG_CIIMGCPT_IMGCPTEN_SC (1 << 30) -#define FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE (1 << 25) -#define FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT (1 << 18) +#define FIMC_REG_CIIMGCPT_IMGCPTEN BIT(31) +#define FIMC_REG_CIIMGCPT_IMGCPTEN_SC BIT(30) +#define FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE BIT(25) +#define FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT BIT(18) /* Frame capture sequence */ #define FIMC_REG_CICPTSEQ 0xc4 /* Image effect */ #define FIMC_REG_CIIMGEFF 0xd0 -#define FIMC_REG_CIIMGEFF_IE_ENABLE (1 << 30) +#define FIMC_REG_CIIMGEFF_IE_ENABLE BIT(30) #define FIMC_REG_CIIMGEFF_IE_SC_BEFORE (0 << 29) #define FIMC_REG_CIIMGEFF_IE_SC_AFTER (1 << 29) #define FIMC_REG_CIIMGEFF_FIN_BYPASS (0 << 26) @@ -198,8 +200,8 @@ /* Real input DMA image size */ #define FIMC_REG_CIREAL_ISIZE 0xf8 -#define FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN (1 << 31) -#define FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS (1 << 30) +#define FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN BIT(31) +#define FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS BIT(30) /* Input DMA control */ #define FIMC_REG_MSCTRL 0xfc @@ -215,7 +217,7 @@ #define FIMC_REG_MSCTRL_FLIP_X_MIRROR (1 << 13) #define FIMC_REG_MSCTRL_FLIP_Y_MIRROR (2 << 13) #define FIMC_REG_MSCTRL_FLIP_180 (3 << 13) -#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL (1 << 12) +#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL BIT(12) #define FIMC_REG_MSCTRL_ORDER422_SHIFT 4 #define FIMC_REG_MSCTRL_ORDER422_CRYCBY (0 << 4) #define FIMC_REG_MSCTRL_ORDER422_YCRYCB (1 << 4) @@ -223,14 +225,14 @@ #define FIMC_REG_MSCTRL_ORDER422_YCBYCR (3 << 4) #define FIMC_REG_MSCTRL_ORDER422_MASK (3 << 4) #define FIMC_REG_MSCTRL_INPUT_EXTCAM (0 << 3) -#define FIMC_REG_MSCTRL_INPUT_MEMORY (1 << 3) -#define FIMC_REG_MSCTRL_INPUT_MASK (1 << 3) +#define FIMC_REG_MSCTRL_INPUT_MEMORY BIT(3) +#define FIMC_REG_MSCTRL_INPUT_MASK BIT(3) #define FIMC_REG_MSCTRL_INFORMAT_YCBCR420 (0 << 1) #define FIMC_REG_MSCTRL_INFORMAT_YCBCR422 (1 << 1) #define FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P (2 << 1) #define FIMC_REG_MSCTRL_INFORMAT_RGB (3 << 1) #define FIMC_REG_MSCTRL_INFORMAT_MASK (3 << 1) -#define FIMC_REG_MSCTRL_ENVID (1 << 0) +#define FIMC_REG_MSCTRL_ENVID BIT(0) #define FIMC_REG_MSCTRL_IN_BURST_COUNT(x) ((x) << 24) /* Output DMA Y/Cb/Cr offset */ @@ -277,10 +279,10 @@ /* SYSREG ISP Writeback register address offsets */ #define SYSREG_ISPBLK 0x020c -#define SYSREG_ISPBLK_FIFORST_CAM_BLK (1 << 7) +#define SYSREG_ISPBLK_FIFORST_CAM_BLK BIT(7) #define SYSREG_CAMBLK 0x0218 -#define SYSREG_CAMBLK_FIFORST_ISP (1 << 15) +#define SYSREG_CAMBLK_FIFORST_ISP BIT(15) #define SYSREG_CAMBLK_ISPWB_FULL_EN (7 << 20) /* diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index d53427a8db11..a838189d4490 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -501,6 +501,7 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) continue; ret = fimc_md_parse_port_node(fmd, port, index); + of_node_put(port); if (ret < 0) { of_node_put(node); goto cleanup; @@ -542,6 +543,7 @@ static int __of_get_csis_id(struct device_node *np) if (!np) return -EINVAL; of_property_read_u32(np, "reg", ®); + of_node_put(np); return reg - FIMC_INPUT_MIPI_CSI2_0; } diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 3e9ac6066cf6..540151bbf58f 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -41,7 +41,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); /* CSIS global control */ #define S5PCSIS_CTRL 0x00 #define S5PCSIS_CTRL_DPDN_DEFAULT (0 << 31) -#define S5PCSIS_CTRL_DPDN_SWAP (1 << 31) +#define S5PCSIS_CTRL_DPDN_SWAP (1UL << 31) #define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20) #define S5PCSIS_CTRL_UPDATE_SHADOW (1 << 16) #define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8) @@ -65,7 +65,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); /* Interrupt mask */ #define S5PCSIS_INTMSK 0x10 -#define S5PCSIS_INTMSK_EVEN_BEFORE (1 << 31) +#define S5PCSIS_INTMSK_EVEN_BEFORE (1UL << 31) #define S5PCSIS_INTMSK_EVEN_AFTER (1 << 30) #define S5PCSIS_INTMSK_ODD_BEFORE (1 << 29) #define S5PCSIS_INTMSK_ODD_AFTER (1 << 28) @@ -83,7 +83,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); /* Interrupt source */ #define S5PCSIS_INTSRC 0x14 -#define S5PCSIS_INTSRC_EVEN_BEFORE (1 << 31) +#define S5PCSIS_INTSRC_EVEN_BEFORE (1UL << 31) #define S5PCSIS_INTSRC_EVEN_AFTER (1 << 30) #define S5PCSIS_INTSRC_EVEN (0x3 << 30) #define S5PCSIS_INTSRC_ODD_BEFORE (1 << 29) @@ -803,10 +803,8 @@ static int s5pcsis_probe(struct platform_device *pdev) return PTR_ERR(state->regs); state->irq = platform_get_irq(pdev, 0); - if (state->irq < 0) { - dev_err(dev, "Failed to get irq\n"); + if (state->irq < 0) return state->irq; - } for (i = 0; i < CSIS_NUM_SUPPLIES; i++) state->supplies[i].supply = csis_supply_name[i]; diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 691be788e38b..81a8faedbba6 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -32,7 +32,7 @@ #define VIU_VERSION "0.5.1" /* Allow building this driver with COMPILE_TEST */ -#ifndef CONFIG_PPC +#if !defined(CONFIG_PPC) && !defined(CONFIG_MICROBLAZE) #define out_be32(v, a) iowrite32be(a, (void __iomem *)v) #define in_be32(a) ioread32be((void __iomem *)a) #endif @@ -214,7 +214,7 @@ enum status_config { FIELD_NO = 0x01 << 28, /* Field number */ DITHER_ON = 0x01 << 29, /* Dithering is on */ ROUND_ON = 0x01 << 30, /* Round is on */ - MODE_32BIT = 0x01 << 31, /* Data in RGBa888, + MODE_32BIT = 1UL << 31, /* Data in RGBa888, * 0 in RGB565 */ }; @@ -563,11 +563,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "viu", sizeof(cap->driver)); strscpy(cap->card, "viu", sizeof(cap->card)); strscpy(cap->bus_info, "platform:viu", sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_OVERLAY | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1380,6 +1375,8 @@ static const struct video_device viu_template = { .release = video_device_release, .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE, }; static int viu_of_probe(struct platform_device *op) diff --git a/drivers/media/platform/imx-pxp.c b/drivers/media/platform/imx-pxp.c index 8e7ef23b9a7e..38d942322302 100644 --- a/drivers/media/platform/imx-pxp.c +++ b/drivers/media/platform/imx-pxp.c @@ -1661,10 +1661,8 @@ static int pxp_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get irq resource: %d\n", irq); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, pxp_irq_handler, IRQF_ONESHOT, dev_name(&pdev->dev), dev); diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index beb7fd7442fb..9ad24c86c5ab 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -37,7 +37,6 @@ module_param(debug, bool, 0644); v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) struct deinterlace_fmt { - char *name; u32 fourcc; /* Types the format can be used for */ u32 types; @@ -45,12 +44,10 @@ struct deinterlace_fmt { static struct deinterlace_fmt formats[] = { { - .name = "YUV 4:2:0 Planar", .fourcc = V4L2_PIX_FMT_YUV420, .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, }, { - .name = "YUYV 4:2:2", .fourcc = V4L2_PIX_FMT_YUYV, .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, }, @@ -135,13 +132,13 @@ struct deinterlace_dev { }; struct deinterlace_ctx { + struct v4l2_fh fh; struct deinterlace_dev *dev; /* Abort requested by m2m */ int aborting; enum v4l2_colorspace colorspace; dma_cookie_t cookie; - struct v4l2_m2m_ctx *m2m_ctx; struct dma_interleaved_template *xt; }; @@ -153,9 +150,9 @@ static int deinterlace_job_ready(void *priv) struct deinterlace_ctx *ctx = priv; struct deinterlace_dev *pcdev = ctx->dev; - if ((v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0) - && (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0) - && (atomic_read(&ctx->dev->busy) == 0)) { + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0 && + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0 && + !atomic_read(&ctx->dev->busy)) { dprintk(pcdev, "Task ready\n"); return 1; } @@ -174,7 +171,7 @@ static void deinterlace_job_abort(void *priv) dprintk(pcdev, "Aborting task\n"); - v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx); + v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->fh.m2m_ctx); } static void dma_callback(void *data) @@ -185,8 +182,8 @@ static void dma_callback(void *data) atomic_set(&pcdev->busy, 0); - src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); - dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; @@ -197,7 +194,7 @@ static void dma_callback(void *data) v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); - v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx); + v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->fh.m2m_ctx); dprintk(pcdev, "dma transfers completed.\n"); } @@ -216,8 +213,8 @@ static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op, dma_addr_t p_in, p_out; enum dma_ctrl_flags flags; - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT); s_width = s_q_data->width; @@ -436,16 +433,7 @@ static int vidioc_querycap(struct file *file, void *priv, { strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); - strscpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->card)); - /* - * This is only a mem-to-mem video device. The capture and output - * device capability flags are left only for backward compatibility - * and are scheduled for removal. - */ - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | - V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - + strscpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->bus_info)); return 0; } @@ -470,7 +458,6 @@ static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) if (i < NUM_FORMATS) { /* Format found */ fmt = &formats[i]; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; } @@ -496,7 +483,7 @@ static int vidioc_g_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f) struct vb2_queue *vq; struct deinterlace_q_data *q_data; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; @@ -593,7 +580,7 @@ static int vidioc_s_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f) struct deinterlace_q_data *q_data; struct vb2_queue *vq; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; @@ -666,36 +653,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, return ret; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct deinterlace_ctx *ctx = priv; - - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct deinterlace_ctx *ctx = priv; - - return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct deinterlace_ctx *ctx = priv; - - return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct deinterlace_ctx *ctx = priv; - - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); -} - static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { @@ -736,15 +693,7 @@ static int vidioc_streamon(struct file *file, void *priv, return -EINVAL; } - return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct deinterlace_ctx *ctx = priv; - - return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); + return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type); } static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = { @@ -760,14 +709,15 @@ static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = { .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, }; @@ -831,7 +781,7 @@ static void deinterlace_buf_queue(struct vb2_buffer *vb) struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } static const struct vb2_ops deinterlace_qops = { @@ -849,7 +799,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_MMAP | VB2_USERPTR; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &deinterlace_qops; @@ -868,7 +818,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &deinterlace_qops; @@ -897,12 +847,13 @@ static int deinterlace_open(struct file *file) if (!ctx) return -ENOMEM; - file->private_data = ctx; + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; ctx->dev = pcdev; - ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); - if (IS_ERR(ctx->m2m_ctx)) { - int ret = PTR_ERR(ctx->m2m_ctx); + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + int ret = PTR_ERR(ctx->fh.m2m_ctx); kfree(ctx); return ret; @@ -916,8 +867,10 @@ static int deinterlace_open(struct file *file) } ctx->colorspace = V4L2_COLORSPACE_REC709; + v4l2_fh_add(&ctx->fh); - dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); + dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", + ctx, ctx->fh.m2m_ctx); return 0; } @@ -929,40 +882,22 @@ static int deinterlace_release(struct file *file) dprintk(pcdev, "Releasing instance %p\n", ctx); - v4l2_m2m_ctx_release(ctx->m2m_ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); kfree(ctx->xt); kfree(ctx); return 0; } -static __poll_t deinterlace_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct deinterlace_ctx *ctx = file->private_data; - __poll_t ret; - - mutex_lock(&ctx->dev->dev_mutex); - ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); - mutex_unlock(&ctx->dev->dev_mutex); - - return ret; -} - -static int deinterlace_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct deinterlace_ctx *ctx = file->private_data; - - return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); -} - static const struct v4l2_file_operations deinterlace_fops = { .owner = THIS_MODULE, .open = deinterlace_open, .release = deinterlace_release, - .poll = deinterlace_poll, + .poll = v4l2_m2m_fop_poll, .unlocked_ioctl = video_ioctl2, - .mmap = deinterlace_mmap, + .mmap = v4l2_m2m_fop_mmap, }; static const struct video_device deinterlace_videodev = { @@ -972,6 +907,7 @@ static const struct video_device deinterlace_videodev = { .minor = -1, .release = video_device_release_empty, .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, }; static const struct v4l2_m2m_ops m2m_ops = { diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index dc30c48d4671..803baf97f06e 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -98,56 +98,48 @@ MODULE_PARM_DESC(buffer_mode, container_of(notifier, struct mcam_camera, notifier) static struct mcam_format_struct { - __u8 *desc; __u32 pixelformat; int bpp; /* Bytes per pixel */ bool planar; u32 mbus_code; } mcam_formats[] = { { - .desc = "YUYV 4:2:2", .pixelformat = V4L2_PIX_FMT_YUYV, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, .planar = false, }, { - .desc = "YVYU 4:2:2", .pixelformat = V4L2_PIX_FMT_YVYU, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, .planar = false, }, { - .desc = "YUV 4:2:0 PLANAR", .pixelformat = V4L2_PIX_FMT_YUV420, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 1, .planar = true, }, { - .desc = "YVU 4:2:0 PLANAR", .pixelformat = V4L2_PIX_FMT_YVU420, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 1, .planar = true, }, { - .desc = "XRGB 444", .pixelformat = V4L2_PIX_FMT_XRGB444, .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, .bpp = 2, .planar = false, }, { - .desc = "RGB 565", .pixelformat = V4L2_PIX_FMT_RGB565, .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, .bpp = 2, .planar = false, }, { - .desc = "Raw RGB Bayer", .pixelformat = V4L2_PIX_FMT_SBGGR8, .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 1, @@ -1357,9 +1349,6 @@ static int mcam_vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "marvell_ccic", sizeof(cap->driver)); strscpy(cap->card, "marvell_ccic", sizeof(cap->card)); strscpy(cap->bus_info, cam->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1369,8 +1358,6 @@ static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp, { if (fmt->index >= N_MCAM_FMTS) return -EINVAL; - strscpy(fmt->description, mcam_formats[fmt->index].desc, - sizeof(fmt->description)); fmt->pixelformat = mcam_formats[fmt->index].pixelformat; return 0; } @@ -1698,6 +1685,8 @@ static const struct video_device mcam_v4l_template = { .fops = &mcam_v4l_fops, .ioctl_ops = &mcam_v4l_ioctl_ops, .release = video_device_release_empty, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 10559492e09e..92b92255dac6 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -372,6 +372,7 @@ static const struct of_device_id mmpcam_of_match[] = { { .compatible = "marvell,mmp2-ccic", }, {}, }; +MODULE_DEVICE_TABLE(of, mmpcam_of_match); static struct platform_driver mmpcam_driver = { .probe = mmpcam_probe, diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c index fb52e5dd044a..3b39e875292e 100644 --- a/drivers/media/platform/meson/ao-cec-g12a.c +++ b/drivers/media/platform/meson/ao-cec-g12a.c @@ -121,6 +121,9 @@ #define CECB_CTRL_TYPE_NEXT 2 #define CECB_CTRL2 0x01 + +#define CECB_CTRL2_RISE_DEL_MAX GENMASK(4, 0) + #define CECB_INTR_MASK 0x02 #define CECB_LADD_LOW 0x05 #define CECB_LADD_HIGH 0x06 @@ -165,6 +168,11 @@ #define CECB_WAKEUPCTRL 0x31 +struct meson_ao_cec_g12a_data { + /* Setup the internal CECB_CTRL2 register */ + bool ctrl2_setup; +}; + struct meson_ao_cec_g12a_device { struct platform_device *pdev; struct regmap *regmap; @@ -175,6 +183,7 @@ struct meson_ao_cec_g12a_device { struct cec_msg rx_msg; struct clk *oscin; struct clk *core; + const struct meson_ao_cec_g12a_data *data; }; static const struct regmap_config meson_ao_cec_g12a_regmap_conf = { @@ -605,6 +614,10 @@ static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable) regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET, 0); + if (ao_cec->data->ctrl2_setup) + regmap_write(ao_cec->regmap_cec, CECB_CTRL2, + FIELD_PREP(CECB_CTRL2_RISE_DEL_MAX, 2)); + meson_ao_cec_g12a_irq_setup(ao_cec, true); return 0; @@ -632,20 +645,28 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) if (!ao_cec) return -ENOMEM; + ao_cec->data = of_device_get_match_data(&pdev->dev); + if (!ao_cec->data) { + dev_err(&pdev->dev, "failed to get match data\n"); + return -ENODEV; + } + spin_lock_init(&ao_cec->cec_reg_lock); ao_cec->pdev = pdev; - ao_cec->notify = cec_notifier_get(hdmi_dev); - if (!ao_cec->notify) - return -ENOMEM; - ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec, "meson_g12a_ao_cec", - CEC_CAP_DEFAULTS, + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, CEC_MAX_LOG_ADDRS); - if (IS_ERR(ao_cec->adap)) { - ret = PTR_ERR(ao_cec->adap); - goto out_probe_notify; + if (IS_ERR(ao_cec->adap)) + return PTR_ERR(ao_cec->adap); + + ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL, + ao_cec->adap); + if (!ao_cec->notify) { + ret = -ENOMEM; + goto out_probe_adapter; } ao_cec->adap->owner = THIS_MODULE; @@ -654,21 +675,21 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) { ret = PTR_ERR(base); - goto out_probe_adapter; + goto out_probe_notify; } ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base, &meson_ao_cec_g12a_regmap_conf); if (IS_ERR(ao_cec->regmap)) { ret = PTR_ERR(ao_cec->regmap); - goto out_probe_adapter; + goto out_probe_notify; } ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec, &meson_ao_cec_g12a_cec_regmap_conf); if (IS_ERR(ao_cec->regmap_cec)) { ret = PTR_ERR(ao_cec->regmap_cec); - goto out_probe_adapter; + goto out_probe_notify; } irq = platform_get_irq(pdev, 0); @@ -678,24 +699,24 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) 0, NULL, ao_cec); if (ret) { dev_err(&pdev->dev, "irq request failed\n"); - goto out_probe_adapter; + goto out_probe_notify; } ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin"); if (IS_ERR(ao_cec->oscin)) { dev_err(&pdev->dev, "oscin clock request failed\n"); ret = PTR_ERR(ao_cec->oscin); - goto out_probe_adapter; + goto out_probe_notify; } ret = meson_ao_cec_g12a_setup_clk(ao_cec); if (ret) - goto out_probe_adapter; + goto out_probe_notify; ret = clk_prepare_enable(ao_cec->core); if (ret) { dev_err(&pdev->dev, "core clock enable failed\n"); - goto out_probe_adapter; + goto out_probe_notify; } device_reset_optional(&pdev->dev); @@ -703,27 +724,23 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ao_cec); ret = cec_register_adapter(ao_cec->adap, &pdev->dev); - if (ret < 0) { - cec_notifier_put(ao_cec->notify); + if (ret < 0) goto out_probe_core_clk; - } /* Setup Hardware */ regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET); - cec_register_cec_notifier(ao_cec->adap, ao_cec->notify); - return 0; out_probe_core_clk: clk_disable_unprepare(ao_cec->core); +out_probe_notify: + cec_notifier_cec_adap_unregister(ao_cec->notify); + out_probe_adapter: cec_delete_adapter(ao_cec->adap); -out_probe_notify: - cec_notifier_put(ao_cec->notify); - dev_err(&pdev->dev, "CEC controller registration failed\n"); return ret; @@ -735,15 +752,30 @@ static int meson_ao_cec_g12a_remove(struct platform_device *pdev) clk_disable_unprepare(ao_cec->core); - cec_unregister_adapter(ao_cec->adap); + cec_notifier_cec_adap_unregister(ao_cec->notify); - cec_notifier_put(ao_cec->notify); + cec_unregister_adapter(ao_cec->adap); return 0; } +static const struct meson_ao_cec_g12a_data ao_cec_g12a_data = { + .ctrl2_setup = false, +}; + +static const struct meson_ao_cec_g12a_data ao_cec_sm1_data = { + .ctrl2_setup = true, +}; + static const struct of_device_id meson_ao_cec_g12a_of_match[] = { - { .compatible = "amlogic,meson-g12a-ao-cec", }, + { + .compatible = "amlogic,meson-g12a-ao-cec", + .data = &ao_cec_g12a_data, + }, + { + .compatible = "amlogic,meson-sm1-ao-cec", + .data = &ao_cec_sm1_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c index facf9b029e79..64ed549bf012 100644 --- a/drivers/media/platform/meson/ao-cec.c +++ b/drivers/media/platform/meson/ao-cec.c @@ -616,20 +616,19 @@ static int meson_ao_cec_probe(struct platform_device *pdev) spin_lock_init(&ao_cec->cec_reg_lock); - ao_cec->notify = cec_notifier_get(hdmi_dev); - if (!ao_cec->notify) - return -ENOMEM; - ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_ops, ao_cec, "meson_ao_cec", - CEC_CAP_LOG_ADDRS | - CEC_CAP_TRANSMIT | - CEC_CAP_RC | - CEC_CAP_PASSTHROUGH, + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, 1); /* Use 1 for now */ - if (IS_ERR(ao_cec->adap)) { - ret = PTR_ERR(ao_cec->adap); - goto out_probe_notify; + if (IS_ERR(ao_cec->adap)) + return PTR_ERR(ao_cec->adap); + + ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL, + ao_cec->adap); + if (!ao_cec->notify) { + ret = -ENOMEM; + goto out_probe_adapter; } ao_cec->adap->owner = THIS_MODULE; @@ -638,7 +637,7 @@ static int meson_ao_cec_probe(struct platform_device *pdev) ao_cec->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(ao_cec->base)) { ret = PTR_ERR(ao_cec->base); - goto out_probe_adapter; + goto out_probe_notify; } irq = platform_get_irq(pdev, 0); @@ -648,20 +647,20 @@ static int meson_ao_cec_probe(struct platform_device *pdev) 0, NULL, ao_cec); if (ret) { dev_err(&pdev->dev, "irq request failed\n"); - goto out_probe_adapter; + goto out_probe_notify; } ao_cec->core = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(ao_cec->core)) { dev_err(&pdev->dev, "core clock request failed\n"); ret = PTR_ERR(ao_cec->core); - goto out_probe_adapter; + goto out_probe_notify; } ret = clk_prepare_enable(ao_cec->core); if (ret) { dev_err(&pdev->dev, "core clock enable failed\n"); - goto out_probe_adapter; + goto out_probe_notify; } ret = clk_set_rate(ao_cec->core, CEC_CLK_RATE); @@ -676,28 +675,24 @@ static int meson_ao_cec_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ao_cec); ret = cec_register_adapter(ao_cec->adap, &pdev->dev); - if (ret < 0) { - cec_notifier_put(ao_cec->notify); + if (ret < 0) goto out_probe_clk; - } /* Setup Hardware */ writel_relaxed(CEC_GEN_CNTL_RESET, ao_cec->base + CEC_GEN_CNTL_REG); - cec_register_cec_notifier(ao_cec->adap, ao_cec->notify); - return 0; out_probe_clk: clk_disable_unprepare(ao_cec->core); +out_probe_notify: + cec_notifier_cec_adap_unregister(ao_cec->notify); + out_probe_adapter: cec_delete_adapter(ao_cec->adap); -out_probe_notify: - cec_notifier_put(ao_cec->notify); - dev_err(&pdev->dev, "CEC controller registration failed\n"); return ret; @@ -709,10 +704,9 @@ static int meson_ao_cec_remove(struct platform_device *pdev) clk_disable_unprepare(ao_cec->core); + cec_notifier_cec_adap_unregister(ao_cec->notify); cec_unregister_adapter(ao_cec->adap); - cec_notifier_put(ao_cec->notify); - return 0; } diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c index fc9faec85edb..c1e29a46ae69 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c @@ -110,7 +110,9 @@ static int mtk_mdp_probe(struct platform_device *pdev) mutex_init(&mdp->vpulock); /* Old dts had the components as child nodes */ - if (of_get_next_child(dev->of_node, NULL)) { + node = of_get_next_child(dev->of_node, NULL); + if (node) { + of_node_put(node); parent = dev->of_node; dev_warn(dev, "device tree is out of date\n"); } else { @@ -145,13 +147,16 @@ static int mtk_mdp_probe(struct platform_device *pdev) comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); if (!comp) { ret = -ENOMEM; + of_node_put(node); goto err_comp; } mdp->comp[comp_id] = comp; ret = mtk_mdp_comp_init(dev, node, comp, comp_id); - if (ret) + if (ret) { + of_node_put(node); goto err_comp; + } } mdp->job_wq = create_singlethread_workqueue(MTK_MDP_MODULE_NAME); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 90d1a67db7e5..26a55c3e807e 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -29,16 +29,19 @@ static const struct mtk_video_fmt mtk_video_formats[] = { .fourcc = V4L2_PIX_FMT_H264, .type = MTK_FMT_DEC, .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .fourcc = V4L2_PIX_FMT_VP8, .type = MTK_FMT_DEC, .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .fourcc = V4L2_PIX_FMT_VP9, .type = MTK_FMT_DEC, .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .fourcc = V4L2_PIX_FMT_MT21C, @@ -948,6 +951,7 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) fmt = &mtk_video_formats[i]; f->pixelformat = fmt->fourcc; + f->flags = fmt->flags; return 0; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index c95de5d08dda..9fd56dee7fd1 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -99,6 +99,7 @@ struct mtk_video_fmt { u32 fourcc; enum mtk_fmt_type type; u32 num_planes; + u32 flags; }; /** diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c index c5f8f1fca44c..49aa85a9bb5a 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -29,6 +29,9 @@ #define H264_MAX_FB_NUM 17 #define HDR_PARSING_BUF_SZ 1024 +#define DEC_ERR_RET(ret) ((ret) >> 16) +#define H264_ERR_NOT_VALID 3 + /** * struct h264_fb - h264 decode frame buffer information * @vdec_fb_va : virtual address of struct vdec_fb @@ -357,8 +360,11 @@ static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs, buf = (unsigned char *)bs->va; buf_sz = bs->size; nal_start_idx = find_start_code(buf, buf_sz); - if (nal_start_idx < 0) + if (nal_start_idx < 0) { + mtk_vcodec_err(inst, "invalid nal start code"); + err = -EIO; goto err_free_fb_out; + } nal_start = buf[nal_start_idx]; nal_type = NAL_TYPE(buf[nal_start_idx]); @@ -382,8 +388,14 @@ static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs, data[0] = buf_sz; data[1] = nal_start; err = vpu_dec_start(vpu, data, 2); - if (err) + if (err) { + if (err > 0 && (DEC_ERR_RET(err) == H264_ERR_NOT_VALID)) { + mtk_vcodec_err(inst, "- error bitstream - err = %d -", + err); + err = -EIO; + } goto err_free_fb_out; + } *res_chg = inst->vsi->dec.resolution_changed; if (*res_chg) { diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index 333324c75027..27779b75df54 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -120,7 +120,7 @@ module_param(debug, bool, 0644); #define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) #define PRP_CNTL_CH2B1EN (1 << 29) #define PRP_CNTL_CH2B2EN (1 << 30) -#define PRP_CNTL_CH2FEN (1 << 31) +#define PRP_CNTL_CH2FEN (1UL << 31) #define PRP_SIZE_HEIGHT(x) (x) #define PRP_SIZE_WIDTH(x) ((x) << 16) @@ -145,7 +145,6 @@ module_param(debug, bool, 0644); #define PRP_INTR_ST_CH2OVF (1 << 8) struct emmaprp_fmt { - char *name; u32 fourcc; /* Types the format can be used for */ u32 types; @@ -153,12 +152,10 @@ struct emmaprp_fmt { static struct emmaprp_fmt formats[] = { { - .name = "YUV 4:2:0 Planar", .fourcc = V4L2_PIX_FMT_YUV420, .types = MEM2MEM_CAPTURE, }, { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .types = MEM2MEM_OUTPUT, }, @@ -210,11 +207,11 @@ struct emmaprp_dev { }; struct emmaprp_ctx { + struct v4l2_fh fh; struct emmaprp_dev *dev; /* Abort requested by m2m */ int aborting; struct emmaprp_q_data q_data[2]; - struct v4l2_m2m_ctx *m2m_ctx; }; static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx, @@ -243,7 +240,7 @@ static void emmaprp_job_abort(void *priv) dprintk(pcdev, "Aborting task\n"); - v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx); + v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->fh.m2m_ctx); } static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev) @@ -278,8 +275,8 @@ static void emmaprp_device_run(void *priv) dma_addr_t p_in, p_out; u32 tmp; - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); s_width = s_q_data->width; @@ -353,8 +350,8 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data) pr_err("PrP bus error occurred, this transfer is probably corrupted\n"); writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); } else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */ - src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); - dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; dst_vb->flags &= @@ -371,7 +368,7 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data) } } - v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx); + v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->fh.m2m_ctx); return IRQ_HANDLED; } @@ -383,8 +380,6 @@ static int vidioc_querycap(struct file *file, void *priv, { strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); - cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -409,7 +404,6 @@ static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) if (i < NUM_FORMATS) { /* Format found */ fmt = &formats[i]; - strscpy(f->description, fmt->name, sizeof(f->description) - 1); f->pixelformat = fmt->fourcc; return 0; } @@ -435,7 +429,7 @@ static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) struct vb2_queue *vq; struct emmaprp_q_data *q_data; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; @@ -540,7 +534,7 @@ static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) struct vb2_queue *vq; int ret; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; @@ -596,52 +590,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, return vidioc_s_fmt(priv, f); } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); -} - static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { .vidioc_querycap = vidioc_querycap, @@ -655,14 +603,14 @@ static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, }; @@ -722,7 +670,7 @@ static void emmaprp_buf_queue(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } static const struct vb2_ops emmaprp_qops = { @@ -740,7 +688,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_MMAP | VB2_USERPTR; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &emmaprp_qops; @@ -754,7 +702,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &emmaprp_qops; @@ -778,7 +726,8 @@ static int emmaprp_open(struct file *file) if (!ctx) return -ENOMEM; - file->private_data = ctx; + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; ctx->dev = pcdev; if (mutex_lock_interruptible(&pcdev->dev_mutex)) { @@ -786,10 +735,10 @@ static int emmaprp_open(struct file *file) return -ERESTARTSYS; } - ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); - if (IS_ERR(ctx->m2m_ctx)) { - int ret = PTR_ERR(ctx->m2m_ctx); + if (IS_ERR(ctx->fh.m2m_ctx)) { + int ret = PTR_ERR(ctx->fh.m2m_ctx); mutex_unlock(&pcdev->dev_mutex); kfree(ctx); @@ -800,9 +749,10 @@ static int emmaprp_open(struct file *file) clk_prepare_enable(pcdev->clk_emma_ahb); ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1]; ctx->q_data[V4L2_M2M_DST].fmt = &formats[0]; + v4l2_fh_add(&ctx->fh); mutex_unlock(&pcdev->dev_mutex); - dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); + dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); return 0; } @@ -817,46 +767,22 @@ static int emmaprp_release(struct file *file) mutex_lock(&pcdev->dev_mutex); clk_disable_unprepare(pcdev->clk_emma_ahb); clk_disable_unprepare(pcdev->clk_emma_ipg); - v4l2_m2m_ctx_release(ctx->m2m_ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(&pcdev->dev_mutex); kfree(ctx); return 0; } -static __poll_t emmaprp_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct emmaprp_dev *pcdev = video_drvdata(file); - struct emmaprp_ctx *ctx = file->private_data; - __poll_t res; - - mutex_lock(&pcdev->dev_mutex); - res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); - mutex_unlock(&pcdev->dev_mutex); - return res; -} - -static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct emmaprp_dev *pcdev = video_drvdata(file); - struct emmaprp_ctx *ctx = file->private_data; - int ret; - - if (mutex_lock_interruptible(&pcdev->dev_mutex)) - return -ERESTARTSYS; - ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); - mutex_unlock(&pcdev->dev_mutex); - return ret; -} - static const struct v4l2_file_operations emmaprp_fops = { .owner = THIS_MODULE, .open = emmaprp_open, .release = emmaprp_release, - .poll = emmaprp_poll, + .poll = v4l2_m2m_fop_poll, .unlocked_ioctl = video_ioctl2, - .mmap = emmaprp_mmap, + .mmap = v4l2_m2m_fop_mmap, }; static const struct video_device emmaprp_videodev = { @@ -866,6 +792,7 @@ static const struct video_device emmaprp_videodev = { .minor = -1, .release = video_device_release, .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, }; static const struct v4l2_m2m_ops m2m_ops = { diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig index 1a99dff21ca0..f73b5893220d 100644 --- a/drivers/media/platform/omap/Kconfig +++ b/drivers/media/platform/omap/Kconfig @@ -10,8 +10,7 @@ config VIDEO_OMAP2_VOUT depends on FB_OMAP2 || (COMPILE_TEST && FB_OMAP2=n) depends on ARCH_OMAP2 || ARCH_OMAP3 || COMPILE_TEST depends on VIDEO_V4L2 - select VIDEOBUF_GEN - select VIDEOBUF_DMA_CONTIG + select VIDEOBUF2_DMA_CONTIG select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 select FRAME_VECTOR help diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index cb6a9e3946b6..513b99bf963b 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -40,9 +40,9 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> -#include <media/videobuf-dma-contig.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> #include <video/omapvrfb.h> #include <video/omapfb_dss.h> @@ -63,33 +63,12 @@ enum omap_vout_channels { OMAP_VIDEO2, }; -static struct videobuf_queue_ops video_vbq_ops; /* Variables configurable through module params*/ -static u32 video1_numbuffers = 3; -static u32 video2_numbuffers = 3; -static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE; -static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE; static bool vid1_static_vrfb_alloc; static bool vid2_static_vrfb_alloc; static bool debug; /* Module parameters */ -module_param(video1_numbuffers, uint, S_IRUGO); -MODULE_PARM_DESC(video1_numbuffers, - "Number of buffers to be allocated at init time for Video1 device."); - -module_param(video2_numbuffers, uint, S_IRUGO); -MODULE_PARM_DESC(video2_numbuffers, - "Number of buffers to be allocated at init time for Video2 device."); - -module_param(video1_bufsize, uint, S_IRUGO); -MODULE_PARM_DESC(video1_bufsize, - "Size of the buffer to be allocated for video1 device"); - -module_param(video2_bufsize, uint, S_IRUGO); -MODULE_PARM_DESC(video2_bufsize, - "Size of the buffer to be allocated for video2 device"); - module_param(vid1_static_vrfb_alloc, bool, S_IRUGO); MODULE_PARM_DESC(vid1_static_vrfb_alloc, "Static allocation of the VRFB buffer for video1 device"); @@ -114,14 +93,12 @@ static const struct v4l2_fmtdesc omap_formats[] = { * Byte 0 Byte 1 * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 */ - .description = "RGB565, le", .pixelformat = V4L2_PIX_FMT_RGB565, }, { /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use * this for RGB24 unpack mode, the last 8 bits are ignored * */ - .description = "RGB32, le", .pixelformat = V4L2_PIX_FMT_RGB32, }, { @@ -129,15 +106,12 @@ static const struct v4l2_fmtdesc omap_formats[] = { * this for RGB24 packed mode * */ - .description = "RGB24, le", .pixelformat = V4L2_PIX_FMT_RGB24, }, { - .description = "YUYV (YUV 4:2:2), packed", .pixelformat = V4L2_PIX_FMT_YUYV, }, { - .description = "UYVY, packed", .pixelformat = V4L2_PIX_FMT_UYVY, }, }; @@ -164,13 +138,13 @@ static int omap_vout_try_format(struct v4l2_pix_format *pix) ifmt = 0; pix->pixelformat = omap_formats[ifmt].pixelformat; - pix->field = V4L2_FIELD_ANY; + pix->field = V4L2_FIELD_NONE; switch (pix->pixelformat) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: default: - pix->colorspace = V4L2_COLORSPACE_JPEG; + pix->colorspace = V4L2_COLORSPACE_SRGB; bpp = YUYV_BPP; break; case V4L2_PIX_FMT_RGB565: @@ -195,56 +169,6 @@ static int omap_vout_try_format(struct v4l2_pix_format *pix) } /* - * omap_vout_get_userptr: Convert user space virtual address to physical - * address. - */ -static int omap_vout_get_userptr(struct videobuf_buffer *vb, long virtp, - u32 *physp) -{ - struct frame_vector *vec; - int ret; - - /* For kernel direct-mapped memory, take the easy way */ - if (virtp >= PAGE_OFFSET) { - *physp = virt_to_phys((void *)virtp); - return 0; - } - - vec = frame_vector_create(1); - if (!vec) - return -ENOMEM; - - ret = get_vaddr_frames(virtp, 1, FOLL_WRITE, vec); - if (ret != 1) { - frame_vector_destroy(vec); - return -EINVAL; - } - *physp = __pfn_to_phys(frame_vector_pfns(vec)[0]); - vb->priv = vec; - - return 0; -} - -/* - * Free the V4L2 buffers - */ -void omap_vout_free_buffers(struct omap_vout_device *vout) -{ - int i, numbuffers; - - /* Allocate memory for the buffers */ - numbuffers = (vout->vid) ? video2_numbuffers : video1_numbuffers; - vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize; - - for (i = 0; i < numbuffers; i++) { - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - vout->buf_phy_addr[i] = 0; - vout->buf_virt_addr[i] = 0; - } -} - -/* * Convert V4L2 rotation to DSS rotation * V4L2 understand 0, 90, 180, 270. * Convert to 0, 1, 2 and 3 respectively for DSS @@ -537,9 +461,9 @@ static int omapvid_handle_interlace_display(struct omap_vout_device *vout, if (vout->cur_frm == vout->next_frm) goto err; - vout->cur_frm->ts = ts; - vout->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&vout->cur_frm->done); + vout->cur_frm->vbuf.vb2_buf.timestamp = ts; + vout->cur_frm->vbuf.sequence = vout->sequence++; + vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_DONE); vout->cur_frm = vout->next_frm; } else { if (list_empty(&vout->dma_queue) || @@ -562,9 +486,6 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) struct omap_dss_device *cur_display; struct omap_vout_device *vout = (struct omap_vout_device *)arg; - if (!vout->streaming) - return; - ovid = &vout->vid_info; ovl = ovid->overlays[0]; @@ -608,9 +529,9 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) } if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { - vout->cur_frm->ts = ts; - vout->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&vout->cur_frm->done); + vout->cur_frm->vbuf.vb2_buf.timestamp = ts; + vout->cur_frm->vbuf.sequence = vout->sequence++; + vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_DONE); vout->cur_frm = vout->next_frm; } @@ -619,12 +540,10 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) goto vout_isr_err; vout->next_frm = list_entry(vout->dma_queue.next, - struct videobuf_buffer, queue); + struct omap_vout_buffer, queue); list_del(&vout->next_frm->queue); - vout->next_frm->state = VIDEOBUF_ACTIVE; - - addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i] + addr = (unsigned long)vout->queued_buf_addr[vout->next_frm->vbuf.vb2_buf.index] + vout->cropped_offset; /* First save the configuration in ovelray structure */ @@ -644,394 +563,6 @@ vout_isr_err: spin_unlock(&vout->vbq_lock); } -/* Video buffer call backs */ - -/* - * Buffer setup function is called by videobuf layer when REQBUF ioctl is - * called. This is used to setup buffers and return size and count of - * buffers allocated. After the call to this buffer, videobuf layer will - * setup buffer queue depending on the size and count of buffers - */ -static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - int startindex = 0, i, j; - u32 phy_addr = 0, virt_addr = 0; - struct omap_vout_device *vout = q->priv_data; - struct omapvideo_info *ovid = &vout->vid_info; - int vid_max_buf_size; - - if (!vout) - return -EINVAL; - - vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize : - video2_bufsize; - - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type) - return -EINVAL; - - startindex = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex) - *count = startindex; - - if (ovid->rotation_type == VOUT_ROT_VRFB) { - if (omap_vout_vrfb_buffer_setup(vout, count, startindex)) - return -ENOMEM; - } - - if (V4L2_MEMORY_MMAP != vout->memory) - return 0; - - /* Now allocated the V4L2 buffers */ - *size = PAGE_ALIGN(vout->pix.width * vout->pix.height * vout->bpp); - startindex = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - - /* Check the size of the buffer */ - if (*size > vid_max_buf_size) { - v4l2_err(&vout->vid_dev->v4l2_dev, - "buffer allocation mismatch [%u] [%u]\n", - *size, vout->buffer_size); - return -ENOMEM; - } - - for (i = startindex; i < *count; i++) { - vout->buffer_size = *size; - - virt_addr = omap_vout_alloc_buffer(vout->buffer_size, - &phy_addr); - if (!virt_addr) { - if (ovid->rotation_type == VOUT_ROT_NONE) - break; - - if (!is_rotation_enabled(vout)) - break; - - /* Free the VRFB buffers if no space for V4L2 buffers */ - for (j = i; j < *count; j++) { - omap_vout_free_buffer(vout->smsshado_virt_addr[j], - vout->smsshado_size); - vout->smsshado_virt_addr[j] = 0; - vout->smsshado_phy_addr[j] = 0; - } - } - vout->buf_virt_addr[i] = virt_addr; - vout->buf_phy_addr[i] = phy_addr; - } - *count = vout->buffer_allocated = i; - - return 0; -} - -/* - * Free the V4L2 buffers additionally allocated than default - * number of buffers - */ -static void omap_vout_free_extra_buffers(struct omap_vout_device *vout) -{ - int num_buffers = 0, i; - - num_buffers = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - - for (i = num_buffers; i < vout->buffer_allocated; i++) { - if (vout->buf_virt_addr[i]) - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - - vout->buf_virt_addr[i] = 0; - vout->buf_phy_addr[i] = 0; - } - vout->buffer_allocated = num_buffers; -} - -/* - * This function will be called when VIDIOC_QBUF ioctl is called. - * It prepare buffers before give out for the display. This function - * converts user space virtual address into physical address if userptr memory - * exchange mechanism is used. If rotation is enabled, it copies entire - * buffer into VRFB memory space before giving it to the DSS. - */ -static int omap_vout_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct omap_vout_device *vout = q->priv_data; - struct omapvideo_info *ovid = &vout->vid_info; - - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = vout->pix.width; - vb->height = vout->pix.height; - vb->size = vb->width * vb->height * vout->bpp; - vb->field = field; - } - vb->state = VIDEOBUF_PREPARED; - /* if user pointer memory mechanism is used, get the physical - * address of the buffer - */ - if (V4L2_MEMORY_USERPTR == vb->memory) { - int ret; - - if (0 == vb->baddr) - return -EINVAL; - /* Physical address */ - ret = omap_vout_get_userptr(vb, vb->baddr, - (u32 *)&vout->queued_buf_addr[vb->i]); - if (ret < 0) - return ret; - } else { - unsigned long addr, dma_addr; - unsigned long size; - - addr = (unsigned long) vout->buf_virt_addr[vb->i]; - size = (unsigned long) vb->size; - - dma_addr = dma_map_single(vout->vid_dev->v4l2_dev.dev, (void *) addr, - size, DMA_TO_DEVICE); - if (dma_mapping_error(vout->vid_dev->v4l2_dev.dev, dma_addr)) - v4l2_err(&vout->vid_dev->v4l2_dev, - "dma_map_single failed\n"); - - vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i]; - } - - if (ovid->rotation_type == VOUT_ROT_VRFB) - return omap_vout_prepare_vrfb(vout, vb); - else - return 0; -} - -/* - * Buffer queue function will be called from the videobuf layer when _QBUF - * ioctl is called. It is used to enqueue buffer, which is ready to be - * displayed. - */ -static void omap_vout_buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct omap_vout_device *vout = q->priv_data; - - /* Driver is also maintainig a queue. So enqueue buffer in the driver - * queue */ - list_add_tail(&vb->queue, &vout->dma_queue); - - vb->state = VIDEOBUF_QUEUED; -} - -/* - * Buffer release function is called from videobuf layer to release buffer - * which are already allocated - */ -static void omap_vout_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - vb->state = VIDEOBUF_NEEDS_INIT; - if (vb->memory == V4L2_MEMORY_USERPTR && vb->priv) { - struct frame_vector *vec = vb->priv; - - put_vaddr_frames(vec); - frame_vector_destroy(vec); - } -} - -/* - * File operations - */ -static __poll_t omap_vout_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct omap_vout_device *vout = file->private_data; - struct videobuf_queue *q = &vout->vbq; - - return videobuf_poll_stream(file, q, wait); -} - -static void omap_vout_vm_open(struct vm_area_struct *vma) -{ - struct omap_vout_device *vout = vma->vm_private_data; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - "vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end); - vout->mmap_count++; -} - -static void omap_vout_vm_close(struct vm_area_struct *vma) -{ - struct omap_vout_device *vout = vma->vm_private_data; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - "vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end); - vout->mmap_count--; -} - -static const struct vm_operations_struct omap_vout_vm_ops = { - .open = omap_vout_vm_open, - .close = omap_vout_vm_close, -}; - -static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma) -{ - int i; - void *pos; - unsigned long start = vma->vm_start; - unsigned long size = (vma->vm_end - vma->vm_start); - struct omap_vout_device *vout = file->private_data; - struct videobuf_queue *q = &vout->vbq; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - " %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__, - vma->vm_pgoff, vma->vm_start, vma->vm_end); - - /* look for the buffer to map */ - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (V4L2_MEMORY_MMAP != q->bufs[i]->memory) - continue; - if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT)) - break; - } - - if (VIDEO_MAX_FRAME == i) { - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - "offset invalid [offset=0x%lx]\n", - (vma->vm_pgoff << PAGE_SHIFT)); - return -EINVAL; - } - /* Check the size of the buffer */ - if (size > vout->buffer_size) { - v4l2_err(&vout->vid_dev->v4l2_dev, - "insufficient memory [%lu] [%u]\n", - size, vout->buffer_size); - return -ENOMEM; - } - - q->bufs[i]->baddr = vma->vm_start; - - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - vma->vm_ops = &omap_vout_vm_ops; - vma->vm_private_data = (void *) vout; - pos = (void *)vout->buf_virt_addr[i]; - vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT; - while (size > 0) { - unsigned long pfn; - pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT; - if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - vout->mmap_count++; - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); - - return 0; -} - -static int omap_vout_release(struct file *file) -{ - unsigned int ret, i; - struct videobuf_queue *q; - struct omapvideo_info *ovid; - struct omap_vout_device *vout = file->private_data; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); - ovid = &vout->vid_info; - - if (!vout) - return 0; - - q = &vout->vbq; - /* Disable all the overlay managers connected with this interface */ - for (i = 0; i < ovid->num_overlays; i++) { - struct omap_overlay *ovl = ovid->overlays[i]; - struct omap_dss_device *dssdev = ovl->get_device(ovl); - - if (dssdev) - ovl->disable(ovl); - } - /* Turn off the pipeline */ - ret = omapvid_apply_changes(vout); - if (ret) - v4l2_warn(&vout->vid_dev->v4l2_dev, - "Unable to apply changes\n"); - - /* Free all buffers */ - omap_vout_free_extra_buffers(vout); - - /* Free the VRFB buffers only if they are allocated - * during reqbufs. Don't free if init time allocated - */ - if (ovid->rotation_type == VOUT_ROT_VRFB) { - if (!vout->vrfb_static_allocation) - omap_vout_free_vrfb_buffers(vout); - } - videobuf_mmap_free(q); - - /* Even if apply changes fails we should continue - freeing allocated memory */ - if (vout->streaming) { - u32 mask = 0; - - mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | - DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2; - omap_dispc_unregister_isr(omap_vout_isr, vout, mask); - vout->streaming = false; - - videobuf_streamoff(q); - videobuf_queue_cancel(q); - } - - if (vout->mmap_count != 0) - vout->mmap_count = 0; - - vout->opened -= 1; - file->private_data = NULL; - - if (vout->buffer_allocated) - videobuf_mmap_free(q); - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); - return ret; -} - -static int omap_vout_open(struct file *file) -{ - struct videobuf_queue *q; - struct omap_vout_device *vout = NULL; - - vout = video_drvdata(file); - - if (vout == NULL) - return -ENODEV; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); - - /* for now, we only support single open */ - if (vout->opened) - return -EBUSY; - - vout->opened += 1; - - file->private_data = vout; - vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - - q = &vout->vbq; - video_vbq_ops.buf_setup = omap_vout_buffer_setup; - video_vbq_ops.buf_prepare = omap_vout_buffer_prepare; - video_vbq_ops.buf_release = omap_vout_buffer_release; - video_vbq_ops.buf_queue = omap_vout_buffer_queue; - spin_lock_init(&vout->vbq_lock); - - videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev, - &vout->vbq_lock, vout->type, V4L2_FIELD_NONE, - sizeof(struct videobuf_buffer), vout, NULL); - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); - return 0; -} /* * V4L2 ioctls @@ -1039,15 +570,12 @@ static int omap_vout_open(struct file *file) static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); strscpy(cap->driver, VOUT_NAME, sizeof(cap->driver)); strscpy(cap->card, vout->vfd->name, sizeof(cap->card)); - cap->bus_info[0] = '\0'; - cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT | - V4L2_CAP_VIDEO_OUTPUT_OVERLAY; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s.%d", VOUT_NAME, vout->vid); return 0; } @@ -1060,8 +588,6 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *fh, return -EINVAL; fmt->flags = omap_formats[index].flags; - strscpy(fmt->description, omap_formats[index].description, - sizeof(fmt->description)); fmt->pixelformat = omap_formats[index].pixelformat; return 0; @@ -1070,7 +596,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *fh, static int vidioc_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f) { - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); f->fmt.pix = vout->pix; return 0; @@ -1083,7 +609,7 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *fh, struct omap_overlay *ovl; struct omapvideo_info *ovid; struct omap_video_timings *timing; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omap_dss_device *dssdev; ovid = &vout->vid_info; @@ -1110,14 +636,12 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, struct omap_overlay *ovl; struct omapvideo_info *ovid; struct omap_video_timings *timing; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omap_dss_device *dssdev; - if (vout->streaming) + if (vb2_is_busy(&vout->vq)) return -EBUSY; - mutex_lock(&vout->lock); - ovid = &vout->vid_info; ovl = ovid->overlays[0]; dssdev = ovl->get_device(ovl); @@ -1168,7 +692,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, ret = 0; s_fmt_vid_out_exit: - mutex_unlock(&vout->lock); return ret; } @@ -1176,7 +699,7 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) { int ret = 0; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omap_overlay *ovl; struct omapvideo_info *ovid; struct v4l2_window *win = &f->fmt.win; @@ -1186,12 +709,8 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, ret = omap_vout_try_window(&vout->fbuf, win); - if (!ret) { - if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) - win->global_alpha = 255; - else - win->global_alpha = f->fmt.win.global_alpha; - } + if (!ret && !(ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA)) + win->global_alpha = 0; return ret; } @@ -1202,35 +721,53 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh, int ret = 0; struct omap_overlay *ovl; struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct v4l2_window *win = &f->fmt.win; - mutex_lock(&vout->lock); ovid = &vout->vid_info; ovl = ovid->overlays[0]; ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win); if (!ret) { + enum omap_dss_trans_key_type key_type = + OMAP_DSS_COLOR_KEY_GFX_DST; + int enable; + /* Video1 plane does not support global alpha on OMAP3 */ - if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) - vout->win.global_alpha = 255; + if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) + vout->win.global_alpha = win->global_alpha; + else + win->global_alpha = 0; + if (vout->fbuf.flags & (V4L2_FBUF_FLAG_CHROMAKEY | + V4L2_FBUF_FLAG_SRC_CHROMAKEY)) + enable = 1; else - vout->win.global_alpha = f->fmt.win.global_alpha; + enable = 0; + if (vout->fbuf.flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) + key_type = OMAP_DSS_COLOR_KEY_VID_SRC; + + if (ovl->manager && ovl->manager->get_manager_info && + ovl->manager->set_manager_info) { + struct omap_overlay_manager_info info; - vout->win.chromakey = f->fmt.win.chromakey; + ovl->manager->get_manager_info(ovl->manager, &info); + info.trans_enabled = enable; + info.trans_key_type = key_type; + info.trans_key = vout->win.chromakey; + + if (ovl->manager->set_manager_info(ovl->manager, &info)) + return -EINVAL; + } } - mutex_unlock(&vout->lock); return ret; } static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) { - u32 key_value = 0; struct omap_overlay *ovl; struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; - struct omap_overlay_manager_info info; + struct omap_vout_device *vout = video_drvdata(file); struct v4l2_window *win = &f->fmt.win; ovid = &vout->vid_info; @@ -1238,19 +775,20 @@ static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, win->w = vout->win.w; win->field = vout->win.field; - win->global_alpha = vout->win.global_alpha; - - if (ovl->manager && ovl->manager->get_manager_info) { - ovl->manager->get_manager_info(ovl->manager, &info); - key_value = info.trans_key; - } - win->chromakey = key_value; + win->chromakey = vout->win.chromakey; + if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) + win->global_alpha = vout->win.global_alpha; + else + win->global_alpha = 0; + win->clips = NULL; + win->clipcount = 0; + win->bitmap = NULL; return 0; } static int vidioc_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) { - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct v4l2_pix_format *pix = &vout->pix; if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -1277,7 +815,7 @@ static int vidioc_g_selection(struct file *file, void *fh, struct v4l2_selection static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection *sel) { int ret = -EINVAL; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omapvideo_info *ovid; struct omap_overlay *ovl; struct omap_video_timings *timing; @@ -1289,10 +827,9 @@ static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - if (vout->streaming) + if (vb2_is_busy(&vout->vq)) return -EBUSY; - mutex_lock(&vout->lock); ovid = &vout->vid_info; ovl = ovid->overlays[0]; /* get the display device attached to the overlay */ @@ -1317,7 +854,6 @@ static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection &vout->fbuf, &sel->r); s_crop_err: - mutex_unlock(&vout->lock); return ret; } @@ -1334,26 +870,21 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl) ovid = &vout->vid_info; - mutex_lock(&vout->lock); if (rotation && ovid->rotation_type == VOUT_ROT_NONE) { - mutex_unlock(&vout->lock); ret = -ERANGE; break; } if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { - mutex_unlock(&vout->lock); ret = -EINVAL; break; } if (v4l2_rot_to_dss_rot(rotation, &vout->rotation, vout->mirror)) { - mutex_unlock(&vout->lock); ret = -EINVAL; break; } - mutex_unlock(&vout->lock); break; } case V4L2_CID_BG_COLOR: @@ -1364,9 +895,7 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl) ovl = vout->vid_info.overlays[0]; - mutex_lock(&vout->lock); if (!ovl->manager || !ovl->manager->get_manager_info) { - mutex_unlock(&vout->lock); ret = -EINVAL; break; } @@ -1374,11 +903,9 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl) ovl->manager->get_manager_info(ovl->manager, &info); info.default_color = color; if (ovl->manager->set_manager_info(ovl->manager, &info)) { - mutex_unlock(&vout->lock); ret = -EINVAL; break; } - mutex_unlock(&vout->lock); break; } case V4L2_CID_VFLIP: @@ -1388,20 +915,16 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl) ovid = &vout->vid_info; - mutex_lock(&vout->lock); if (mirror && ovid->rotation_type == VOUT_ROT_NONE) { - mutex_unlock(&vout->lock); ret = -ERANGE; break; } if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { - mutex_unlock(&vout->lock); ret = -EINVAL; break; } vout->mirror = mirror; - mutex_unlock(&vout->lock); break; } default: @@ -1414,185 +937,94 @@ static const struct v4l2_ctrl_ops omap_vout_ctrl_ops = { .s_ctrl = omap_vout_s_ctrl, }; -static int vidioc_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *req) +static int omap_vout_vb2_queue_setup(struct vb2_queue *vq, + unsigned int *nbufs, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) { - int ret = 0; - unsigned int i, num_buffers = 0; - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; - - if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - /* if memory is not mmp or userptr - return error */ - if ((V4L2_MEMORY_MMAP != req->memory) && - (V4L2_MEMORY_USERPTR != req->memory)) - return -EINVAL; - - mutex_lock(&vout->lock); - /* Cannot be requested when streaming is on */ - if (vout->streaming) { - ret = -EBUSY; - goto reqbuf_err; - } + struct omap_vout_device *vout = vb2_get_drv_priv(vq); + int size = vout->pix.sizeimage; - /* If buffers are already allocated free them */ - if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) { - if (vout->mmap_count) { - ret = -EBUSY; - goto reqbuf_err; - } - num_buffers = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - for (i = num_buffers; i < vout->buffer_allocated; i++) { - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - vout->buf_virt_addr[i] = 0; - vout->buf_phy_addr[i] = 0; - } - vout->buffer_allocated = num_buffers; - videobuf_mmap_free(q); - } else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) { - if (vout->buffer_allocated) { - videobuf_mmap_free(q); - for (i = 0; i < vout->buffer_allocated; i++) { - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - vout->buffer_allocated = 0; - } + if (is_rotation_enabled(vout) && vq->num_buffers + *nbufs > VRFB_NUM_BUFS) { + *nbufs = VRFB_NUM_BUFS - vq->num_buffers; + if (*nbufs == 0) + return -EINVAL; } - /*store the memory type in data structure */ - vout->memory = req->memory; - - INIT_LIST_HEAD(&vout->dma_queue); - - /* call videobuf_reqbufs api */ - ret = videobuf_reqbufs(q, req); - if (ret < 0) - goto reqbuf_err; - - vout->buffer_allocated = req->count; - -reqbuf_err: - mutex_unlock(&vout->lock); - return ret; -} - -static int vidioc_querybuf(struct file *file, void *fh, - struct v4l2_buffer *b) -{ - struct omap_vout_device *vout = fh; + if (*num_planes) + return sizes[0] < size ? -EINVAL : 0; - return videobuf_querybuf(&vout->vbq, b); + *num_planes = 1; + sizes[0] = size; + return 0; } -static int vidioc_qbuf(struct file *file, void *fh, - struct v4l2_buffer *buffer) +static int omap_vout_vb2_prepare(struct vb2_buffer *vb) { - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; + struct omap_vout_device *vout = vb2_get_drv_priv(vb->vb2_queue); + struct omapvideo_info *ovid = &vout->vid_info; + struct omap_vout_buffer *voutbuf = vb2_to_omap_vout_buffer(vb); + dma_addr_t buf_phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0); - if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) || - (buffer->index >= vout->buffer_allocated) || - (q->bufs[buffer->index]->memory != buffer->memory)) { + if (vb2_plane_size(vb, 0) < vout->pix.sizeimage) { + v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, + "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), vout->pix.sizeimage); return -EINVAL; } - if (V4L2_MEMORY_USERPTR == buffer->memory) { - if ((buffer->length < vout->pix.sizeimage) || - (0 == buffer->m.userptr)) { - return -EINVAL; - } - } - if ((is_rotation_enabled(vout)) && - vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) { - v4l2_warn(&vout->vid_dev->v4l2_dev, - "DMA Channel not allocated for Rotation\n"); - return -EINVAL; - } + vb2_set_plane_payload(vb, 0, vout->pix.sizeimage); + voutbuf->vbuf.field = V4L2_FIELD_NONE; - return videobuf_qbuf(q, buffer); + vout->queued_buf_addr[vb->index] = (u8 *)buf_phy_addr; + if (ovid->rotation_type == VOUT_ROT_VRFB) + return omap_vout_prepare_vrfb(vout, vb); + return 0; } -static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) +static void omap_vout_vb2_queue(struct vb2_buffer *vb) { - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; + struct omap_vout_device *vout = vb2_get_drv_priv(vb->vb2_queue); + struct omap_vout_buffer *voutbuf = vb2_to_omap_vout_buffer(vb); - int ret; - u32 addr; - unsigned long size; - struct videobuf_buffer *vb; - - if (!vout->streaming) - return -EINVAL; - - ret = videobuf_dqbuf(q, b, !!(file->f_flags & O_NONBLOCK)); - if (ret) - return ret; - - vb = q->bufs[b->index]; - - addr = (unsigned long) vout->buf_phy_addr[vb->i]; - size = (unsigned long) vb->size; - dma_unmap_single(vout->vid_dev->v4l2_dev.dev, addr, - size, DMA_TO_DEVICE); - return 0; + list_add_tail(&voutbuf->queue, &vout->dma_queue); } -static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) +static int omap_vout_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) { - int ret = 0, j; - u32 addr = 0, mask = 0; - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; + struct omap_vout_device *vout = vb2_get_drv_priv(vq); struct omapvideo_info *ovid = &vout->vid_info; - - mutex_lock(&vout->lock); - - if (vout->streaming) { - ret = -EBUSY; - goto streamon_err; - } - - ret = videobuf_streamon(q); - if (ret) - goto streamon_err; - - if (list_empty(&vout->dma_queue)) { - ret = -EIO; - goto streamon_err1; - } + struct omap_vout_buffer *buf, *tmp; + u32 addr = 0, mask = 0; + int ret, j; /* Get the next frame from the buffer queue */ vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next, - struct videobuf_buffer, queue); + struct omap_vout_buffer, queue); /* Remove buffer from the buffer queue */ list_del(&vout->cur_frm->queue); - /* Mark state of the current frame to active */ - vout->cur_frm->state = VIDEOBUF_ACTIVE; /* Initialize field_id and started member */ vout->field_id = 0; - - /* set flag here. Next QBUF will start DMA */ - vout->streaming = true; - vout->first_int = 1; + vout->sequence = 0; if (omap_vout_calculate_offset(vout)) { ret = -EINVAL; - goto streamon_err1; + goto out; } - addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i] + if (ovid->rotation_type == VOUT_ROT_VRFB) + if (omap_vout_vrfb_buffer_setup(vout, &count, 0)) { + ret = -ENOMEM; + goto out; + } + + addr = (unsigned long)vout->queued_buf_addr[vout->cur_frm->vbuf.vb2_buf.index] + vout->cropped_offset; mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2; - /* First save the configuration in ovelray structure */ + /* First save the configuration in overlay structure */ ret = omapvid_init(vout, addr); if (ret) { v4l2_err(&vout->vid_dev->v4l2_dev, @@ -1617,28 +1049,43 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) goto streamon_err1; } } - - ret = 0; + return 0; streamon_err1: - if (ret) - ret = videobuf_streamoff(q); -streamon_err: - mutex_unlock(&vout->lock); + mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD + | DISPC_IRQ_VSYNC2; + + omap_dispc_unregister_isr(omap_vout_isr, vout, mask); + + for (j = 0; j < ovid->num_overlays; j++) { + struct omap_overlay *ovl = ovid->overlays[j]; + struct omap_dss_device *dssdev = ovl->get_device(ovl); + + if (dssdev) + ovl->disable(ovl); + } + /* Turn of the pipeline */ + if (omapvid_apply_changes(vout)) + v4l2_err(&vout->vid_dev->v4l2_dev, + "failed to change mode in streamoff\n"); + +out: + vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); + list_for_each_entry_safe(buf, tmp, &vout->dma_queue, queue) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); + } return ret; } -static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) +static void omap_vout_vb2_stop_streaming(struct vb2_queue *vq) { - u32 mask = 0; - int ret = 0, j; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = vb2_get_drv_priv(vq); struct omapvideo_info *ovid = &vout->vid_info; + struct omap_vout_buffer *buf, *tmp; + u32 mask = 0; + int j; - if (!vout->streaming) - return -EINVAL; - - vout->streaming = false; mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2; @@ -1651,17 +1098,18 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) if (dssdev) ovl->disable(ovl); } - /* Turn of the pipeline */ - ret = omapvid_apply_changes(vout); - if (ret) + if (omapvid_apply_changes(vout)) v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode in streamoff\n"); - INIT_LIST_HEAD(&vout->dma_queue); - ret = videobuf_streamoff(&vout->vbq); - - return ret; + if (vout->next_frm != vout->cur_frm) + vb2_buffer_done(&vout->next_frm->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); + list_for_each_entry_safe(buf, tmp, &vout->dma_queue, queue) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); + } } static int vidioc_s_fbuf(struct file *file, void *fh, @@ -1670,7 +1118,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, int enable = 0; struct omap_overlay *ovl; struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omap_overlay_manager_info info; enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST; @@ -1741,17 +1189,36 @@ static int vidioc_g_fbuf(struct file *file, void *fh, { struct omap_overlay *ovl; struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omap_overlay_manager_info info; + struct omap_video_timings *timing; + struct omap_dss_device *dssdev; ovid = &vout->vid_info; ovl = ovid->overlays[0]; + /* get the display device attached to the overlay */ + dssdev = ovl->get_device(ovl); + + if (!dssdev) + return -EINVAL; + + timing = &dssdev->panel.timings; - /* The video overlay must stay within the framebuffer and can't be - positioned independently. */ - a->flags = V4L2_FBUF_FLAG_OVERLAY; - a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY - | V4L2_FBUF_CAP_SRC_CHROMAKEY; + vout->fbuf.fmt.height = timing->y_res; + vout->fbuf.fmt.width = timing->x_res; + a->fmt.field = V4L2_FIELD_NONE; + a->fmt.colorspace = V4L2_COLORSPACE_SRGB; + a->fmt.pixelformat = V4L2_PIX_FMT_RGBA32; + a->fmt.height = vout->fbuf.fmt.height; + a->fmt.width = vout->fbuf.fmt.width; + a->fmt.bytesperline = vout->fbuf.fmt.width * 4; + a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline; + a->base = vout->fbuf.base; + + a->flags = vout->fbuf.flags; + a->capability = vout->fbuf.capability; + a->flags &= ~(V4L2_FBUF_FLAG_SRC_CHROMAKEY | V4L2_FBUF_FLAG_CHROMAKEY | + V4L2_FBUF_FLAG_LOCAL_ALPHA); if (ovl->manager && ovl->manager->get_manager_info) { ovl->manager->get_manager_info(ovl->manager, &info); @@ -1759,9 +1226,6 @@ static int vidioc_g_fbuf(struct file *file, void *fh, a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY; if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST) a->flags |= V4L2_FBUF_FLAG_CHROMAKEY; - } - if (ovl->manager && ovl->manager->get_manager_info) { - ovl->manager->get_manager_info(ovl->manager, &info); if (info.partial_alpha_enabled) a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; } @@ -1769,6 +1233,27 @@ static int vidioc_g_fbuf(struct file *file, void *fh, return 0; } +static int vidioc_enum_output(struct file *file, void *priv_fh, + struct v4l2_output *out) +{ + if (out->index) + return -EINVAL; + snprintf(out->name, sizeof(out->name), "Overlay"); + out->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY; + return 0; +} + +static int vidioc_g_output(struct file *file, void *priv_fh, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_output(struct file *file, void *priv_fh, unsigned int i) +{ + return i ? -EINVAL : 0; +} + static const struct v4l2_ioctl_ops vout_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, @@ -1782,21 +1267,38 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = { .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_overlay, .vidioc_g_selection = vidioc_g_selection, .vidioc_s_selection = vidioc_s_selection, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_enum_output = vidioc_enum_output, + .vidioc_g_output = vidioc_g_output, + .vidioc_s_output = vidioc_s_output, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static const struct v4l2_file_operations omap_vout_fops = { .owner = THIS_MODULE, - .poll = omap_vout_poll, .unlocked_ioctl = video_ioctl2, - .mmap = omap_vout_mmap, - .open = omap_vout_open, - .release = omap_vout_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .open = v4l2_fh_open, + .release = vb2_fop_release, +}; + +static const struct vb2_ops omap_vout_vb2_ops = { + .queue_setup = omap_vout_vb2_queue_setup, + .buf_queue = omap_vout_vb2_queue, + .buf_prepare = omap_vout_vb2_prepare, + .start_streaming = omap_vout_vb2_start_streaming, + .stop_streaming = omap_vout_vb2_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; /* Init functions used during driver initialization */ @@ -1808,6 +1310,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) struct omap_overlay *ovl = vout->vid_info.overlays[0]; struct omap_dss_device *display = ovl->get_device(ovl); struct v4l2_ctrl_handler *hdl; + struct vb2_queue *vq; + int ret; /* set the default pix */ pix = &vout->pix; @@ -1818,37 +1322,48 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) /* Default pixel format is RGB 5-6-5 */ pix->pixelformat = V4L2_PIX_FMT_RGB565; - pix->field = V4L2_FIELD_ANY; + pix->field = V4L2_FIELD_NONE; pix->bytesperline = pix->width * 2; pix->sizeimage = pix->bytesperline * pix->height; - pix->colorspace = V4L2_COLORSPACE_JPEG; + pix->colorspace = V4L2_COLORSPACE_SRGB; vout->bpp = RGB565_BPP; vout->fbuf.fmt.width = display->panel.timings.x_res; vout->fbuf.fmt.height = display->panel.timings.y_res; + vout->cropped_offset = 0; /* Set the data structures for the overlay parameters*/ - vout->win.global_alpha = 255; - vout->fbuf.flags = 0; + vout->fbuf.flags = V4L2_FBUF_FLAG_OVERLAY; vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA | - V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY; - vout->win.chromakey = 0; + V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY | + V4L2_FBUF_CAP_EXTERNOVERLAY; + if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) { + vout->win.global_alpha = 255; + vout->fbuf.capability |= V4L2_FBUF_CAP_GLOBAL_ALPHA; + vout->fbuf.flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; + } else { + vout->win.global_alpha = 0; + } + vout->win.field = V4L2_FIELD_NONE; omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win); hdl = &vout->ctrl_handler; v4l2_ctrl_handler_init(hdl, 3); - v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, - V4L2_CID_ROTATE, 0, 270, 90, 0); + if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) { + v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, + V4L2_CID_ROTATE, 0, 270, 90, 0); + v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + } v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, V4L2_CID_BG_COLOR, 0, 0xffffff, 1, 0); - v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); if (hdl->error) return hdl->error; vout->rotation = 0; vout->mirror = false; + INIT_LIST_HEAD(&vout->dma_queue); if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) vout->vrfb_bpp = 2; @@ -1870,63 +1385,54 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) vfd->fops = &omap_vout_fops; vfd->v4l2_dev = &vout->vid_dev->v4l2_dev; vfd->vfl_dir = VFL_DIR_TX; - mutex_init(&vout->lock); - vfd->minor = -1; - return 0; + vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + mutex_init(&vout->lock); + vq = &vout->vq; + vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + vq->io_modes = VB2_MMAP | VB2_DMABUF; + vq->drv_priv = vout; + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vq->buf_struct_size = sizeof(struct omap_vout_buffer); + vq->dev = vfd->v4l2_dev->dev; + + vq->ops = &omap_vout_vb2_ops; + vq->mem_ops = &vb2_dma_contig_memops; + vq->lock = &vout->lock; + vq->min_buffers_needed = 1; + vfd->queue = vq; + + ret = vb2_queue_init(vq); + if (ret) { + v4l2_ctrl_handler_free(hdl); + video_device_release(vfd); + } + return ret; } /* Setup video buffers */ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev, int vid_num) { - u32 numbuffers; - int ret = 0, i; struct omapvideo_info *ovid; struct omap_vout_device *vout; struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); struct omap2video_device *vid_dev = container_of(v4l2_dev, struct omap2video_device, v4l2_dev); + int ret = 0; vout = vid_dev->vouts[vid_num]; ovid = &vout->vid_info; - numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers; - vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize; - dev_info(&pdev->dev, "Buffer Size = %d\n", vout->buffer_size); - - for (i = 0; i < numbuffers; i++) { - vout->buf_virt_addr[i] = - omap_vout_alloc_buffer(vout->buffer_size, - (u32 *) &vout->buf_phy_addr[i]); - if (!vout->buf_virt_addr[i]) { - numbuffers = i; - ret = -ENOMEM; - goto free_buffers; - } - } - - vout->cropped_offset = 0; - if (ovid->rotation_type == VOUT_ROT_VRFB) { bool static_vrfb_allocation = (vid_num == 0) ? vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; ret = omap_vout_setup_vrfb_bufs(pdev, vid_num, static_vrfb_allocation); } - - return ret; - -free_buffers: - for (i = 0; i < numbuffers; i++) { - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - vout->buf_virt_addr[i] = 0; - vout->buf_phy_addr[i] = 0; - } return ret; - } /* Create video out devices */ @@ -1938,6 +1444,10 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); struct omap2video_device *vid_dev = container_of(v4l2_dev, struct omap2video_device, v4l2_dev); + struct omap_overlay *ovl = vid_dev->overlays[0]; + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); for (k = 0; k < pdev->num_resources; k++) { @@ -1958,6 +1468,15 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) vout->vid_info.overlays[0] = vid_dev->overlays[k + 1]; vout->vid_info.num_overlays = 1; vout->vid_info.id = k + 1; + spin_lock_init(&vout->vbq_lock); + /* + * Set the framebuffer base, this allows applications to find + * the fb corresponding to this overlay. + * + * To be precise: fbuf.base should match smem_start of + * struct fb_fix_screeninfo. + */ + vout->fbuf.base = (void *)info.paddr; /* Set VRFB as rotation_type for omap2 and omap3 */ if (omap_vout_dss_omap24xx() || omap_vout_dss_omap34xx()) @@ -2000,7 +1519,6 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) error2: if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) omap_vout_release_vrfb(vout); - omap_vout_free_buffers(vout); error1: video_device_release(vfd); error: @@ -2045,7 +1563,6 @@ static void omap_vout_cleanup_device(struct omap_vout_device *vout) if (vout->vrfb_static_allocation) omap_vout_free_vrfb_buffers(vout); } - omap_vout_free_buffers(vout); kfree(vout); } diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index 11ec048929e8..6bd672cbdb62 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -14,7 +14,6 @@ #include <linux/videodev2.h> #include <linux/slab.h> -#include <media/videobuf-dma-contig.h> #include <media/v4l2-device.h> #include <video/omapvrfb.h> @@ -40,7 +39,7 @@ static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout, &vout->smsshado_phy_addr[i]); } if (!vout->smsshado_virt_addr[i] && startindex != -1) { - if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex) + if (vout->vq.memory == V4L2_MEMORY_MMAP && i >= startindex) break; } if (!vout->smsshado_virt_addr[i]) { @@ -109,8 +108,7 @@ int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, dev_info(&pdev->dev, ": VRFB allocation failed\n"); for (j = 0; j < i; j++) omap_vrfb_release_ctx(&vout->vrfb_context[j]); - ret = -ENOMEM; - goto free_buffers; + return -ENOMEM; } } @@ -155,8 +153,10 @@ int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, init_waitqueue_head(&vout->vrfb_dma_tx.wait); - /* statically allocated the VRFB buffer is done through - commands line aruments */ + /* + * statically allocated the VRFB buffer is done through + * command line arguments + */ if (static_vrfb_allocation) { if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) { ret = -ENOMEM; @@ -169,9 +169,6 @@ int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, release_vrfb_ctx: for (j = 0; j < VRFB_NUM_BUFS; j++) omap_vrfb_release_ctx(&vout->vrfb_context[j]); -free_buffers: - omap_vout_free_buffers(vout); - return ret; } @@ -231,13 +228,14 @@ int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, } int omap_vout_prepare_vrfb(struct omap_vout_device *vout, - struct videobuf_buffer *vb) + struct vb2_buffer *vb) { struct dma_async_tx_descriptor *tx; enum dma_ctrl_flags flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; struct dma_chan *chan = vout->vrfb_dma_tx.chan; struct dma_interleaved_template *xt = vout->vrfb_dma_tx.xt; dma_cookie_t cookie; + dma_addr_t buf_phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0); enum dma_status status; enum dss_rotation rotation; size_t dst_icg; @@ -255,8 +253,8 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, pixsize = vout->bpp * vout->vrfb_bpp; dst_icg = MAX_PIXELS_PER_LINE * pixsize - vout->pix.width * vout->bpp; - xt->src_start = vout->buf_phy_addr[vb->i]; - xt->dst_start = vout->vrfb_context[vb->i].paddr[0]; + xt->src_start = buf_phy_addr; + xt->dst_start = vout->vrfb_context[vb->index].paddr[0]; xt->numf = vout->pix.height; xt->frame_size = 1; @@ -307,8 +305,8 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, /* Store buffers physical address into an array. Addresses * from this array will be used to configure DSS */ rotation = calc_rotation(vout); - vout->queued_buf_addr[vb->i] = (u8 *) - vout->vrfb_context[vb->i].paddr[rotation]; + vout->queued_buf_addr[vb->index] = (u8 *) + vout->vrfb_context[vb->index].paddr[rotation]; return 0; } diff --git a/drivers/media/platform/omap/omap_vout_vrfb.h b/drivers/media/platform/omap/omap_vout_vrfb.h index c976975024df..40bc9e54ecc6 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.h +++ b/drivers/media/platform/omap/omap_vout_vrfb.h @@ -20,7 +20,7 @@ void omap_vout_release_vrfb(struct omap_vout_device *vout); int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, unsigned int *count, unsigned int startindex); int omap_vout_prepare_vrfb(struct omap_vout_device *vout, - struct videobuf_buffer *vb); + struct vb2_buffer *vb); void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout); #else static inline void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }; @@ -32,7 +32,7 @@ static inline int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, unsigned int *count, unsigned int startindex) { return 0; }; static inline int omap_vout_prepare_vrfb(struct omap_vout_device *vout, - struct videobuf_buffer *vb) + struct vb2_buffer *vb) { return 0; }; static inline void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { }; #endif diff --git a/drivers/media/platform/omap/omap_voutdef.h b/drivers/media/platform/omap/omap_voutdef.h index c740393c8509..1cff6dea1879 100644 --- a/drivers/media/platform/omap/omap_voutdef.h +++ b/drivers/media/platform/omap/omap_voutdef.h @@ -11,6 +11,7 @@ #ifndef OMAP_VOUTDEF_H #define OMAP_VOUTDEF_H +#include <media/videobuf2-dma-contig.h> #include <media/v4l2-ctrls.h> #include <video/omapfb_dss.h> #include <video/omapvrfb.h> @@ -113,6 +114,20 @@ struct omap2video_device { struct omap_overlay_manager *managers[MAX_MANAGERS]; }; +/* buffer for one video frame */ +struct omap_vout_buffer { + /* common v4l buffer stuff -- must be first */ + struct vb2_v4l2_buffer vbuf; + struct list_head queue; +}; + +static inline struct omap_vout_buffer *vb2_to_omap_vout_buffer(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + return container_of(vbuf, struct omap_vout_buffer, vbuf); +} + /* per-device data structure */ struct omap_vout_device { @@ -121,29 +136,12 @@ struct omap_vout_device { struct omap2video_device *vid_dev; struct v4l2_ctrl_handler ctrl_handler; int vid; - int opened; - /* we don't allow to change image fmt/size once buffer has - * been allocated - */ - int buffer_allocated; /* allow to reuse previously allocated buffer which is big enough */ int buffer_size; - /* keep buffer info across opens */ - unsigned long buf_virt_addr[VIDEO_MAX_FRAME]; - unsigned long buf_phy_addr[VIDEO_MAX_FRAME]; enum omap_color_mode dss_mode; - /* we don't allow to request new buffer when old buffers are - * still mmapped - */ - int mmap_count; - - spinlock_t vbq_lock; /* spinlock for videobuf queues */ - unsigned long field_count; /* field counter for videobuf_buffer */ - - /* non-NULL means streaming is in progress. */ - bool streaming; + u32 sequence; struct v4l2_pix_format pix; struct v4l2_rect crop; @@ -169,19 +167,14 @@ struct omap_vout_device { unsigned char pos; int ps, vr_ps, line_length, first_int, field_id; - enum v4l2_memory memory; - struct videobuf_buffer *cur_frm, *next_frm; + struct omap_vout_buffer *cur_frm, *next_frm; + spinlock_t vbq_lock; /* spinlock for dma_queue */ struct list_head dma_queue; u8 *queued_buf_addr[VIDEO_MAX_FRAME]; u32 cropped_offset; s32 tv_field1_offset; void *isr_handle; - - /* Buffer queue variables */ - struct omap_vout_device *vout; - enum v4l2_buf_type type; - struct videobuf_queue vbq; - int io_allowed; + struct vb2_queue vq; }; diff --git a/drivers/media/platform/omap/omap_voutlib.c b/drivers/media/platform/omap/omap_voutlib.c index 58a25fdf0cce..480a7e95533d 100644 --- a/drivers/media/platform/omap/omap_voutlib.c +++ b/drivers/media/platform/omap/omap_voutlib.c @@ -95,7 +95,11 @@ int omap_vout_try_window(struct v4l2_framebuffer *fbuf, /* We now have a valid preview window, so go with it */ new_win->w = try_win; - new_win->field = V4L2_FIELD_ANY; + new_win->field = V4L2_FIELD_NONE; + new_win->clips = NULL; + new_win->clipcount = 0; + new_win->bitmap = NULL; + return 0; } EXPORT_SYMBOL_GPL(omap_vout_try_window); diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 83216fc7156b..327c5716922a 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -719,6 +719,10 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, s_stream, mode); pipe->do_propagation = true; } + + /* Stop at the first external sub-device. */ + if (subdev->dev != isp->dev) + break; } return 0; @@ -833,6 +837,10 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) &subdev->entity); failure = -ETIMEDOUT; } + + /* Stop at the first external sub-device. */ + if (subdev->dev != isp->dev) + break; } return failure; @@ -2014,136 +2022,6 @@ enum isp_of_phy { ISP_OF_PHY_CSIPHY2, }; -static int isp_fwnode_parse(struct device *dev, - struct v4l2_fwnode_endpoint *vep, - struct v4l2_async_subdev *asd) -{ - struct isp_async_subdev *isd = - container_of(asd, struct isp_async_subdev, asd); - struct isp_bus_cfg *buscfg = &isd->bus; - bool csi1 = false; - unsigned int i; - - dev_dbg(dev, "parsing endpoint %pOF, interface %u\n", - to_of_node(vep->base.local_fwnode), vep->base.port); - - switch (vep->base.port) { - case ISP_OF_PHY_PARALLEL: - buscfg->interface = ISP_INTERFACE_PARALLEL; - buscfg->bus.parallel.data_lane_shift = - vep->bus.parallel.data_shift; - buscfg->bus.parallel.clk_pol = - !!(vep->bus.parallel.flags - & V4L2_MBUS_PCLK_SAMPLE_FALLING); - buscfg->bus.parallel.hs_pol = - !!(vep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW); - buscfg->bus.parallel.vs_pol = - !!(vep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW); - buscfg->bus.parallel.fld_pol = - !!(vep->bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW); - buscfg->bus.parallel.data_pol = - !!(vep->bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW); - buscfg->bus.parallel.bt656 = vep->bus_type == V4L2_MBUS_BT656; - break; - - case ISP_OF_PHY_CSIPHY1: - case ISP_OF_PHY_CSIPHY2: - switch (vep->bus_type) { - case V4L2_MBUS_CCP2: - case V4L2_MBUS_CSI1: - dev_dbg(dev, "CSI-1/CCP-2 configuration\n"); - csi1 = true; - break; - case V4L2_MBUS_CSI2_DPHY: - dev_dbg(dev, "CSI-2 configuration\n"); - csi1 = false; - break; - default: - dev_err(dev, "unsupported bus type %u\n", - vep->bus_type); - return -EINVAL; - } - - switch (vep->base.port) { - case ISP_OF_PHY_CSIPHY1: - if (csi1) - buscfg->interface = ISP_INTERFACE_CCP2B_PHY1; - else - buscfg->interface = ISP_INTERFACE_CSI2C_PHY1; - break; - case ISP_OF_PHY_CSIPHY2: - if (csi1) - buscfg->interface = ISP_INTERFACE_CCP2B_PHY2; - else - buscfg->interface = ISP_INTERFACE_CSI2A_PHY2; - break; - } - if (csi1) { - buscfg->bus.ccp2.lanecfg.clk.pos = - vep->bus.mipi_csi1.clock_lane; - buscfg->bus.ccp2.lanecfg.clk.pol = - vep->bus.mipi_csi1.lane_polarity[0]; - dev_dbg(dev, "clock lane polarity %u, pos %u\n", - buscfg->bus.ccp2.lanecfg.clk.pol, - buscfg->bus.ccp2.lanecfg.clk.pos); - - buscfg->bus.ccp2.lanecfg.data[0].pos = - vep->bus.mipi_csi1.data_lane; - buscfg->bus.ccp2.lanecfg.data[0].pol = - vep->bus.mipi_csi1.lane_polarity[1]; - - dev_dbg(dev, "data lane polarity %u, pos %u\n", - buscfg->bus.ccp2.lanecfg.data[0].pol, - buscfg->bus.ccp2.lanecfg.data[0].pos); - - buscfg->bus.ccp2.strobe_clk_pol = - vep->bus.mipi_csi1.clock_inv; - buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe; - buscfg->bus.ccp2.ccp2_mode = - vep->bus_type == V4L2_MBUS_CCP2; - buscfg->bus.ccp2.vp_clk_pol = 1; - - buscfg->bus.ccp2.crc = 1; - } else { - buscfg->bus.csi2.lanecfg.clk.pos = - vep->bus.mipi_csi2.clock_lane; - buscfg->bus.csi2.lanecfg.clk.pol = - vep->bus.mipi_csi2.lane_polarities[0]; - dev_dbg(dev, "clock lane polarity %u, pos %u\n", - buscfg->bus.csi2.lanecfg.clk.pol, - buscfg->bus.csi2.lanecfg.clk.pos); - - buscfg->bus.csi2.num_data_lanes = - vep->bus.mipi_csi2.num_data_lanes; - - for (i = 0; i < buscfg->bus.csi2.num_data_lanes; i++) { - buscfg->bus.csi2.lanecfg.data[i].pos = - vep->bus.mipi_csi2.data_lanes[i]; - buscfg->bus.csi2.lanecfg.data[i].pol = - vep->bus.mipi_csi2.lane_polarities[i + 1]; - dev_dbg(dev, - "data lane %u polarity %u, pos %u\n", i, - buscfg->bus.csi2.lanecfg.data[i].pol, - buscfg->bus.csi2.lanecfg.data[i].pos); - } - /* - * FIXME: now we assume the CRC is always there. - * Implement a way to obtain this information from the - * sensor. Frame descriptors, perhaps? - */ - buscfg->bus.csi2.crc = 1; - } - break; - - default: - dev_warn(dev, "%pOF: invalid interface %u\n", - to_of_node(vep->base.local_fwnode), vep->base.port); - return -EINVAL; - } - - return 0; -} - static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) { struct isp_device *isp = container_of(async, struct isp_device, @@ -2173,6 +2051,201 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) return media_device_register(&isp->media_dev); } +static void isp_parse_of_parallel_endpoint(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct isp_bus_cfg *buscfg) +{ + buscfg->interface = ISP_INTERFACE_PARALLEL; + buscfg->bus.parallel.data_lane_shift = vep->bus.parallel.data_shift; + buscfg->bus.parallel.clk_pol = + !!(vep->bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING); + buscfg->bus.parallel.hs_pol = + !!(vep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW); + buscfg->bus.parallel.vs_pol = + !!(vep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW); + buscfg->bus.parallel.fld_pol = + !!(vep->bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW); + buscfg->bus.parallel.data_pol = + !!(vep->bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW); + buscfg->bus.parallel.bt656 = vep->bus_type == V4L2_MBUS_BT656; +} + +static void isp_parse_of_csi2_endpoint(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct isp_bus_cfg *buscfg) +{ + unsigned int i; + + buscfg->bus.csi2.lanecfg.clk.pos = vep->bus.mipi_csi2.clock_lane; + buscfg->bus.csi2.lanecfg.clk.pol = + vep->bus.mipi_csi2.lane_polarities[0]; + dev_dbg(dev, "clock lane polarity %u, pos %u\n", + buscfg->bus.csi2.lanecfg.clk.pol, + buscfg->bus.csi2.lanecfg.clk.pos); + + buscfg->bus.csi2.num_data_lanes = vep->bus.mipi_csi2.num_data_lanes; + + for (i = 0; i < buscfg->bus.csi2.num_data_lanes; i++) { + buscfg->bus.csi2.lanecfg.data[i].pos = + vep->bus.mipi_csi2.data_lanes[i]; + buscfg->bus.csi2.lanecfg.data[i].pol = + vep->bus.mipi_csi2.lane_polarities[i + 1]; + dev_dbg(dev, + "data lane %u polarity %u, pos %u\n", i, + buscfg->bus.csi2.lanecfg.data[i].pol, + buscfg->bus.csi2.lanecfg.data[i].pos); + } + /* + * FIXME: now we assume the CRC is always there. Implement a way to + * obtain this information from the sensor. Frame descriptors, perhaps? + */ + buscfg->bus.csi2.crc = 1; +} + +static void isp_parse_of_csi1_endpoint(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct isp_bus_cfg *buscfg) +{ + buscfg->bus.ccp2.lanecfg.clk.pos = vep->bus.mipi_csi1.clock_lane; + buscfg->bus.ccp2.lanecfg.clk.pol = vep->bus.mipi_csi1.lane_polarity[0]; + dev_dbg(dev, "clock lane polarity %u, pos %u\n", + buscfg->bus.ccp2.lanecfg.clk.pol, + buscfg->bus.ccp2.lanecfg.clk.pos); + + buscfg->bus.ccp2.lanecfg.data[0].pos = vep->bus.mipi_csi1.data_lane; + buscfg->bus.ccp2.lanecfg.data[0].pol = + vep->bus.mipi_csi1.lane_polarity[1]; + + dev_dbg(dev, "data lane polarity %u, pos %u\n", + buscfg->bus.ccp2.lanecfg.data[0].pol, + buscfg->bus.ccp2.lanecfg.data[0].pos); + + buscfg->bus.ccp2.strobe_clk_pol = vep->bus.mipi_csi1.clock_inv; + buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe; + buscfg->bus.ccp2.ccp2_mode = vep->bus_type == V4L2_MBUS_CCP2; + buscfg->bus.ccp2.vp_clk_pol = 1; + + buscfg->bus.ccp2.crc = 1; +} + +static int isp_alloc_isd(struct isp_async_subdev **isd, + struct isp_bus_cfg **buscfg) +{ + struct isp_async_subdev *__isd; + + __isd = kzalloc(sizeof(*__isd), GFP_KERNEL); + if (!__isd) + return -ENOMEM; + + *isd = __isd; + *buscfg = &__isd->bus; + + return 0; +} + +static struct { + u32 phy; + u32 csi2_if; + u32 csi1_if; +} isp_bus_interfaces[2] = { + { ISP_OF_PHY_CSIPHY1, + ISP_INTERFACE_CSI2C_PHY1, ISP_INTERFACE_CCP2B_PHY1 }, + { ISP_OF_PHY_CSIPHY2, + ISP_INTERFACE_CSI2A_PHY2, ISP_INTERFACE_CCP2B_PHY2 }, +}; + +static int isp_parse_of_endpoints(struct isp_device *isp) +{ + struct fwnode_handle *ep; + struct isp_async_subdev *isd = NULL; + struct isp_bus_cfg *buscfg; + unsigned int i; + + ep = fwnode_graph_get_endpoint_by_id( + dev_fwnode(isp->dev), ISP_OF_PHY_PARALLEL, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + + if (ep) { + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_PARALLEL + }; + int ret; + + dev_dbg(isp->dev, "parsing parallel interface\n"); + + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + + if (!ret) { + ret = isp_alloc_isd(&isd, &buscfg); + if (ret) + return ret; + } + + if (!ret) { + isp_parse_of_parallel_endpoint(isp->dev, &vep, buscfg); + ret = v4l2_async_notifier_add_fwnode_remote_subdev( + &isp->notifier, ep, &isd->asd); + } + + fwnode_handle_put(ep); + if (ret) + kfree(isd); + } + + for (i = 0; i < ARRAY_SIZE(isp_bus_interfaces); i++) { + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + int ret; + + ep = fwnode_graph_get_endpoint_by_id( + dev_fwnode(isp->dev), isp_bus_interfaces[i].phy, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + + if (!ep) + continue; + + dev_dbg(isp->dev, "parsing serial interface %u, node %pOF\n", i, + to_of_node(ep)); + + ret = isp_alloc_isd(&isd, &buscfg); + if (ret) + return ret; + + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + if (!ret) { + buscfg->interface = isp_bus_interfaces[i].csi2_if; + isp_parse_of_csi2_endpoint(isp->dev, &vep, buscfg); + } else if (ret == -ENXIO) { + vep = (struct v4l2_fwnode_endpoint) + { .bus_type = V4L2_MBUS_CSI1 }; + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + + if (ret == -ENXIO) { + vep = (struct v4l2_fwnode_endpoint) + { .bus_type = V4L2_MBUS_CCP2 }; + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + } + if (!ret) { + buscfg->interface = + isp_bus_interfaces[i].csi1_if; + isp_parse_of_csi1_endpoint(isp->dev, &vep, + buscfg); + } + } + + if (!ret) + ret = v4l2_async_notifier_add_fwnode_remote_subdev( + &isp->notifier, ep, &isd->asd); + + fwnode_handle_put(ep); + if (ret) + kfree(isd); + } + + return 0; +} + static const struct v4l2_async_notifier_operations isp_subdev_notifier_ops = { .complete = isp_subdev_notifier_complete, }; @@ -2223,14 +2296,12 @@ static int isp_probe(struct platform_device *pdev) mutex_init(&isp->isp_mutex); spin_lock_init(&isp->stat_lock); v4l2_async_notifier_init(&isp->notifier); + isp->dev = &pdev->dev; - ret = v4l2_async_notifier_parse_fwnode_endpoints( - &pdev->dev, &isp->notifier, sizeof(struct isp_async_subdev), - isp_fwnode_parse); + ret = isp_parse_of_endpoints(isp); if (ret < 0) goto error; - isp->dev = &pdev->dev; isp->ref_count = 0; ret = dma_coerce_mask_and_coherent(isp->dev, DMA_BIT_MASK(32)); @@ -2324,7 +2395,6 @@ static int isp_probe(struct platform_device *pdev) /* Interrupt */ ret = platform_get_irq(pdev, 0); if (ret <= 0) { - dev_err(isp->dev, "No IRQ resource\n"); ret = -ENODEV; goto error_iommu; } diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 1ba8a5ba343f..e2f336c715a4 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -2602,6 +2602,7 @@ int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, int ret; /* Register the subdev and video node. */ + ccdc->subdev.dev = vdev->mdev->dev; ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); if (ret < 0) goto error; diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index efca45bb02c8..d0a49cdfd22d 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -1031,6 +1031,7 @@ int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, int ret; /* Register the subdev and video nodes. */ + ccp2->subdev.dev = vdev->mdev->dev; ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); if (ret < 0) goto error; diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index e85917f4a50c..fd493c5e4e24 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -1198,6 +1198,7 @@ int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, int ret; /* Register the subdev and video nodes. */ + csi2->subdev.dev = vdev->mdev->dev; ret = v4l2_device_register_subdev(vdev, &csi2->subdev); if (ret < 0) goto error; diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 40e22400cf5e..97d660606d98 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -2225,6 +2225,7 @@ int omap3isp_preview_register_entities(struct isp_prev_device *prev, int ret; /* Register the subdev and video nodes. */ + prev->subdev.dev = vdev->mdev->dev; ret = v4l2_device_register_subdev(vdev, &prev->subdev); if (ret < 0) goto error; diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h index 38e2b99b3f10..86b6ebb0438d 100644 --- a/drivers/media/platform/omap3isp/ispreg.h +++ b/drivers/media/platform/omap3isp/ispreg.h @@ -45,7 +45,7 @@ #define ISPCCP2_REVISION (0x000) #define ISPCCP2_SYSCONFIG (0x004) -#define ISPCCP2_SYSCONFIG_SOFT_RESET (1 << 1) +#define ISPCCP2_SYSCONFIG_SOFT_RESET BIT(1) #define ISPCCP2_SYSCONFIG_AUTO_IDLE 0x1 #define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT 12 #define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_FORCE \ @@ -55,44 +55,44 @@ #define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART \ (0x2 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT) #define ISPCCP2_SYSSTATUS (0x008) -#define ISPCCP2_SYSSTATUS_RESET_DONE (1 << 0) +#define ISPCCP2_SYSSTATUS_RESET_DONE BIT(0) #define ISPCCP2_LC01_IRQENABLE (0x00C) #define ISPCCP2_LC01_IRQSTATUS (0x010) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ (1 << 11) -#define ISPCCP2_LC01_IRQSTATUS_LC0_LE_IRQ (1 << 10) -#define ISPCCP2_LC01_IRQSTATUS_LC0_LS_IRQ (1 << 9) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FE_IRQ (1 << 8) -#define ISPCCP2_LC01_IRQSTATUS_LC0_COUNT_IRQ (1 << 7) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ (1 << 5) -#define ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ (1 << 4) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ (1 << 3) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ (1 << 2) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ (1 << 1) -#define ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ (1 << 0) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ BIT(11) +#define ISPCCP2_LC01_IRQSTATUS_LC0_LE_IRQ BIT(10) +#define ISPCCP2_LC01_IRQSTATUS_LC0_LS_IRQ BIT(9) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FE_IRQ BIT(8) +#define ISPCCP2_LC01_IRQSTATUS_LC0_COUNT_IRQ BIT(7) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ BIT(5) +#define ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ BIT(4) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ BIT(3) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ BIT(2) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ BIT(1) +#define ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ BIT(0) #define ISPCCP2_LC23_IRQENABLE (0x014) #define ISPCCP2_LC23_IRQSTATUS (0x018) #define ISPCCP2_LCM_IRQENABLE (0x02C) -#define ISPCCP2_LCM_IRQSTATUS_EOF_IRQ (1 << 0) -#define ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ (1 << 1) +#define ISPCCP2_LCM_IRQSTATUS_EOF_IRQ BIT(0) +#define ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ BIT(1) #define ISPCCP2_LCM_IRQSTATUS (0x030) #define ISPCCP2_CTRL (0x040) -#define ISPCCP2_CTRL_IF_EN (1 << 0) -#define ISPCCP2_CTRL_PHY_SEL (1 << 1) +#define ISPCCP2_CTRL_IF_EN BIT(0) +#define ISPCCP2_CTRL_PHY_SEL BIT(1) #define ISPCCP2_CTRL_PHY_SEL_CLOCK (0 << 1) #define ISPCCP2_CTRL_PHY_SEL_STROBE (1 << 1) #define ISPCCP2_CTRL_PHY_SEL_MASK 0x1 #define ISPCCP2_CTRL_PHY_SEL_SHIFT 1 -#define ISPCCP2_CTRL_IO_OUT_SEL (1 << 2) +#define ISPCCP2_CTRL_IO_OUT_SEL BIT(2) #define ISPCCP2_CTRL_IO_OUT_SEL_MASK 0x1 #define ISPCCP2_CTRL_IO_OUT_SEL_SHIFT 2 -#define ISPCCP2_CTRL_MODE (1 << 4) -#define ISPCCP2_CTRL_VP_CLK_FORCE_ON (1 << 9) -#define ISPCCP2_CTRL_INV (1 << 10) +#define ISPCCP2_CTRL_MODE BIT(4) +#define ISPCCP2_CTRL_VP_CLK_FORCE_ON BIT(9) +#define ISPCCP2_CTRL_INV BIT(10) #define ISPCCP2_CTRL_INV_MASK 0x1 #define ISPCCP2_CTRL_INV_SHIFT 10 -#define ISPCCP2_CTRL_VP_ONLY_EN (1 << 11) -#define ISPCCP2_CTRL_VP_CLK_POL (1 << 12) +#define ISPCCP2_CTRL_VP_ONLY_EN BIT(11) +#define ISPCCP2_CTRL_VP_CLK_POL BIT(12) #define ISPCCP2_CTRL_VP_CLK_POL_MASK 0x1 #define ISPCCP2_CTRL_VP_CLK_POL_SHIFT 12 #define ISPCCP2_CTRL_VPCLK_DIV_SHIFT 15 @@ -102,12 +102,12 @@ #define ISPCCP2_DBG (0x044) #define ISPCCP2_GNQ (0x048) #define ISPCCP2_LCx_CTRL(x) ((0x050)+0x30*(x)) -#define ISPCCP2_LCx_CTRL_CHAN_EN (1 << 0) -#define ISPCCP2_LCx_CTRL_CRC_EN (1 << 19) +#define ISPCCP2_LCx_CTRL_CHAN_EN BIT(0) +#define ISPCCP2_LCx_CTRL_CRC_EN BIT(19) #define ISPCCP2_LCx_CTRL_CRC_MASK 0x1 #define ISPCCP2_LCx_CTRL_CRC_SHIFT 2 #define ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0 19 -#define ISPCCP2_LCx_CTRL_REGION_EN (1 << 1) +#define ISPCCP2_LCx_CTRL_REGION_EN BIT(1) #define ISPCCP2_LCx_CTRL_REGION_MASK 0x1 #define ISPCCP2_LCx_CTRL_REGION_SHIFT 1 #define ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0 0x3f @@ -127,8 +127,8 @@ #define ISPCCP2_LCx_DAT_PONG_ADDR(x) ((0x074)+0x30*(x)) #define ISPCCP2_LCx_DAT_OFST(x) ((0x078)+0x30*(x)) #define ISPCCP2_LCM_CTRL (0x1D0) -#define ISPCCP2_LCM_CTRL_CHAN_EN (1 << 0) -#define ISPCCP2_LCM_CTRL_DST_PORT (1 << 2) +#define ISPCCP2_LCM_CTRL_CHAN_EN BIT(0) +#define ISPCCP2_LCM_CTRL_DST_PORT BIT(2) #define ISPCCP2_LCM_CTRL_DST_PORT_SHIFT 2 #define ISPCCP2_LCM_CTRL_READ_THROTTLE_SHIFT 3 #define ISPCCP2_LCM_CTRL_READ_THROTTLE_MASK 0x11 @@ -138,8 +138,8 @@ #define ISPCCP2_LCM_CTRL_SRC_FORMAT_MASK 0x7 #define ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT 20 #define ISPCCP2_LCM_CTRL_SRC_DECOMPR_MASK 0x3 -#define ISPCCP2_LCM_CTRL_SRC_DPCM_PRED (1 << 22) -#define ISPCCP2_LCM_CTRL_SRC_PACK (1 << 23) +#define ISPCCP2_LCM_CTRL_SRC_DPCM_PRED BIT(22) +#define ISPCCP2_LCM_CTRL_SRC_PACK BIT(23) #define ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT 24 #define ISPCCP2_LCM_CTRL_DST_FORMAT_MASK 0x7 #define ISPCCP2_LCM_VSIZE (0x1D4) @@ -201,19 +201,19 @@ /* SBL */ #define ISPSBL_PCR 0x4 -#define ISPSBL_PCR_H3A_AEAWB_WBL_OVF (1 << 16) -#define ISPSBL_PCR_H3A_AF_WBL_OVF (1 << 17) -#define ISPSBL_PCR_RSZ4_WBL_OVF (1 << 18) -#define ISPSBL_PCR_RSZ3_WBL_OVF (1 << 19) -#define ISPSBL_PCR_RSZ2_WBL_OVF (1 << 20) -#define ISPSBL_PCR_RSZ1_WBL_OVF (1 << 21) -#define ISPSBL_PCR_PRV_WBL_OVF (1 << 22) -#define ISPSBL_PCR_CCDC_WBL_OVF (1 << 23) -#define ISPSBL_PCR_CCDCPRV_2_RSZ_OVF (1 << 24) -#define ISPSBL_PCR_CSIA_WBL_OVF (1 << 25) -#define ISPSBL_PCR_CSIB_WBL_OVF (1 << 26) +#define ISPSBL_PCR_H3A_AEAWB_WBL_OVF BIT(16) +#define ISPSBL_PCR_H3A_AF_WBL_OVF BIT(17) +#define ISPSBL_PCR_RSZ4_WBL_OVF BIT(18) +#define ISPSBL_PCR_RSZ3_WBL_OVF BIT(19) +#define ISPSBL_PCR_RSZ2_WBL_OVF BIT(20) +#define ISPSBL_PCR_RSZ1_WBL_OVF BIT(21) +#define ISPSBL_PCR_PRV_WBL_OVF BIT(22) +#define ISPSBL_PCR_CCDC_WBL_OVF BIT(23) +#define ISPSBL_PCR_CCDCPRV_2_RSZ_OVF BIT(24) +#define ISPSBL_PCR_CSIA_WBL_OVF BIT(25) +#define ISPSBL_PCR_CSIB_WBL_OVF BIT(26) #define ISPSBL_CCDC_WR_0 (0x028) -#define ISPSBL_CCDC_WR_0_DATA_READY (1 << 21) +#define ISPSBL_CCDC_WR_0_DATA_READY BIT(21) #define ISPSBL_CCDC_WR_1 (0x02C) #define ISPSBL_CCDC_WR_2 (0x030) #define ISPSBL_CCDC_WR_3 (0x034) @@ -366,16 +366,16 @@ #define ISP_INT_CLR 0xFF113F11 #define ISPPRV_PCR_EN 1 -#define ISPPRV_PCR_BUSY (1 << 1) -#define ISPPRV_PCR_SOURCE (1 << 2) -#define ISPPRV_PCR_ONESHOT (1 << 3) -#define ISPPRV_PCR_WIDTH (1 << 4) -#define ISPPRV_PCR_INVALAW (1 << 5) -#define ISPPRV_PCR_DRKFEN (1 << 6) -#define ISPPRV_PCR_DRKFCAP (1 << 7) -#define ISPPRV_PCR_HMEDEN (1 << 8) -#define ISPPRV_PCR_NFEN (1 << 9) -#define ISPPRV_PCR_CFAEN (1 << 10) +#define ISPPRV_PCR_BUSY BIT(1) +#define ISPPRV_PCR_SOURCE BIT(2) +#define ISPPRV_PCR_ONESHOT BIT(3) +#define ISPPRV_PCR_WIDTH BIT(4) +#define ISPPRV_PCR_INVALAW BIT(5) +#define ISPPRV_PCR_DRKFEN BIT(6) +#define ISPPRV_PCR_DRKFCAP BIT(7) +#define ISPPRV_PCR_HMEDEN BIT(8) +#define ISPPRV_PCR_NFEN BIT(9) +#define ISPPRV_PCR_CFAEN BIT(10) #define ISPPRV_PCR_CFAFMT_SHIFT 11 #define ISPPRV_PCR_CFAFMT_MASK 0x7800 #define ISPPRV_PCR_CFAFMT_BAYER (0 << 11) @@ -384,22 +384,22 @@ #define ISPPRV_PCR_CFAFMT_DNSPL (3 << 11) #define ISPPRV_PCR_CFAFMT_HONEYCOMB (4 << 11) #define ISPPRV_PCR_CFAFMT_RRGGBBFOVEON (5 << 11) -#define ISPPRV_PCR_YNENHEN (1 << 15) -#define ISPPRV_PCR_SUPEN (1 << 16) +#define ISPPRV_PCR_YNENHEN BIT(15) +#define ISPPRV_PCR_SUPEN BIT(16) #define ISPPRV_PCR_YCPOS_SHIFT 17 #define ISPPRV_PCR_YCPOS_YCrYCb (0 << 17) #define ISPPRV_PCR_YCPOS_YCbYCr (1 << 17) #define ISPPRV_PCR_YCPOS_CbYCrY (2 << 17) #define ISPPRV_PCR_YCPOS_CrYCbY (3 << 17) -#define ISPPRV_PCR_RSZPORT (1 << 19) -#define ISPPRV_PCR_SDRPORT (1 << 20) -#define ISPPRV_PCR_SCOMP_EN (1 << 21) +#define ISPPRV_PCR_RSZPORT BIT(19) +#define ISPPRV_PCR_SDRPORT BIT(20) +#define ISPPRV_PCR_SCOMP_EN BIT(21) #define ISPPRV_PCR_SCOMP_SFT_SHIFT (22) #define ISPPRV_PCR_SCOMP_SFT_MASK (7 << 22) -#define ISPPRV_PCR_GAMMA_BYPASS (1 << 26) -#define ISPPRV_PCR_DCOREN (1 << 27) -#define ISPPRV_PCR_DCCOUP (1 << 28) -#define ISPPRV_PCR_DRK_FAIL (1 << 31) +#define ISPPRV_PCR_GAMMA_BYPASS BIT(26) +#define ISPPRV_PCR_DCOREN BIT(27) +#define ISPPRV_PCR_DCCOUP BIT(28) +#define ISPPRV_PCR_DRK_FAIL BIT(31) #define ISPPRV_HORZ_INFO_EPH_SHIFT 0 #define ISPPRV_HORZ_INFO_EPH_MASK 0x3fff @@ -423,8 +423,8 @@ #define ISPPRV_AVE_ODDDIST_4 0x3 #define ISPPRV_HMED_THRESHOLD_SHIFT 0 -#define ISPPRV_HMED_EVENDIST (1 << 8) -#define ISPPRV_HMED_ODDDIST (1 << 9) +#define ISPPRV_HMED_EVENDIST BIT(8) +#define ISPPRV_HMED_ODDDIST BIT(9) #define ISPPRV_WBGAIN_COEF0_SHIFT 0 #define ISPPRV_WBGAIN_COEF1_SHIFT 8 @@ -517,8 +517,8 @@ /* Define bit fields within selected registers */ #define ISP_REVISION_SHIFT 0 -#define ISP_SYSCONFIG_AUTOIDLE (1 << 0) -#define ISP_SYSCONFIG_SOFTRESET (1 << 1) +#define ISP_SYSCONFIG_AUTOIDLE BIT(0) +#define ISP_SYSCONFIG_SOFTRESET BIT(1) #define ISP_SYSCONFIG_MIDLEMODE_SHIFT 12 #define ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY 0x0 #define ISP_SYSCONFIG_MIDLEMODE_NOSTANBY 0x1 @@ -526,68 +526,68 @@ #define ISP_SYSSTATUS_RESETDONE 0 -#define IRQ0ENABLE_CSIA_IRQ (1 << 0) -#define IRQ0ENABLE_CSIC_IRQ (1 << 1) -#define IRQ0ENABLE_CCP2_LCM_IRQ (1 << 3) -#define IRQ0ENABLE_CCP2_LC0_IRQ (1 << 4) -#define IRQ0ENABLE_CCP2_LC1_IRQ (1 << 5) -#define IRQ0ENABLE_CCP2_LC2_IRQ (1 << 6) -#define IRQ0ENABLE_CCP2_LC3_IRQ (1 << 7) +#define IRQ0ENABLE_CSIA_IRQ BIT(0) +#define IRQ0ENABLE_CSIC_IRQ BIT(1) +#define IRQ0ENABLE_CCP2_LCM_IRQ BIT(3) +#define IRQ0ENABLE_CCP2_LC0_IRQ BIT(4) +#define IRQ0ENABLE_CCP2_LC1_IRQ BIT(5) +#define IRQ0ENABLE_CCP2_LC2_IRQ BIT(6) +#define IRQ0ENABLE_CCP2_LC3_IRQ BIT(7) #define IRQ0ENABLE_CSIB_IRQ (IRQ0ENABLE_CCP2_LCM_IRQ | \ IRQ0ENABLE_CCP2_LC0_IRQ | \ IRQ0ENABLE_CCP2_LC1_IRQ | \ IRQ0ENABLE_CCP2_LC2_IRQ | \ IRQ0ENABLE_CCP2_LC3_IRQ) -#define IRQ0ENABLE_CCDC_VD0_IRQ (1 << 8) -#define IRQ0ENABLE_CCDC_VD1_IRQ (1 << 9) -#define IRQ0ENABLE_CCDC_VD2_IRQ (1 << 10) -#define IRQ0ENABLE_CCDC_ERR_IRQ (1 << 11) -#define IRQ0ENABLE_H3A_AF_DONE_IRQ (1 << 12) -#define IRQ0ENABLE_H3A_AWB_DONE_IRQ (1 << 13) -#define IRQ0ENABLE_HIST_DONE_IRQ (1 << 16) -#define IRQ0ENABLE_CCDC_LSC_DONE_IRQ (1 << 17) -#define IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ (1 << 18) -#define IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ (1 << 19) -#define IRQ0ENABLE_PRV_DONE_IRQ (1 << 20) -#define IRQ0ENABLE_RSZ_DONE_IRQ (1 << 24) -#define IRQ0ENABLE_OVF_IRQ (1 << 25) -#define IRQ0ENABLE_PING_IRQ (1 << 26) -#define IRQ0ENABLE_PONG_IRQ (1 << 27) -#define IRQ0ENABLE_MMU_ERR_IRQ (1 << 28) -#define IRQ0ENABLE_OCP_ERR_IRQ (1 << 29) -#define IRQ0ENABLE_SEC_ERR_IRQ (1 << 30) -#define IRQ0ENABLE_HS_VS_IRQ (1 << 31) - -#define IRQ0STATUS_CSIA_IRQ (1 << 0) -#define IRQ0STATUS_CSI2C_IRQ (1 << 1) -#define IRQ0STATUS_CCP2_LCM_IRQ (1 << 3) -#define IRQ0STATUS_CCP2_LC0_IRQ (1 << 4) +#define IRQ0ENABLE_CCDC_VD0_IRQ BIT(8) +#define IRQ0ENABLE_CCDC_VD1_IRQ BIT(9) +#define IRQ0ENABLE_CCDC_VD2_IRQ BIT(10) +#define IRQ0ENABLE_CCDC_ERR_IRQ BIT(11) +#define IRQ0ENABLE_H3A_AF_DONE_IRQ BIT(12) +#define IRQ0ENABLE_H3A_AWB_DONE_IRQ BIT(13) +#define IRQ0ENABLE_HIST_DONE_IRQ BIT(16) +#define IRQ0ENABLE_CCDC_LSC_DONE_IRQ BIT(17) +#define IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ BIT(18) +#define IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ BIT(19) +#define IRQ0ENABLE_PRV_DONE_IRQ BIT(20) +#define IRQ0ENABLE_RSZ_DONE_IRQ BIT(24) +#define IRQ0ENABLE_OVF_IRQ BIT(25) +#define IRQ0ENABLE_PING_IRQ BIT(26) +#define IRQ0ENABLE_PONG_IRQ BIT(27) +#define IRQ0ENABLE_MMU_ERR_IRQ BIT(28) +#define IRQ0ENABLE_OCP_ERR_IRQ BIT(29) +#define IRQ0ENABLE_SEC_ERR_IRQ BIT(30) +#define IRQ0ENABLE_HS_VS_IRQ BIT(31) + +#define IRQ0STATUS_CSIA_IRQ BIT(0) +#define IRQ0STATUS_CSI2C_IRQ BIT(1) +#define IRQ0STATUS_CCP2_LCM_IRQ BIT(3) +#define IRQ0STATUS_CCP2_LC0_IRQ BIT(4) #define IRQ0STATUS_CSIB_IRQ (IRQ0STATUS_CCP2_LCM_IRQ | \ IRQ0STATUS_CCP2_LC0_IRQ) -#define IRQ0STATUS_CSIB_LC1_IRQ (1 << 5) -#define IRQ0STATUS_CSIB_LC2_IRQ (1 << 6) -#define IRQ0STATUS_CSIB_LC3_IRQ (1 << 7) -#define IRQ0STATUS_CCDC_VD0_IRQ (1 << 8) -#define IRQ0STATUS_CCDC_VD1_IRQ (1 << 9) -#define IRQ0STATUS_CCDC_VD2_IRQ (1 << 10) -#define IRQ0STATUS_CCDC_ERR_IRQ (1 << 11) -#define IRQ0STATUS_H3A_AF_DONE_IRQ (1 << 12) -#define IRQ0STATUS_H3A_AWB_DONE_IRQ (1 << 13) -#define IRQ0STATUS_HIST_DONE_IRQ (1 << 16) -#define IRQ0STATUS_CCDC_LSC_DONE_IRQ (1 << 17) -#define IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ (1 << 18) -#define IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ (1 << 19) -#define IRQ0STATUS_PRV_DONE_IRQ (1 << 20) -#define IRQ0STATUS_RSZ_DONE_IRQ (1 << 24) -#define IRQ0STATUS_OVF_IRQ (1 << 25) -#define IRQ0STATUS_PING_IRQ (1 << 26) -#define IRQ0STATUS_PONG_IRQ (1 << 27) -#define IRQ0STATUS_MMU_ERR_IRQ (1 << 28) -#define IRQ0STATUS_OCP_ERR_IRQ (1 << 29) -#define IRQ0STATUS_SEC_ERR_IRQ (1 << 30) -#define IRQ0STATUS_HS_VS_IRQ (1 << 31) +#define IRQ0STATUS_CSIB_LC1_IRQ BIT(5) +#define IRQ0STATUS_CSIB_LC2_IRQ BIT(6) +#define IRQ0STATUS_CSIB_LC3_IRQ BIT(7) +#define IRQ0STATUS_CCDC_VD0_IRQ BIT(8) +#define IRQ0STATUS_CCDC_VD1_IRQ BIT(9) +#define IRQ0STATUS_CCDC_VD2_IRQ BIT(10) +#define IRQ0STATUS_CCDC_ERR_IRQ BIT(11) +#define IRQ0STATUS_H3A_AF_DONE_IRQ BIT(12) +#define IRQ0STATUS_H3A_AWB_DONE_IRQ BIT(13) +#define IRQ0STATUS_HIST_DONE_IRQ BIT(16) +#define IRQ0STATUS_CCDC_LSC_DONE_IRQ BIT(17) +#define IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ BIT(18) +#define IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ BIT(19) +#define IRQ0STATUS_PRV_DONE_IRQ BIT(20) +#define IRQ0STATUS_RSZ_DONE_IRQ BIT(24) +#define IRQ0STATUS_OVF_IRQ BIT(25) +#define IRQ0STATUS_PING_IRQ BIT(26) +#define IRQ0STATUS_PONG_IRQ BIT(27) +#define IRQ0STATUS_MMU_ERR_IRQ BIT(28) +#define IRQ0STATUS_OCP_ERR_IRQ BIT(29) +#define IRQ0STATUS_SEC_ERR_IRQ BIT(30) +#define IRQ0STATUS_HS_VS_IRQ BIT(31) #define TCTRL_GRESET_LEN 0 @@ -607,20 +607,20 @@ #define ISPCTRL_PAR_BRIDGE_MASK (0x3 << 2) #define ISPCTRL_PAR_CLK_POL_SHIFT 4 -#define ISPCTRL_PAR_CLK_POL_INV (1 << 4) -#define ISPCTRL_PING_PONG_EN (1 << 5) +#define ISPCTRL_PAR_CLK_POL_INV BIT(4) +#define ISPCTRL_PING_PONG_EN BIT(5) #define ISPCTRL_SHIFT_SHIFT 6 #define ISPCTRL_SHIFT_0 (0x0 << 6) #define ISPCTRL_SHIFT_2 (0x1 << 6) #define ISPCTRL_SHIFT_4 (0x2 << 6) #define ISPCTRL_SHIFT_MASK (0x3 << 6) -#define ISPCTRL_CCDC_CLK_EN (1 << 8) -#define ISPCTRL_SCMP_CLK_EN (1 << 9) -#define ISPCTRL_H3A_CLK_EN (1 << 10) -#define ISPCTRL_HIST_CLK_EN (1 << 11) -#define ISPCTRL_PREV_CLK_EN (1 << 12) -#define ISPCTRL_RSZ_CLK_EN (1 << 13) +#define ISPCTRL_CCDC_CLK_EN BIT(8) +#define ISPCTRL_SCMP_CLK_EN BIT(9) +#define ISPCTRL_H3A_CLK_EN BIT(10) +#define ISPCTRL_HIST_CLK_EN BIT(11) +#define ISPCTRL_PREV_CLK_EN BIT(12) +#define ISPCTRL_RSZ_CLK_EN BIT(13) #define ISPCTRL_SYNC_DETECT_SHIFT 14 #define ISPCTRL_SYNC_DETECT_HSFALL (0x0 << ISPCTRL_SYNC_DETECT_SHIFT) #define ISPCTRL_SYNC_DETECT_HSRISE (0x1 << ISPCTRL_SYNC_DETECT_SHIFT) @@ -628,17 +628,17 @@ #define ISPCTRL_SYNC_DETECT_VSRISE (0x3 << ISPCTRL_SYNC_DETECT_SHIFT) #define ISPCTRL_SYNC_DETECT_MASK (0x3 << ISPCTRL_SYNC_DETECT_SHIFT) -#define ISPCTRL_CCDC_RAM_EN (1 << 16) -#define ISPCTRL_PREV_RAM_EN (1 << 17) -#define ISPCTRL_SBL_RD_RAM_EN (1 << 18) -#define ISPCTRL_SBL_WR1_RAM_EN (1 << 19) -#define ISPCTRL_SBL_WR0_RAM_EN (1 << 20) -#define ISPCTRL_SBL_AUTOIDLE (1 << 21) -#define ISPCTRL_SBL_SHARED_WPORTC (1 << 26) -#define ISPCTRL_SBL_SHARED_RPORTA (1 << 27) -#define ISPCTRL_SBL_SHARED_RPORTB (1 << 28) -#define ISPCTRL_JPEG_FLUSH (1 << 30) -#define ISPCTRL_CCDC_FLUSH (1 << 31) +#define ISPCTRL_CCDC_RAM_EN BIT(16) +#define ISPCTRL_PREV_RAM_EN BIT(17) +#define ISPCTRL_SBL_RD_RAM_EN BIT(18) +#define ISPCTRL_SBL_WR1_RAM_EN BIT(19) +#define ISPCTRL_SBL_WR0_RAM_EN BIT(20) +#define ISPCTRL_SBL_AUTOIDLE BIT(21) +#define ISPCTRL_SBL_SHARED_WPORTC BIT(26) +#define ISPCTRL_SBL_SHARED_RPORTA BIT(27) +#define ISPCTRL_SBL_SHARED_RPORTB BIT(28) +#define ISPCTRL_JPEG_FLUSH BIT(30) +#define ISPCTRL_CCDC_FLUSH BIT(31) #define ISPSECURE_SECUREMODE 0 @@ -655,20 +655,20 @@ #define ISPTCTRL_CTRL_DIVC_SHIFT 10 #define ISPTCTRL_CTRL_DIVC_NOCLOCK (0x0 << 10) -#define ISPTCTRL_CTRL_SHUTEN (1 << 21) -#define ISPTCTRL_CTRL_PSTRBEN (1 << 22) -#define ISPTCTRL_CTRL_STRBEN (1 << 23) -#define ISPTCTRL_CTRL_SHUTPOL (1 << 24) -#define ISPTCTRL_CTRL_STRBPSTRBPOL (1 << 26) +#define ISPTCTRL_CTRL_SHUTEN BIT(21) +#define ISPTCTRL_CTRL_PSTRBEN BIT(22) +#define ISPTCTRL_CTRL_STRBEN BIT(23) +#define ISPTCTRL_CTRL_SHUTPOL BIT(24) +#define ISPTCTRL_CTRL_STRBPSTRBPOL BIT(26) #define ISPTCTRL_CTRL_INSEL_SHIFT 27 #define ISPTCTRL_CTRL_INSEL_PARALLEL (0x0 << 27) #define ISPTCTRL_CTRL_INSEL_CSIA (0x1 << 27) #define ISPTCTRL_CTRL_INSEL_CSIB (0x2 << 27) -#define ISPTCTRL_CTRL_GRESETEn (1 << 29) -#define ISPTCTRL_CTRL_GRESETPOL (1 << 30) -#define ISPTCTRL_CTRL_GRESETDIR (1 << 31) +#define ISPTCTRL_CTRL_GRESETEn BIT(29) +#define ISPTCTRL_CTRL_GRESETPOL BIT(30) +#define ISPTCTRL_CTRL_GRESETDIR BIT(31) #define ISPTCTRL_FRAME_SHUT_SHIFT 0 #define ISPTCTRL_FRAME_PSTRB_SHIFT 6 @@ -679,33 +679,33 @@ #define ISPCCDC_PID_TID_SHIFT 16 #define ISPCCDC_PCR_EN 1 -#define ISPCCDC_PCR_BUSY (1 << 1) +#define ISPCCDC_PCR_BUSY BIT(1) #define ISPCCDC_SYN_MODE_VDHDOUT 0x1 -#define ISPCCDC_SYN_MODE_FLDOUT (1 << 1) -#define ISPCCDC_SYN_MODE_VDPOL (1 << 2) -#define ISPCCDC_SYN_MODE_HDPOL (1 << 3) -#define ISPCCDC_SYN_MODE_FLDPOL (1 << 4) -#define ISPCCDC_SYN_MODE_EXWEN (1 << 5) -#define ISPCCDC_SYN_MODE_DATAPOL (1 << 6) -#define ISPCCDC_SYN_MODE_FLDMODE (1 << 7) +#define ISPCCDC_SYN_MODE_FLDOUT BIT(1) +#define ISPCCDC_SYN_MODE_VDPOL BIT(2) +#define ISPCCDC_SYN_MODE_HDPOL BIT(3) +#define ISPCCDC_SYN_MODE_FLDPOL BIT(4) +#define ISPCCDC_SYN_MODE_EXWEN BIT(5) +#define ISPCCDC_SYN_MODE_DATAPOL BIT(6) +#define ISPCCDC_SYN_MODE_FLDMODE BIT(7) #define ISPCCDC_SYN_MODE_DATSIZ_MASK (0x7 << 8) #define ISPCCDC_SYN_MODE_DATSIZ_8_16 (0x0 << 8) #define ISPCCDC_SYN_MODE_DATSIZ_12 (0x4 << 8) #define ISPCCDC_SYN_MODE_DATSIZ_11 (0x5 << 8) #define ISPCCDC_SYN_MODE_DATSIZ_10 (0x6 << 8) #define ISPCCDC_SYN_MODE_DATSIZ_8 (0x7 << 8) -#define ISPCCDC_SYN_MODE_PACK8 (1 << 11) +#define ISPCCDC_SYN_MODE_PACK8 BIT(11) #define ISPCCDC_SYN_MODE_INPMOD_MASK (3 << 12) #define ISPCCDC_SYN_MODE_INPMOD_RAW (0 << 12) #define ISPCCDC_SYN_MODE_INPMOD_YCBCR16 (1 << 12) #define ISPCCDC_SYN_MODE_INPMOD_YCBCR8 (2 << 12) -#define ISPCCDC_SYN_MODE_LPF (1 << 14) -#define ISPCCDC_SYN_MODE_FLDSTAT (1 << 15) -#define ISPCCDC_SYN_MODE_VDHDEN (1 << 16) -#define ISPCCDC_SYN_MODE_WEN (1 << 17) -#define ISPCCDC_SYN_MODE_VP2SDR (1 << 18) -#define ISPCCDC_SYN_MODE_SDR2RSZ (1 << 19) +#define ISPCCDC_SYN_MODE_LPF BIT(14) +#define ISPCCDC_SYN_MODE_FLDSTAT BIT(15) +#define ISPCCDC_SYN_MODE_VDHDEN BIT(16) +#define ISPCCDC_SYN_MODE_WEN BIT(17) +#define ISPCCDC_SYN_MODE_VP2SDR BIT(18) +#define ISPCCDC_SYN_MODE_SDR2RSZ BIT(19) #define ISPCCDC_HD_VD_WID_VDW_SHIFT 0 #define ISPCCDC_HD_VD_WID_HDW_SHIFT 16 @@ -731,7 +731,7 @@ #define ISPCCDC_HSIZE_OFF_SHIFT 0 -#define ISPCCDC_SDOFST_FIINV (1 << 14) +#define ISPCCDC_SDOFST_FIINV BIT(14) #define ISPCCDC_SDOFST_FOFST_SHIFT 12 #define ISPCCDC_SDOFST_FOFST_MASK (3 << 12) #define ISPCCDC_SDOFST_LOFST3_SHIFT 0 @@ -743,7 +743,7 @@ #define ISPCCDC_CLAMP_OBST_SHIFT 10 #define ISPCCDC_CLAMP_OBSLN_SHIFT 25 #define ISPCCDC_CLAMP_OBSLEN_SHIFT 28 -#define ISPCCDC_CLAMP_CLAMPEN (1 << 31) +#define ISPCCDC_CLAMP_CLAMPEN BIT(31) #define ISPCCDC_COLPTN_R_Ye 0x0 #define ISPCCDC_COLPTN_Gr_Cy 0x1 @@ -772,8 +772,8 @@ #define ISPCCDC_BLKCMP_R_YE_SHIFT 24 #define ISPCCDC_FPC_FPNUM_SHIFT 0 -#define ISPCCDC_FPC_FPCEN (1 << 15) -#define ISPCCDC_FPC_FPERR (1 << 16) +#define ISPCCDC_FPC_FPCEN BIT(15) +#define ISPCCDC_FPC_FPERR BIT(16) #define ISPCCDC_VDINT_1_SHIFT 0 #define ISPCCDC_VDINT_1_MASK 0x00007fff @@ -784,23 +784,23 @@ #define ISPCCDC_ALAW_GWDI_11_2 (0x4 << 0) #define ISPCCDC_ALAW_GWDI_10_1 (0x5 << 0) #define ISPCCDC_ALAW_GWDI_9_0 (0x6 << 0) -#define ISPCCDC_ALAW_CCDTBL (1 << 3) +#define ISPCCDC_ALAW_CCDTBL BIT(3) #define ISPCCDC_REC656IF_R656ON 1 -#define ISPCCDC_REC656IF_ECCFVH (1 << 1) +#define ISPCCDC_REC656IF_ECCFVH BIT(1) -#define ISPCCDC_CFG_BW656 (1 << 5) +#define ISPCCDC_CFG_BW656 BIT(5) #define ISPCCDC_CFG_FIDMD_SHIFT 6 -#define ISPCCDC_CFG_WENLOG (1 << 8) +#define ISPCCDC_CFG_WENLOG BIT(8) #define ISPCCDC_CFG_WENLOG_AND (0 << 8) #define ISPCCDC_CFG_WENLOG_OR (1 << 8) -#define ISPCCDC_CFG_Y8POS (1 << 11) -#define ISPCCDC_CFG_BSWD (1 << 12) -#define ISPCCDC_CFG_MSBINVI (1 << 13) -#define ISPCCDC_CFG_VDLC (1 << 15) +#define ISPCCDC_CFG_Y8POS BIT(11) +#define ISPCCDC_CFG_BSWD BIT(12) +#define ISPCCDC_CFG_MSBINVI BIT(13) +#define ISPCCDC_CFG_VDLC BIT(15) #define ISPCCDC_FMTCFG_FMTEN 0x1 -#define ISPCCDC_FMTCFG_LNALT (1 << 1) +#define ISPCCDC_FMTCFG_LNALT BIT(1) #define ISPCCDC_FMTCFG_LNUM_SHIFT 2 #define ISPCCDC_FMTCFG_PLEN_ODD_SHIFT 4 #define ISPCCDC_FMTCFG_PLEN_EVEN_SHIFT 8 @@ -809,7 +809,7 @@ #define ISPCCDC_FMTCFG_VPIN_11_2 (0x4 << 12) #define ISPCCDC_FMTCFG_VPIN_10_1 (0x5 << 12) #define ISPCCDC_FMTCFG_VPIN_9_0 (0x6 << 12) -#define ISPCCDC_FMTCFG_VPEN (1 << 15) +#define ISPCCDC_FMTCFG_VPEN BIT(15) #define ISPCCDC_FMTCFG_VPIF_FRQ_MASK 0x003f0000 #define ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT 16 @@ -839,9 +839,9 @@ #define ISPRSZ_PID_CID_SHIFT 8 #define ISPRSZ_PID_TID_SHIFT 16 -#define ISPRSZ_PCR_ENABLE (1 << 0) -#define ISPRSZ_PCR_BUSY (1 << 1) -#define ISPRSZ_PCR_ONESHOT (1 << 2) +#define ISPRSZ_PCR_ENABLE BIT(0) +#define ISPRSZ_PCR_BUSY BIT(1) +#define ISPRSZ_PCR_ONESHOT BIT(2) #define ISPRSZ_CNT_HRSZ_SHIFT 0 #define ISPRSZ_CNT_HRSZ_MASK \ @@ -853,10 +853,10 @@ #define ISPRSZ_CNT_HSTPH_MASK (0x7 << ISPRSZ_CNT_HSTPH_SHIFT) #define ISPRSZ_CNT_VSTPH_SHIFT 23 #define ISPRSZ_CNT_VSTPH_MASK (0x7 << ISPRSZ_CNT_VSTPH_SHIFT) -#define ISPRSZ_CNT_YCPOS (1 << 26) -#define ISPRSZ_CNT_INPTYP (1 << 27) -#define ISPRSZ_CNT_INPSRC (1 << 28) -#define ISPRSZ_CNT_CBILIN (1 << 29) +#define ISPRSZ_CNT_YCPOS BIT(26) +#define ISPRSZ_CNT_INPTYP BIT(27) +#define ISPRSZ_CNT_INPSRC BIT(28) +#define ISPRSZ_CNT_CBILIN BIT(29) #define ISPRSZ_OUT_SIZE_HORZ_SHIFT 0 #define ISPRSZ_OUT_SIZE_HORZ_MASK \ @@ -1081,8 +1081,8 @@ #define ISPH3A_PCR_AF_RGBPOS_SHIFT 11 #define ISPH3A_PCR_AEW_AVE2LMT_SHIFT 22 #define ISPH3A_PCR_AEW_AVE2LMT_MASK 0xFFC00000 -#define ISPH3A_PCR_BUSYAF (1 << 15) -#define ISPH3A_PCR_BUSYAEAWB (1 << 18) +#define ISPH3A_PCR_BUSYAF BIT(15) +#define ISPH3A_PCR_BUSYAEAWB BIT(18) #define ISPH3A_AEWWIN1_WINHC_SHIFT 0 #define ISPH3A_AEWWIN1_WINHC_MASK 0x3F @@ -1166,15 +1166,15 @@ #define ISPHIST_HV_INFO_MASK 0x3FFF3FFF -#define ISPCCDC_LSC_ENABLE 1 -#define ISPCCDC_LSC_BUSY (1 << 7) +#define ISPCCDC_LSC_ENABLE BIT(0) +#define ISPCCDC_LSC_BUSY BIT(7) #define ISPCCDC_LSC_GAIN_MODE_N_MASK 0x700 #define ISPCCDC_LSC_GAIN_MODE_N_SHIFT 8 #define ISPCCDC_LSC_GAIN_MODE_M_MASK 0x3800 #define ISPCCDC_LSC_GAIN_MODE_M_SHIFT 12 #define ISPCCDC_LSC_GAIN_FORMAT_MASK 0xE #define ISPCCDC_LSC_GAIN_FORMAT_SHIFT 1 -#define ISPCCDC_LSC_AFTER_REFORMATTER_MASK (1<<6) +#define ISPCCDC_LSC_AFTER_REFORMATTER_MASK BIT(6) #define ISPCCDC_LSC_INITIAL_X_MASK 0x3F #define ISPCCDC_LSC_INITIAL_X_SHIFT 0 @@ -1196,43 +1196,43 @@ (0x1 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT) #define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART \ (0x2 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT) -#define ISPCSI2_SYSCONFIG_SOFT_RESET (1 << 1) -#define ISPCSI2_SYSCONFIG_AUTO_IDLE (1 << 0) +#define ISPCSI2_SYSCONFIG_SOFT_RESET BIT(1) +#define ISPCSI2_SYSCONFIG_AUTO_IDLE BIT(0) #define ISPCSI2_SYSSTATUS (0x014) -#define ISPCSI2_SYSSTATUS_RESET_DONE (1 << 0) +#define ISPCSI2_SYSSTATUS_RESET_DONE BIT(0) #define ISPCSI2_IRQSTATUS (0x018) -#define ISPCSI2_IRQSTATUS_OCP_ERR_IRQ (1 << 14) -#define ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ (1 << 13) -#define ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ (1 << 12) -#define ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ (1 << 11) -#define ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ (1 << 10) -#define ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ (1 << 9) -#define ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ (1 << 8) -#define ISPCSI2_IRQSTATUS_CONTEXT(n) (1 << (n)) +#define ISPCSI2_IRQSTATUS_OCP_ERR_IRQ BIT(14) +#define ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ BIT(13) +#define ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ BIT(12) +#define ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ BIT(11) +#define ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ BIT(10) +#define ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ BIT(9) +#define ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ BIT(8) +#define ISPCSI2_IRQSTATUS_CONTEXT(n) BIT(n) #define ISPCSI2_IRQENABLE (0x01c) #define ISPCSI2_CTRL (0x040) -#define ISPCSI2_CTRL_VP_CLK_EN (1 << 15) -#define ISPCSI2_CTRL_VP_ONLY_EN (1 << 11) +#define ISPCSI2_CTRL_VP_CLK_EN BIT(15) +#define ISPCSI2_CTRL_VP_ONLY_EN BIT(11) #define ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT 8 #define ISPCSI2_CTRL_VP_OUT_CTRL_MASK \ (3 << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT) -#define ISPCSI2_CTRL_DBG_EN (1 << 7) +#define ISPCSI2_CTRL_DBG_EN BIT(7) #define ISPCSI2_CTRL_BURST_SIZE_SHIFT 5 #define ISPCSI2_CTRL_BURST_SIZE_MASK \ (3 << ISPCSI2_CTRL_BURST_SIZE_SHIFT) -#define ISPCSI2_CTRL_FRAME (1 << 3) -#define ISPCSI2_CTRL_ECC_EN (1 << 2) -#define ISPCSI2_CTRL_SECURE (1 << 1) -#define ISPCSI2_CTRL_IF_EN (1 << 0) +#define ISPCSI2_CTRL_FRAME BIT(3) +#define ISPCSI2_CTRL_ECC_EN BIT(2) +#define ISPCSI2_CTRL_SECURE BIT(1) +#define ISPCSI2_CTRL_IF_EN BIT(0) #define ISPCSI2_DBG_H (0x044) #define ISPCSI2_GNQ (0x048) #define ISPCSI2_PHY_CFG (0x050) -#define ISPCSI2_PHY_CFG_RESET_CTRL (1 << 30) -#define ISPCSI2_PHY_CFG_RESET_DONE (1 << 29) +#define ISPCSI2_PHY_CFG_RESET_CTRL BIT(30) +#define ISPCSI2_PHY_CFG_RESET_DONE BIT(29) #define ISPCSI2_PHY_CFG_PWR_CMD_SHIFT 27 #define ISPCSI2_PHY_CFG_PWR_CMD_MASK \ (0x3 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT) @@ -1251,7 +1251,7 @@ (0x1 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT) #define ISPCSI2_PHY_CFG_PWR_STATUS_ULPW \ (0x2 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT) -#define ISPCSI2_PHY_CFG_PWR_AUTO (1 << 24) +#define ISPCSI2_PHY_CFG_PWR_AUTO BIT(24) #define ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n) (3 + ((n) * 4)) #define ISPCSI2_PHY_CFG_DATA_POL_MASK(n) \ @@ -1300,63 +1300,63 @@ (0x5 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) #define ISPCSI2_PHY_IRQSTATUS (0x054) -#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMEXIT (1 << 26) -#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMENTER (1 << 25) -#define ISPCSI2_PHY_IRQSTATUS_STATEULPM5 (1 << 24) -#define ISPCSI2_PHY_IRQSTATUS_STATEULPM4 (1 << 23) -#define ISPCSI2_PHY_IRQSTATUS_STATEULPM3 (1 << 22) -#define ISPCSI2_PHY_IRQSTATUS_STATEULPM2 (1 << 21) -#define ISPCSI2_PHY_IRQSTATUS_STATEULPM1 (1 << 20) -#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL5 (1 << 19) -#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL4 (1 << 18) -#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL3 (1 << 17) -#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL2 (1 << 16) -#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL1 (1 << 15) -#define ISPCSI2_PHY_IRQSTATUS_ERRESC5 (1 << 14) -#define ISPCSI2_PHY_IRQSTATUS_ERRESC4 (1 << 13) -#define ISPCSI2_PHY_IRQSTATUS_ERRESC3 (1 << 12) -#define ISPCSI2_PHY_IRQSTATUS_ERRESC2 (1 << 11) -#define ISPCSI2_PHY_IRQSTATUS_ERRESC1 (1 << 10) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS5 (1 << 9) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS4 (1 << 8) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS3 (1 << 7) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS2 (1 << 6) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS1 (1 << 5) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS5 (1 << 4) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS4 (1 << 3) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS3 (1 << 2) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS2 (1 << 1) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS1 1 +#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMEXIT BIT(26) +#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMENTER BIT(25) +#define ISPCSI2_PHY_IRQSTATUS_STATEULPM5 BIT(24) +#define ISPCSI2_PHY_IRQSTATUS_STATEULPM4 BIT(23) +#define ISPCSI2_PHY_IRQSTATUS_STATEULPM3 BIT(22) +#define ISPCSI2_PHY_IRQSTATUS_STATEULPM2 BIT(21) +#define ISPCSI2_PHY_IRQSTATUS_STATEULPM1 BIT(20) +#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL5 BIT(19) +#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL4 BIT(18) +#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL3 BIT(17) +#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL2 BIT(16) +#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL1 BIT(15) +#define ISPCSI2_PHY_IRQSTATUS_ERRESC5 BIT(14) +#define ISPCSI2_PHY_IRQSTATUS_ERRESC4 BIT(13) +#define ISPCSI2_PHY_IRQSTATUS_ERRESC3 BIT(12) +#define ISPCSI2_PHY_IRQSTATUS_ERRESC2 BIT(11) +#define ISPCSI2_PHY_IRQSTATUS_ERRESC1 BIT(10) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS5 BIT(9) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS4 BIT(8) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS3 BIT(7) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS2 BIT(6) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS1 BIT(5) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS5 BIT(4) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS4 BIT(3) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS3 BIT(2) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS2 BIT(1) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS1 BIT(0) #define ISPCSI2_SHORT_PACKET (0x05c) #define ISPCSI2_PHY_IRQENABLE (0x060) -#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT (1 << 26) -#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER (1 << 25) -#define ISPCSI2_PHY_IRQENABLE_STATEULPM5 (1 << 24) -#define ISPCSI2_PHY_IRQENABLE_STATEULPM4 (1 << 23) -#define ISPCSI2_PHY_IRQENABLE_STATEULPM3 (1 << 22) -#define ISPCSI2_PHY_IRQENABLE_STATEULPM2 (1 << 21) -#define ISPCSI2_PHY_IRQENABLE_STATEULPM1 (1 << 20) -#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 (1 << 19) -#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 (1 << 18) -#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 (1 << 17) -#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 (1 << 16) -#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 (1 << 15) -#define ISPCSI2_PHY_IRQENABLE_ERRESC5 (1 << 14) -#define ISPCSI2_PHY_IRQENABLE_ERRESC4 (1 << 13) -#define ISPCSI2_PHY_IRQENABLE_ERRESC3 (1 << 12) -#define ISPCSI2_PHY_IRQENABLE_ERRESC2 (1 << 11) -#define ISPCSI2_PHY_IRQENABLE_ERRESC1 (1 << 10) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 (1 << 9) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 (1 << 8) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 (1 << 7) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 (1 << 6) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 (1 << 5) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 (1 << 4) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 (1 << 3) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 (1 << 2) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 (1 << 1) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS1 (1 << 0) +#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT BIT(26) +#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER BIT(25) +#define ISPCSI2_PHY_IRQENABLE_STATEULPM5 BIT(24) +#define ISPCSI2_PHY_IRQENABLE_STATEULPM4 BIT(23) +#define ISPCSI2_PHY_IRQENABLE_STATEULPM3 BIT(22) +#define ISPCSI2_PHY_IRQENABLE_STATEULPM2 BIT(21) +#define ISPCSI2_PHY_IRQENABLE_STATEULPM1 BIT(20) +#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 BIT(19) +#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 BIT(18) +#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 BIT(17) +#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 BIT(16) +#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 BIT(15) +#define ISPCSI2_PHY_IRQENABLE_ERRESC5 BIT(14) +#define ISPCSI2_PHY_IRQENABLE_ERRESC4 BIT(13) +#define ISPCSI2_PHY_IRQENABLE_ERRESC3 BIT(12) +#define ISPCSI2_PHY_IRQENABLE_ERRESC2 BIT(11) +#define ISPCSI2_PHY_IRQENABLE_ERRESC1 BIT(10) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 BIT(9) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 BIT(8) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 BIT(7) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 BIT(6) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 BIT(5) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 BIT(4) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 BIT(3) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 BIT(2) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 BIT(1) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS1 BIT(0) #define ISPCSI2_DBG_P (0x068) #define ISPCSI2_TIMING (0x06c) @@ -1371,12 +1371,12 @@ #define ISPCSI2_CTX_CTRL1_COUNT_SHIFT 8 #define ISPCSI2_CTX_CTRL1_COUNT_MASK \ (0xff << ISPCSI2_CTX_CTRL1_COUNT_SHIFT) -#define ISPCSI2_CTX_CTRL1_EOF_EN (1 << 7) -#define ISPCSI2_CTX_CTRL1_EOL_EN (1 << 6) -#define ISPCSI2_CTX_CTRL1_CS_EN (1 << 5) -#define ISPCSI2_CTX_CTRL1_COUNT_UNLOCK (1 << 4) -#define ISPCSI2_CTX_CTRL1_PING_PONG (1 << 3) -#define ISPCSI2_CTX_CTRL1_CTX_EN (1 << 0) +#define ISPCSI2_CTX_CTRL1_EOF_EN BIT(7) +#define ISPCSI2_CTX_CTRL1_EOL_EN BIT(6) +#define ISPCSI2_CTX_CTRL1_CS_EN BIT(5) +#define ISPCSI2_CTX_CTRL1_COUNT_UNLOCK BIT(4) +#define ISPCSI2_CTX_CTRL1_PING_PONG BIT(3) +#define ISPCSI2_CTX_CTRL1_CTX_EN BIT(0) #define ISPCSI2_CTX_CTRL2(n) ((0x074) + 0x20 * (n)) #define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT 13 @@ -1385,7 +1385,7 @@ #define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT 11 #define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK \ (0x3 << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT) -#define ISPCSI2_CTX_CTRL2_DPCM_PRED (1 << 10) +#define ISPCSI2_CTX_CTRL2_DPCM_PRED BIT(10) #define ISPCSI2_CTX_CTRL2_FORMAT_SHIFT 0 #define ISPCSI2_CTX_CTRL2_FORMAT_MASK \ (0x3ff << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT) @@ -1401,24 +1401,24 @@ #define ISPCSI2_CTX_DAT_PING_ADDR(n) ((0x07c) + 0x20 * (n)) #define ISPCSI2_CTX_DAT_PONG_ADDR(n) ((0x080) + 0x20 * (n)) #define ISPCSI2_CTX_IRQENABLE(n) ((0x084) + 0x20 * (n)) -#define ISPCSI2_CTX_IRQENABLE_ECC_CORRECTION_IRQ (1 << 8) -#define ISPCSI2_CTX_IRQENABLE_LINE_NUMBER_IRQ (1 << 7) -#define ISPCSI2_CTX_IRQENABLE_FRAME_NUMBER_IRQ (1 << 6) -#define ISPCSI2_CTX_IRQENABLE_CS_IRQ (1 << 5) -#define ISPCSI2_CTX_IRQENABLE_LE_IRQ (1 << 3) -#define ISPCSI2_CTX_IRQENABLE_LS_IRQ (1 << 2) -#define ISPCSI2_CTX_IRQENABLE_FE_IRQ (1 << 1) -#define ISPCSI2_CTX_IRQENABLE_FS_IRQ (1 << 0) +#define ISPCSI2_CTX_IRQENABLE_ECC_CORRECTION_IRQ BIT(8) +#define ISPCSI2_CTX_IRQENABLE_LINE_NUMBER_IRQ BIT(7) +#define ISPCSI2_CTX_IRQENABLE_FRAME_NUMBER_IRQ BIT(6) +#define ISPCSI2_CTX_IRQENABLE_CS_IRQ BIT(5) +#define ISPCSI2_CTX_IRQENABLE_LE_IRQ BIT(3) +#define ISPCSI2_CTX_IRQENABLE_LS_IRQ BIT(2) +#define ISPCSI2_CTX_IRQENABLE_FE_IRQ BIT(1) +#define ISPCSI2_CTX_IRQENABLE_FS_IRQ BIT(0) #define ISPCSI2_CTX_IRQSTATUS(n) ((0x088) + 0x20 * (n)) -#define ISPCSI2_CTX_IRQSTATUS_ECC_CORRECTION_IRQ (1 << 8) -#define ISPCSI2_CTX_IRQSTATUS_LINE_NUMBER_IRQ (1 << 7) -#define ISPCSI2_CTX_IRQSTATUS_FRAME_NUMBER_IRQ (1 << 6) -#define ISPCSI2_CTX_IRQSTATUS_CS_IRQ (1 << 5) -#define ISPCSI2_CTX_IRQSTATUS_LE_IRQ (1 << 3) -#define ISPCSI2_CTX_IRQSTATUS_LS_IRQ (1 << 2) -#define ISPCSI2_CTX_IRQSTATUS_FE_IRQ (1 << 1) -#define ISPCSI2_CTX_IRQSTATUS_FS_IRQ (1 << 0) +#define ISPCSI2_CTX_IRQSTATUS_ECC_CORRECTION_IRQ BIT(8) +#define ISPCSI2_CTX_IRQSTATUS_LINE_NUMBER_IRQ BIT(7) +#define ISPCSI2_CTX_IRQSTATUS_FRAME_NUMBER_IRQ BIT(6) +#define ISPCSI2_CTX_IRQSTATUS_CS_IRQ BIT(5) +#define ISPCSI2_CTX_IRQSTATUS_LE_IRQ BIT(3) +#define ISPCSI2_CTX_IRQSTATUS_LS_IRQ BIT(2) +#define ISPCSI2_CTX_IRQSTATUS_FE_IRQ BIT(1) +#define ISPCSI2_CTX_IRQSTATUS_FS_IRQ BIT(0) #define ISPCSI2_CTX_CTRL3(n) ((0x08c) + 0x20 * (n)) #define ISPCSI2_CTX_CTRL3_ALPHA_SHIFT 5 @@ -1454,9 +1454,9 @@ (0xff << ISPCSIPHY_REG0_THS_SETTLE_SHIFT) #define ISPCSIPHY_REG1 (0x004) -#define ISPCSIPHY_REG1_RESET_DONE_CTRLCLK (1 << 29) +#define ISPCSIPHY_REG1_RESET_DONE_CTRLCLK BIT(29) /* This field is for OMAP3630 only */ -#define ISPCSIPHY_REG1_CLOCK_MISS_DETECTOR_STATUS (1 << 25) +#define ISPCSIPHY_REG1_CLOCK_MISS_DETECTOR_STATUS BIT(25) #define ISPCSIPHY_REG1_TCLK_TERM_SHIFT 18 #define ISPCSIPHY_REG1_TCLK_TERM_MASK \ (0x7f << ISPCSIPHY_REG1_TCLK_TERM_SHIFT) @@ -1498,11 +1498,11 @@ */ /* OMAP343X_CONTROL_CSIRXFE */ -#define OMAP343X_CONTROL_CSIRXFE_CSIB_INV (1 << 7) -#define OMAP343X_CONTROL_CSIRXFE_RESENABLE (1 << 8) -#define OMAP343X_CONTROL_CSIRXFE_SELFORM (1 << 10) -#define OMAP343X_CONTROL_CSIRXFE_PWRDNZ (1 << 12) -#define OMAP343X_CONTROL_CSIRXFE_RESET (1 << 13) +#define OMAP343X_CONTROL_CSIRXFE_CSIB_INV BIT(7) +#define OMAP343X_CONTROL_CSIRXFE_RESENABLE BIT(8) +#define OMAP343X_CONTROL_CSIRXFE_SELFORM BIT(10) +#define OMAP343X_CONTROL_CSIRXFE_PWRDNZ BIT(12) +#define OMAP343X_CONTROL_CSIRXFE_RESET BIT(13) /* OMAP3630_CONTROL_CAMERA_PHY_CTRL */ #define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT 2 @@ -1513,6 +1513,6 @@ #define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_GPI 0x3 #define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_MASK 0x3 /* CCP2B: set to receive data from PHY2 instead of PHY1 */ -#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2 (1 << 4) +#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2 BIT(4) #endif /* OMAP3_ISP_REG_H */ diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 21ca6954df72..78d9dd7ea2da 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -1681,6 +1681,7 @@ int omap3isp_resizer_register_entities(struct isp_res_device *res, int ret; /* Register the subdev and video nodes. */ + res->subdev.dev = vdev->mdev->dev; ret = v4l2_device_register_subdev(vdev, &res->subdev); if (ret < 0) goto error; diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index 62b2eacb96fd..5b9b57f4d9bf 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -1026,6 +1026,8 @@ void omap3isp_stat_unregister_entities(struct ispstat *stat) int omap3isp_stat_register_entities(struct ispstat *stat, struct v4l2_device *vdev) { + stat->subdev.dev = vdev->mdev->dev; + return v4l2_device_register_subdev(vdev, &stat->subdev); } diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 499a7284c5a8..ee183c35ff3b 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -658,10 +658,6 @@ isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - else - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; return 0; } @@ -1024,8 +1020,8 @@ static int isp_video_check_external_subdevs(struct isp_video *video, ctrls.count = 1; ctrls.controls = &ctrl; - - ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, NULL, &ctrls); + ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &video->video, + NULL, &ctrls); if (ret < 0) { dev_warn(isp->dev, "no pixel rate control in subdev %s\n", pipe->external->name); @@ -1460,6 +1456,13 @@ int omap3isp_video_init(struct isp_video *video, const char *name) video->video.vfl_type = VFL_TYPE_GRABBER; video->video.release = video_device_release_empty; video->video.ioctl_ops = &isp_video_ioctl_ops; + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_STREAMING; + else + video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT + | V4L2_CAP_STREAMING; + video->pipe.stream_state = ISP_PIPELINE_STREAM_STOPPED; video_set_drvdata(&video->video, video); diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index 1c9bfaabc54c..8d47ea0c33f8 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -64,7 +64,7 @@ #define CIBR1 0x0030 #define CIBR2 0x0038 -#define CICR0_DMAEN (1 << 31) /* DMA request enable */ +#define CICR0_DMAEN (1UL << 31) /* DMA request enable */ #define CICR0_PAR_EN (1 << 30) /* Parity enable */ #define CICR0_SL_CAP_EN (1 << 29) /* Capture enable for slave mode */ #define CICR0_ENB (1 << 28) /* Camera interface enable */ @@ -81,7 +81,7 @@ #define CICR0_EOFM (1 << 1) /* End-of-frame mask */ #define CICR0_FOM (1 << 0) /* FIFO-overrun mask */ -#define CICR1_TBIT (1 << 31) /* Transparency bit */ +#define CICR1_TBIT (1UL << 31) /* Transparency bit */ #define CICR1_RGBT_CONV (0x3 << 29) /* RGBT conversion mask */ #define CICR1_PPL (0x7ff << 15) /* Pixels per line mask */ #define CICR1_RGB_CONV (0x7 << 12) /* RGB conversion mask */ @@ -1992,9 +1992,6 @@ static int pxac_vidioc_querycap(struct file *file, void *priv, strscpy(cap->bus_info, "platform:pxa-camera", sizeof(cap->bus_info)); strscpy(cap->driver, PXA_CAM_DRV_NAME, sizeof(cap->driver)); strscpy(cap->card, pxa_cam_driver_description, sizeof(cap->card)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 63da18773d24..3fdc9f964a3c 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -486,9 +486,9 @@ static int camss_of_parse_ports(struct camss *camss) asd = v4l2_async_notifier_add_fwnode_subdev( &camss->notifier, of_fwnode_handle(remote), sizeof(*csd)); + of_node_put(remote); if (IS_ERR(asd)) { ret = PTR_ERR(asd); - of_node_put(remote); goto err_cleanup; } diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 0acc7576cc58..e6eff512a8a1 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -198,7 +198,7 @@ static int venus_enumerate_codecs(struct venus_core *core, u32 type) goto err; for (i = 0; i < MAX_CODEC_NUM; i++) { - codec = (1 << i) & codecs; + codec = (1UL << i) & codecs; if (!codec) continue; diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 9ab95fd57760..922cb7e64bfa 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -46,6 +46,7 @@ struct venus_format { u32 pixfmt; unsigned int num_planes; u32 type; + u32 flags; }; #define MAX_PLANES 4 @@ -209,6 +210,25 @@ struct venus_buffer { #define to_venus_buffer(ptr) container_of(ptr, struct venus_buffer, vb) +enum venus_dec_state { + VENUS_DEC_STATE_DEINIT = 0, + VENUS_DEC_STATE_INIT = 1, + VENUS_DEC_STATE_CAPTURE_SETUP = 2, + VENUS_DEC_STATE_STOPPED = 3, + VENUS_DEC_STATE_SEEK = 4, + VENUS_DEC_STATE_DRAIN = 5, + VENUS_DEC_STATE_DECODING = 6, + VENUS_DEC_STATE_DRC = 7 +}; + +struct venus_ts_metadata { + bool used; + u64 ts_ns; + u64 ts_us; + u32 flags; + struct v4l2_timecode tc; +}; + /** * struct venus_inst - holds per instance parameters * @@ -232,6 +252,10 @@ struct venus_buffer { * @colorspace: current color space * @quantization: current quantization * @xfer_func: current xfer function + * @codec_state: current codec API state (see DEC/ENC_STATE_) + * @reconf_wait: wait queue for resolution change event + * @subscriptions: used to hold current events subscriptions + * @buf_count: used to count number of buffers (reqbuf(0)) * @fps: holds current FPS * @timeperframe: holds current time per frame structure * @fmt_out: a reference to output format structure @@ -246,8 +270,6 @@ struct venus_buffer { * @opb_buftype: output picture buffer type * @opb_fmt: output picture buffer raw format * @reconfig: a flag raised by decoder when the stream resolution changed - * @reconfig_width: holds the new width - * @reconfig_height: holds the new height * @hfi_codec: current codec for this instance in HFI space * @sequence_cap: a sequence counter for capture queue * @sequence_out: a sequence counter for output queue @@ -287,6 +309,11 @@ struct venus_inst { u8 ycbcr_enc; u8 quantization; u8 xfer_func; + enum venus_dec_state codec_state; + wait_queue_head_t reconf_wait; + unsigned int subscriptions; + int buf_count; + struct venus_ts_metadata tss[VIDEO_MAX_FRAME]; u64 fps; struct v4l2_fract timeperframe; const struct venus_format *fmt_out; @@ -301,8 +328,6 @@ struct venus_inst { u32 opb_buftype; u32 opb_fmt; bool reconfig; - u32 reconfig_width; - u32 reconfig_height; u32 hfi_codec; u32 sequence_cap; u32 sequence_out; diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 71b06dfc6dc4..1ad96c25ab09 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -79,7 +79,7 @@ bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt) } EXPORT_SYMBOL_GPL(venus_helper_check_codec); -static int venus_helper_queue_dpb_bufs(struct venus_inst *inst) +int venus_helper_queue_dpb_bufs(struct venus_inst *inst) { struct intbuf *buf; int ret = 0; @@ -100,6 +100,7 @@ static int venus_helper_queue_dpb_bufs(struct venus_inst *inst) fail: return ret; } +EXPORT_SYMBOL_GPL(venus_helper_queue_dpb_bufs); int venus_helper_free_dpb_bufs(struct venus_inst *inst) { @@ -278,7 +279,7 @@ static const unsigned int intbuf_types_4xx[] = { HFI_BUFFER_INTERNAL_PERSIST_1, }; -static int intbufs_alloc(struct venus_inst *inst) +int venus_helper_intbufs_alloc(struct venus_inst *inst) { const unsigned int *intbuf; size_t arr_sz, i; @@ -304,11 +305,59 @@ error: intbufs_unset_buffers(inst); return ret; } +EXPORT_SYMBOL_GPL(venus_helper_intbufs_alloc); -static int intbufs_free(struct venus_inst *inst) +int venus_helper_intbufs_free(struct venus_inst *inst) { return intbufs_unset_buffers(inst); } +EXPORT_SYMBOL_GPL(venus_helper_intbufs_free); + +int venus_helper_intbufs_realloc(struct venus_inst *inst) +{ + enum hfi_version ver = inst->core->res->hfi_version; + struct hfi_buffer_desc bd; + struct intbuf *buf, *n; + int ret; + + list_for_each_entry_safe(buf, n, &inst->internalbufs, list) { + if (buf->type == HFI_BUFFER_INTERNAL_PERSIST || + buf->type == HFI_BUFFER_INTERNAL_PERSIST_1) + continue; + + memset(&bd, 0, sizeof(bd)); + bd.buffer_size = buf->size; + bd.buffer_type = buf->type; + bd.num_buffers = 1; + bd.device_addr = buf->da; + bd.response_required = true; + + ret = hfi_session_unset_buffers(inst, &bd); + + dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da, + buf->attrs); + + list_del_init(&buf->list); + kfree(buf); + } + + ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH(ver)); + if (ret) + goto err; + + ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH_1(ver)); + if (ret) + goto err; + + ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH_2(ver)); + if (ret) + goto err; + + return 0; +err: + return ret; +} +EXPORT_SYMBOL_GPL(venus_helper_intbufs_realloc); static u32 load_per_instance(struct venus_inst *inst) { @@ -339,7 +388,7 @@ static u32 load_per_type(struct venus_core *core, u32 session_type) return mbs_per_sec; } -static int load_scale_clocks(struct venus_core *core) +int venus_helper_load_scale_clocks(struct venus_core *core) { const struct freq_tbl *table = core->res->freq_tbl; unsigned int num_rows = core->res->freq_tbl_size; @@ -388,6 +437,7 @@ err: dev_err(dev, "failed to set clock rate %lu (%d)\n", freq, ret); return ret; } +EXPORT_SYMBOL_GPL(venus_helper_load_scale_clocks); static void fill_buffer_desc(const struct venus_buffer *buf, struct hfi_buffer_desc *bd, bool response) @@ -413,6 +463,57 @@ static void return_buf_error(struct venus_inst *inst, v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); } +static void +put_ts_metadata(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf) +{ + struct vb2_buffer *vb = &vbuf->vb2_buf; + unsigned int i; + int slot = -1; + u64 ts_us = vb->timestamp; + + for (i = 0; i < ARRAY_SIZE(inst->tss); i++) { + if (!inst->tss[i].used) { + slot = i; + break; + } + } + + if (slot == -1) { + dev_dbg(inst->core->dev, "%s: no free slot\n", __func__); + return; + } + + do_div(ts_us, NSEC_PER_USEC); + + inst->tss[slot].used = true; + inst->tss[slot].flags = vbuf->flags; + inst->tss[slot].tc = vbuf->timecode; + inst->tss[slot].ts_us = ts_us; + inst->tss[slot].ts_ns = vb->timestamp; +} + +void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us, + struct vb2_v4l2_buffer *vbuf) +{ + struct vb2_buffer *vb = &vbuf->vb2_buf; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(inst->tss); ++i) { + if (!inst->tss[i].used) + continue; + + if (inst->tss[i].ts_us != timestamp_us) + continue; + + inst->tss[i].used = false; + vbuf->flags |= inst->tss[i].flags; + vbuf->timecode = inst->tss[i].tc; + vb->timestamp = inst->tss[i].ts_ns; + break; + } +} +EXPORT_SYMBOL_GPL(venus_helper_get_ts_metadata); + static int session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf) { @@ -437,6 +538,9 @@ session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf) if (vbuf->flags & V4L2_BUF_FLAG_LAST || !fdata.filled_len) fdata.flags |= HFI_BUFFERFLAG_EOS; + + if (inst->session_type == VIDC_SESSION_TYPE_DEC) + put_ts_metadata(inst, vbuf); } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { if (inst->session_type == VIDC_SESSION_TYPE_ENC) fdata.buffer_type = HFI_BUFFER_OUTPUT; @@ -472,7 +576,7 @@ static bool is_dynamic_bufmode(struct venus_inst *inst) return caps->cap_bufs_mode_dynamic; } -static int session_unregister_bufs(struct venus_inst *inst) +int venus_helper_unregister_bufs(struct venus_inst *inst) { struct venus_buffer *buf, *n; struct hfi_buffer_desc bd; @@ -489,6 +593,7 @@ static int session_unregister_bufs(struct venus_inst *inst) return ret; } +EXPORT_SYMBOL_GPL(venus_helper_unregister_bufs); static int session_register_bufs(struct venus_inst *inst) { @@ -947,6 +1052,17 @@ int venus_helper_vb2_buf_prepare(struct vb2_buffer *vb) { struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); unsigned int out_buf_size = venus_helper_get_opb_size(inst); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + if (vbuf->field == V4L2_FIELD_ANY) + vbuf->field = V4L2_FIELD_NONE; + if (vbuf->field != V4L2_FIELD_NONE) { + dev_err(inst->core->dev, "%s field isn't supported\n", + __func__); + return -EINVAL; + } + } if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && vb2_plane_size(vb, 0) < out_buf_size) @@ -970,16 +1086,19 @@ void venus_helper_vb2_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(m2m_ctx, vbuf); - if (!(inst->streamon_out & inst->streamon_cap)) + if (inst->session_type == VIDC_SESSION_TYPE_ENC && + !(inst->streamon_out && inst->streamon_cap)) goto unlock; - ret = is_buf_refed(inst, vbuf); - if (ret) - goto unlock; + if (vb2_start_streaming_called(vb->vb2_queue)) { + ret = is_buf_refed(inst, vbuf); + if (ret) + goto unlock; - ret = session_process_buf(inst, vbuf); - if (ret) - return_buf_error(inst, vbuf); + ret = session_process_buf(inst, vbuf); + if (ret) + return_buf_error(inst, vbuf); + } unlock: mutex_unlock(&inst->lock); @@ -1009,8 +1128,8 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q) if (inst->streamon_out & inst->streamon_cap) { ret = hfi_session_stop(inst); ret |= hfi_session_unload_res(inst); - ret |= session_unregister_bufs(inst); - ret |= intbufs_free(inst); + ret |= venus_helper_unregister_bufs(inst); + ret |= venus_helper_intbufs_free(inst); ret |= hfi_session_deinit(inst); if (inst->session_error || core->sys_error) @@ -1021,7 +1140,7 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q) venus_helper_free_dpb_bufs(inst); - load_scale_clocks(core); + venus_helper_load_scale_clocks(core); INIT_LIST_HEAD(&inst->registeredbufs); } @@ -1036,12 +1155,48 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q) } EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming); +int venus_helper_process_initial_cap_bufs(struct venus_inst *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; + struct v4l2_m2m_buffer *buf, *n; + int ret; + + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) { + ret = session_process_buf(inst, &buf->vb); + if (ret) { + return_buf_error(inst, &buf->vb); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(venus_helper_process_initial_cap_bufs); + +int venus_helper_process_initial_out_bufs(struct venus_inst *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; + struct v4l2_m2m_buffer *buf, *n; + int ret; + + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) { + ret = session_process_buf(inst, &buf->vb); + if (ret) { + return_buf_error(inst, &buf->vb); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(venus_helper_process_initial_out_bufs); + int venus_helper_vb2_start_streaming(struct venus_inst *inst) { struct venus_core *core = inst->core; int ret; - ret = intbufs_alloc(inst); + ret = venus_helper_intbufs_alloc(inst); if (ret) return ret; @@ -1049,7 +1204,7 @@ int venus_helper_vb2_start_streaming(struct venus_inst *inst) if (ret) goto err_bufs_free; - load_scale_clocks(core); + venus_helper_load_scale_clocks(core); ret = hfi_session_load_res(inst); if (ret) @@ -1059,20 +1214,14 @@ int venus_helper_vb2_start_streaming(struct venus_inst *inst) if (ret) goto err_unload_res; - ret = venus_helper_queue_dpb_bufs(inst); - if (ret) - goto err_session_stop; - return 0; -err_session_stop: - hfi_session_stop(inst); err_unload_res: hfi_session_unload_res(inst); err_unreg_bufs: - session_unregister_bufs(inst); + venus_helper_unregister_bufs(inst); err_bufs_free: - intbufs_free(inst); + venus_helper_intbufs_free(inst); return ret; } EXPORT_SYMBOL_GPL(venus_helper_vb2_start_streaming); diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h index 153783687a0c..01f411b12f81 100644 --- a/drivers/media/platform/qcom/venus/helpers.h +++ b/drivers/media/platform/qcom/venus/helpers.h @@ -9,6 +9,7 @@ #include <media/videobuf2-v4l2.h> struct venus_inst; +struct venus_core; bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt); struct vb2_v4l2_buffer *venus_helper_find_buf(struct venus_inst *inst, @@ -53,4 +54,14 @@ int venus_helper_alloc_dpb_bufs(struct venus_inst *inst); int venus_helper_free_dpb_bufs(struct venus_inst *inst); int venus_helper_power_enable(struct venus_core *core, u32 session_type, bool enable); +int venus_helper_intbufs_alloc(struct venus_inst *inst); +int venus_helper_intbufs_free(struct venus_inst *inst); +int venus_helper_intbufs_realloc(struct venus_inst *inst); +int venus_helper_queue_dpb_bufs(struct venus_inst *inst); +int venus_helper_unregister_bufs(struct venus_inst *inst); +int venus_helper_load_scale_clocks(struct venus_core *core); +int venus_helper_process_initial_cap_bufs(struct venus_inst *inst); +int venus_helper_process_initial_out_bufs(struct venus_inst *inst); +void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us, + struct vb2_v4l2_buffer *vbuf); #endif diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index 6ad0c1772ea7..3d8b1284d1f3 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -198,6 +198,9 @@ int hfi_session_init(struct venus_inst *inst, u32 pixfmt) const struct hfi_ops *ops = core->ops; int ret; + if (inst->state != INST_UNINIT) + return -EINVAL; + inst->hfi_codec = to_codec_type(pixfmt); reinit_completion(&inst->done); @@ -276,6 +279,7 @@ int hfi_session_start(struct venus_inst *inst) return 0; } +EXPORT_SYMBOL_GPL(hfi_session_start); int hfi_session_stop(struct venus_inst *inst) { @@ -299,6 +303,7 @@ int hfi_session_stop(struct venus_inst *inst) return 0; } +EXPORT_SYMBOL_GPL(hfi_session_stop); int hfi_session_continue(struct venus_inst *inst) { @@ -328,6 +333,7 @@ int hfi_session_abort(struct venus_inst *inst) return 0; } +EXPORT_SYMBOL_GPL(hfi_session_abort); int hfi_session_load_res(struct venus_inst *inst) { @@ -374,15 +380,16 @@ int hfi_session_unload_res(struct venus_inst *inst) return 0; } +EXPORT_SYMBOL_GPL(hfi_session_unload_res); -int hfi_session_flush(struct venus_inst *inst) +int hfi_session_flush(struct venus_inst *inst, u32 type) { const struct hfi_ops *ops = inst->core->ops; int ret; reinit_completion(&inst->done); - ret = ops->session_flush(inst, HFI_FLUSH_ALL); + ret = ops->session_flush(inst, type); if (ret) return ret; diff --git a/drivers/media/platform/qcom/venus/hfi.h b/drivers/media/platform/qcom/venus/hfi.h index b121cb1427ac..855822c9f39b 100644 --- a/drivers/media/platform/qcom/venus/hfi.h +++ b/drivers/media/platform/qcom/venus/hfi.h @@ -161,7 +161,7 @@ int hfi_session_continue(struct venus_inst *inst); int hfi_session_abort(struct venus_inst *inst); int hfi_session_load_res(struct venus_inst *inst); int hfi_session_unload_res(struct venus_inst *inst); -int hfi_session_flush(struct venus_inst *inst); +int hfi_session_flush(struct venus_inst *inst, u32 type); int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd); int hfi_session_unset_buffers(struct venus_inst *inst, diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index e1f998656c07..7f4660555ddb 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -37,42 +37,52 @@ static const struct venus_format vdec_formats[] = { .pixfmt = V4L2_PIX_FMT_MPEG4, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .pixfmt = V4L2_PIX_FMT_MPEG2, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .pixfmt = V4L2_PIX_FMT_H263, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_G, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_L, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .pixfmt = V4L2_PIX_FMT_H264, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .pixfmt = V4L2_PIX_FMT_VP8, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .pixfmt = V4L2_PIX_FMT_VP9, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .pixfmt = V4L2_PIX_FMT_XVID, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .pixfmt = V4L2_PIX_FMT_HEVC, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, }; @@ -133,6 +143,7 @@ vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt; const struct venus_format *fmt; + u32 szimage; memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved)); memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); @@ -161,14 +172,17 @@ vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) pixmp->num_planes = fmt->num_planes; pixmp->flags = 0; - pfmt[0].sizeimage = venus_helper_get_framesz(pixmp->pixelformat, - pixmp->width, - pixmp->height); + szimage = venus_helper_get_framesz(pixmp->pixelformat, pixmp->width, + pixmp->height); - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + pfmt[0].sizeimage = szimage; pfmt[0].bytesperline = ALIGN(pixmp->width, 128); - else + } else { + pfmt[0].sizeimage = clamp_t(u32, pfmt[0].sizeimage, 0, SZ_8M); + pfmt[0].sizeimage = max(pfmt[0].sizeimage, szimage); pfmt[0].bytesperline = 0; + } return fmt; } @@ -182,33 +196,56 @@ static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f) return 0; } +static int vdec_check_src_change(struct venus_inst *inst) +{ + int ret; + + if (inst->subscriptions & V4L2_EVENT_SOURCE_CHANGE && + inst->codec_state == VENUS_DEC_STATE_INIT && + !inst->reconfig) + return -EINVAL; + + if (inst->subscriptions & V4L2_EVENT_SOURCE_CHANGE) + return 0; + + /* + * The code snippet below is a workaround for backward compatibility + * with applications which doesn't support V4L2 events. It will be + * dropped in future once those applications are fixed. + */ + + if (inst->codec_state != VENUS_DEC_STATE_INIT) + goto done; + + ret = wait_event_timeout(inst->reconf_wait, inst->reconfig, + msecs_to_jiffies(100)); + if (!ret) + return -EINVAL; + + if (!(inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) || + !inst->reconfig) + dev_dbg(inst->core->dev, "%s: wrong state\n", __func__); + +done: + return 0; +} + static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f) { struct venus_inst *inst = to_inst(file); const struct venus_format *fmt = NULL; struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + int ret; if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) fmt = inst->fmt_cap; else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) fmt = inst->fmt_out; - if (inst->reconfig) { - struct v4l2_format format = {}; - - inst->out_width = inst->reconfig_width; - inst->out_height = inst->reconfig_height; - inst->reconfig = false; - - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - format.fmt.pix_mp.pixelformat = inst->fmt_cap->pixfmt; - format.fmt.pix_mp.width = inst->out_width; - format.fmt.pix_mp.height = inst->out_height; - - vdec_try_fmt_common(inst, &format); - - inst->width = format.fmt.pix_mp.width; - inst->height = format.fmt.pix_mp.height; + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = vdec_check_src_change(inst); + if (ret) + return ret; } pixmp->pixelformat = fmt->pixfmt; @@ -266,6 +303,7 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) inst->ycbcr_enc = pixmp->ycbcr_enc; inst->quantization = pixmp->quantization; inst->xfer_func = pixmp->xfer_func; + inst->input_buf_size = pixmp->plane_fmt[0].sizeimage; } memset(&format, 0, sizeof(format)); @@ -351,6 +389,7 @@ static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) return -EINVAL; f->pixelformat = fmt->pixfmt; + f->flags = fmt->flags; return 0; } @@ -422,11 +461,18 @@ static int vdec_enum_framesizes(struct file *file, void *fh, static int vdec_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { + struct venus_inst *inst = container_of(fh, struct venus_inst, fh); + int ret; + switch (sub->type) { case V4L2_EVENT_EOS: return v4l2_event_subscribe(fh, sub, 2, NULL); case V4L2_EVENT_SOURCE_CHANGE: - return v4l2_src_change_event_subscribe(fh, sub); + ret = v4l2_src_change_event_subscribe(fh, sub); + if (ret) + return ret; + inst->subscriptions |= V4L2_EVENT_SOURCE_CHANGE; + return 0; case V4L2_EVENT_CTRL: return v4l2_ctrl_subscribe_event(fh, sub); default: @@ -435,45 +481,35 @@ static int vdec_subscribe_event(struct v4l2_fh *fh, } static int -vdec_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) -{ - switch (cmd->cmd) { - case V4L2_DEC_CMD_STOP: - if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK) - return -EINVAL; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { struct venus_inst *inst = to_inst(file); struct hfi_frame_data fdata = {0}; int ret; - ret = vdec_try_decoder_cmd(file, fh, cmd); + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd); if (ret) return ret; mutex_lock(&inst->lock); - /* - * Implement V4L2_DEC_CMD_STOP by enqueue an empty buffer on decoder - * input to signal EOS. - */ - if (!(inst->streamon_out & inst->streamon_cap)) - goto unlock; + if (cmd->cmd == V4L2_DEC_CMD_STOP) { + /* + * Implement V4L2_DEC_CMD_STOP by enqueue an empty buffer on + * decoder input to signal EOS. + */ + if (!(inst->streamon_out && inst->streamon_cap)) + goto unlock; - fdata.buffer_type = HFI_BUFFER_INPUT; - fdata.flags |= HFI_BUFFERFLAG_EOS; - fdata.device_addr = 0xdeadbeef; + fdata.buffer_type = HFI_BUFFER_INPUT; + fdata.flags |= HFI_BUFFERFLAG_EOS; + fdata.device_addr = 0xdeadb000; - ret = hfi_session_process_buf(inst, &fdata); + ret = hfi_session_process_buf(inst, &fdata); + + if (!ret && inst->codec_state == VENUS_DEC_STATE_DECODING) + inst->codec_state = VENUS_DEC_STATE_DRAIN; + } unlock: mutex_unlock(&inst->lock); @@ -504,7 +540,7 @@ static const struct v4l2_ioctl_ops vdec_ioctl_ops = { .vidioc_enum_framesizes = vdec_enum_framesizes, .vidioc_subscribe_event = vdec_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - .vidioc_try_decoder_cmd = vdec_try_decoder_cmd, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, .vidioc_decoder_cmd = vdec_decoder_cmd, }; @@ -634,20 +670,18 @@ static int vdec_output_conf(struct venus_inst *inst) return 0; } -static int vdec_init_session(struct venus_inst *inst) +static int vdec_session_init(struct venus_inst *inst) { int ret; ret = hfi_session_init(inst, inst->fmt_out->pixfmt); - if (ret) + if (ret == -EINVAL) + return 0; + else if (ret) return ret; - ret = venus_helper_set_input_resolution(inst, inst->out_width, - inst->out_height); - if (ret) - goto deinit; - - ret = venus_helper_set_color_format(inst, inst->fmt_cap->pixfmt); + ret = venus_helper_set_input_resolution(inst, frame_width_min(inst), + frame_height_min(inst)); if (ret) goto deinit; @@ -666,26 +700,19 @@ static int vdec_num_buffers(struct venus_inst *inst, unsigned int *in_num, *in_num = *out_num = 0; - ret = vdec_init_session(inst); - if (ret) - return ret; - ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq); if (ret) - goto deinit; + return ret; *in_num = HFI_BUFREQ_COUNT_MIN(&bufreq, ver); ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq); if (ret) - goto deinit; + return ret; *out_num = HFI_BUFREQ_COUNT_MIN(&bufreq, ver); -deinit: - hfi_session_deinit(inst); - - return ret; + return 0; } static int vdec_queue_setup(struct vb2_queue *q, @@ -718,6 +745,10 @@ static int vdec_queue_setup(struct vb2_queue *q, return 0; } + ret = vdec_session_init(inst); + if (ret) + return ret; + ret = vdec_num_buffers(inst, &in_num, &out_num); if (ret) return ret; @@ -728,6 +759,7 @@ static int vdec_queue_setup(struct vb2_queue *q, sizes[0] = venus_helper_get_framesz(inst->fmt_out->pixfmt, inst->out_width, inst->out_height); + sizes[0] = max(sizes[0], inst->input_buf_size); inst->input_buf_size = sizes[0]; *num_buffers = max(*num_buffers, in_num); inst->num_input_bufs = *num_buffers; @@ -741,6 +773,11 @@ static int vdec_queue_setup(struct vb2_queue *q, inst->output_buf_size = sizes[0]; *num_buffers = max(*num_buffers, out_num); inst->num_output_bufs = *num_buffers; + + mutex_lock(&inst->lock); + if (inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) + inst->codec_state = VENUS_DEC_STATE_STOPPED; + mutex_unlock(&inst->lock); break; default: ret = -EINVAL; @@ -777,80 +814,295 @@ static int vdec_verify_conf(struct venus_inst *inst) return 0; } -static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) +static int vdec_start_capture(struct venus_inst *inst) { - struct venus_inst *inst = vb2_get_drv_priv(q); int ret; - mutex_lock(&inst->lock); + if (!inst->streamon_out) + return 0; - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - inst->streamon_out = 1; - else - inst->streamon_cap = 1; + if (inst->codec_state == VENUS_DEC_STATE_DECODING) { + if (inst->reconfig) + goto reconfigure; - if (!(inst->streamon_out & inst->streamon_cap)) { - mutex_unlock(&inst->lock); + venus_helper_queue_dpb_bufs(inst); + venus_helper_process_initial_cap_bufs(inst); + inst->streamon_cap = 1; return 0; } - venus_helper_init_instance(inst); + if (inst->codec_state != VENUS_DEC_STATE_STOPPED) + return 0; - inst->reconfig = false; - inst->sequence_cap = 0; - inst->sequence_out = 0; +reconfigure: + ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT); + if (ret) + return ret; - ret = vdec_init_session(inst); + ret = vdec_output_conf(inst); if (ret) - goto bufs_done; + return ret; + + ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs, + VB2_MAX_FRAME, VB2_MAX_FRAME); + if (ret) + return ret; + + ret = venus_helper_intbufs_realloc(inst); + if (ret) + goto err; + + ret = venus_helper_alloc_dpb_bufs(inst); + if (ret) + goto err; + + ret = venus_helper_queue_dpb_bufs(inst); + if (ret) + goto free_dpb_bufs; + + ret = venus_helper_process_initial_cap_bufs(inst); + if (ret) + goto free_dpb_bufs; + + venus_helper_load_scale_clocks(inst->core); + + ret = hfi_session_continue(inst); + if (ret) + goto free_dpb_bufs; + + inst->codec_state = VENUS_DEC_STATE_DECODING; + + inst->streamon_cap = 1; + inst->sequence_cap = 0; + inst->reconfig = false; + + return 0; + +free_dpb_bufs: + venus_helper_free_dpb_bufs(inst); +err: + return ret; +} + +static int vdec_start_output(struct venus_inst *inst) +{ + int ret; + + if (inst->codec_state == VENUS_DEC_STATE_SEEK) { + ret = venus_helper_process_initial_out_bufs(inst); + inst->codec_state = VENUS_DEC_STATE_DECODING; + goto done; + } + + if (inst->codec_state == VENUS_DEC_STATE_INIT || + inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) { + ret = venus_helper_process_initial_out_bufs(inst); + goto done; + } + + if (inst->codec_state != VENUS_DEC_STATE_DEINIT) + return -EINVAL; + + venus_helper_init_instance(inst); + inst->sequence_out = 0; + inst->reconfig = false; ret = vdec_set_properties(inst); if (ret) - goto deinit_sess; + return ret; ret = vdec_output_conf(inst); if (ret) - goto deinit_sess; + return ret; ret = vdec_verify_conf(inst); if (ret) - goto deinit_sess; + return ret; ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs, VB2_MAX_FRAME, VB2_MAX_FRAME); if (ret) - goto deinit_sess; + return ret; - ret = venus_helper_alloc_dpb_bufs(inst); + ret = venus_helper_vb2_start_streaming(inst); if (ret) - goto deinit_sess; + return ret; - ret = venus_helper_vb2_start_streaming(inst); + ret = venus_helper_process_initial_out_bufs(inst); if (ret) - goto deinit_sess; + return ret; - mutex_unlock(&inst->lock); + inst->codec_state = VENUS_DEC_STATE_INIT; + +done: + inst->streamon_out = 1; + return ret; +} + +static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct venus_inst *inst = vb2_get_drv_priv(q); + int ret; + + mutex_lock(&inst->lock); + + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + ret = vdec_start_capture(inst); + else + ret = vdec_start_output(inst); + if (ret) + goto error; + + mutex_unlock(&inst->lock); return 0; -deinit_sess: - hfi_session_deinit(inst); -bufs_done: +error: venus_helper_buffers_done(inst, VB2_BUF_STATE_QUEUED); + mutex_unlock(&inst->lock); + return ret; +} + +static void vdec_cancel_dst_buffers(struct venus_inst *inst) +{ + struct vb2_v4l2_buffer *buf; + + while ((buf = v4l2_m2m_dst_buf_remove(inst->m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); +} + +static int vdec_stop_capture(struct venus_inst *inst) +{ + int ret = 0; + + switch (inst->codec_state) { + case VENUS_DEC_STATE_DECODING: + ret = hfi_session_flush(inst, HFI_FLUSH_ALL); + /* fallthrough */ + case VENUS_DEC_STATE_DRAIN: + vdec_cancel_dst_buffers(inst); + inst->codec_state = VENUS_DEC_STATE_STOPPED; + break; + case VENUS_DEC_STATE_DRC: + ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT); + vdec_cancel_dst_buffers(inst); + inst->codec_state = VENUS_DEC_STATE_CAPTURE_SETUP; + INIT_LIST_HEAD(&inst->registeredbufs); + venus_helper_free_dpb_bufs(inst); + break; + default: + return 0; + } + + return ret; +} + +static int vdec_stop_output(struct venus_inst *inst) +{ + int ret = 0; + + switch (inst->codec_state) { + case VENUS_DEC_STATE_DECODING: + case VENUS_DEC_STATE_DRAIN: + case VENUS_DEC_STATE_STOPPED: + ret = hfi_session_flush(inst, HFI_FLUSH_ALL); + inst->codec_state = VENUS_DEC_STATE_SEEK; + break; + case VENUS_DEC_STATE_INIT: + case VENUS_DEC_STATE_CAPTURE_SETUP: + ret = hfi_session_flush(inst, HFI_FLUSH_INPUT); + break; + default: + break; + } + + return ret; +} + +static void vdec_stop_streaming(struct vb2_queue *q) +{ + struct venus_inst *inst = vb2_get_drv_priv(q); + int ret = -EINVAL; + + mutex_lock(&inst->lock); + + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + ret = vdec_stop_capture(inst); + else + ret = vdec_stop_output(inst); + + venus_helper_buffers_done(inst, VB2_BUF_STATE_ERROR); + + if (ret) + goto unlock; + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) inst->streamon_out = 0; else inst->streamon_cap = 0; + +unlock: mutex_unlock(&inst->lock); - return ret; +} + +static void vdec_session_release(struct venus_inst *inst) +{ + struct venus_core *core = inst->core; + int ret, abort = 0; + + mutex_lock(&inst->lock); + + inst->codec_state = VENUS_DEC_STATE_DEINIT; + + ret = hfi_session_stop(inst); + abort = (ret && ret != -EINVAL) ? 1 : 0; + ret = hfi_session_unload_res(inst); + abort = (ret && ret != -EINVAL) ? 1 : 0; + ret = venus_helper_unregister_bufs(inst); + abort = (ret && ret != -EINVAL) ? 1 : 0; + ret = venus_helper_intbufs_free(inst); + abort = (ret && ret != -EINVAL) ? 1 : 0; + ret = hfi_session_deinit(inst); + abort = (ret && ret != -EINVAL) ? 1 : 0; + + if (inst->session_error || core->sys_error) + abort = 1; + + if (abort) + hfi_session_abort(inst); + + venus_helper_free_dpb_bufs(inst); + venus_helper_load_scale_clocks(core); + INIT_LIST_HEAD(&inst->registeredbufs); + + mutex_unlock(&inst->lock); +} + +static int vdec_buf_init(struct vb2_buffer *vb) +{ + struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); + + inst->buf_count++; + + return venus_helper_vb2_buf_init(vb); +} + +static void vdec_buf_cleanup(struct vb2_buffer *vb) +{ + struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); + + inst->buf_count--; + if (!inst->buf_count) + vdec_session_release(inst); } static const struct vb2_ops vdec_vb2_ops = { .queue_setup = vdec_queue_setup, - .buf_init = venus_helper_vb2_buf_init, + .buf_init = vdec_buf_init, + .buf_cleanup = vdec_buf_cleanup, .buf_prepare = venus_helper_vb2_buf_prepare, .start_streaming = vdec_start_streaming, - .stop_streaming = venus_helper_vb2_stop_streaming, + .stop_streaming = vdec_stop_streaming, .buf_queue = venus_helper_vb2_buf_queue, }; @@ -874,9 +1126,9 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, vbuf->flags = flags; vbuf->field = V4L2_FIELD_NONE; + vb = &vbuf->vb2_buf; if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - vb = &vbuf->vb2_buf; vb2_set_plane_payload(vb, 0, bytesused); vb->planes[0].data_offset = data_offset; vb->timestamp = timestamp_us * NSEC_PER_USEC; @@ -886,28 +1138,85 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; v4l2_event_queue_fh(&inst->fh, &ev); + + if (inst->codec_state == VENUS_DEC_STATE_DRAIN) + inst->codec_state = VENUS_DEC_STATE_STOPPED; } } else { vbuf->sequence = inst->sequence_out++; } + venus_helper_get_ts_metadata(inst, timestamp_us, vbuf); + if (hfi_flags & HFI_BUFFERFLAG_READONLY) venus_helper_acquire_buf_ref(vbuf); if (hfi_flags & HFI_BUFFERFLAG_DATACORRUPT) state = VB2_BUF_STATE_ERROR; + if (hfi_flags & HFI_BUFFERFLAG_DROP_FRAME) { + state = VB2_BUF_STATE_ERROR; + vb2_set_plane_payload(vb, 0, 0); + vb->timestamp = 0; + } + v4l2_m2m_buf_done(vbuf, state); } +static void vdec_event_change(struct venus_inst *inst, + struct hfi_event_data *ev_data, bool sufficient) +{ + static const struct v4l2_event ev = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION }; + struct device *dev = inst->core->dev_dec; + struct v4l2_format format = {}; + + mutex_lock(&inst->lock); + + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + format.fmt.pix_mp.pixelformat = inst->fmt_cap->pixfmt; + format.fmt.pix_mp.width = ev_data->width; + format.fmt.pix_mp.height = ev_data->height; + + vdec_try_fmt_common(inst, &format); + + inst->width = format.fmt.pix_mp.width; + inst->height = format.fmt.pix_mp.height; + + inst->out_width = ev_data->width; + inst->out_height = ev_data->height; + + dev_dbg(dev, "event %s sufficient resources (%ux%u)\n", + sufficient ? "" : "not", ev_data->width, ev_data->height); + + if (sufficient) { + hfi_session_continue(inst); + } else { + switch (inst->codec_state) { + case VENUS_DEC_STATE_INIT: + inst->codec_state = VENUS_DEC_STATE_CAPTURE_SETUP; + break; + case VENUS_DEC_STATE_DECODING: + inst->codec_state = VENUS_DEC_STATE_DRC; + break; + default: + break; + } + } + + inst->reconfig = true; + v4l2_event_queue_fh(&inst->fh, &ev); + wake_up(&inst->reconf_wait); + + mutex_unlock(&inst->lock); +} + static void vdec_event_notify(struct venus_inst *inst, u32 event, struct hfi_event_data *data) { struct venus_core *core = inst->core; struct device *dev = core->dev_dec; - static const struct v4l2_event ev = { - .type = V4L2_EVENT_SOURCE_CHANGE, - .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION }; switch (event) { case EVT_SESSION_ERROR: @@ -917,18 +1226,10 @@ static void vdec_event_notify(struct venus_inst *inst, u32 event, case EVT_SYS_EVENT_CHANGE: switch (data->event_type) { case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES: - hfi_session_continue(inst); - dev_dbg(dev, "event sufficient resources\n"); + vdec_event_change(inst, data, true); break; case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES: - inst->reconfig_height = data->height; - inst->reconfig_width = data->width; - inst->reconfig = true; - - v4l2_event_queue_fh(&inst->fh, &ev); - - dev_dbg(dev, "event not sufficient resources (%ux%u)\n", - data->width, data->height); + vdec_event_change(inst, data, false); break; case HFI_EVENT_RELEASE_BUFFER_REFERENCE: venus_helper_release_buf_ref(inst, data->tag); @@ -949,20 +1250,25 @@ static const struct hfi_inst_ops vdec_hfi_ops = { static void vdec_inst_init(struct venus_inst *inst) { + inst->hfi_codec = HFI_VIDEO_CODEC_H264; inst->fmt_out = &vdec_formats[6]; inst->fmt_cap = &vdec_formats[0]; - inst->width = 1280; - inst->height = ALIGN(720, 32); - inst->out_width = 1280; - inst->out_height = 720; + inst->width = frame_width_min(inst); + inst->height = ALIGN(frame_height_min(inst), 32); + inst->out_width = frame_width_min(inst); + inst->out_height = frame_height_min(inst); inst->fps = 30; inst->timeperframe.numerator = 1; inst->timeperframe.denominator = 30; - inst->hfi_codec = HFI_VIDEO_CODEC_H264; + inst->opb_buftype = HFI_BUFFER_OUTPUT; +} + +static void vdec_m2m_device_run(void *priv) +{ } static const struct v4l2_m2m_ops vdec_m2m_ops = { - .device_run = venus_helper_m2m_device_run, + .device_run = vdec_m2m_device_run, .job_abort = venus_helper_m2m_job_abort, }; @@ -980,7 +1286,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->drv_priv = inst; src_vq->buf_struct_size = sizeof(struct venus_buffer); src_vq->allow_zero_bytesused = 1; - src_vq->min_buffers_needed = 1; + src_vq->min_buffers_needed = 0; src_vq->dev = inst->core->dev; ret = vb2_queue_init(src_vq); if (ret) @@ -994,7 +1300,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->drv_priv = inst; dst_vq->buf_struct_size = sizeof(struct venus_buffer); dst_vq->allow_zero_bytesused = 1; - dst_vq->min_buffers_needed = 1; + dst_vq->min_buffers_needed = 0; dst_vq->dev = inst->core->dev; ret = vb2_queue_init(dst_vq); if (ret) { @@ -1024,7 +1330,9 @@ static int vdec_open(struct file *file) inst->core = core; inst->session_type = VIDC_SESSION_TYPE_DEC; inst->num_output_bufs = 1; - + inst->codec_state = VENUS_DEC_STATE_DEINIT; + inst->buf_count = 0; + init_waitqueue_head(&inst->reconf_wait); venus_helper_init_instance(inst); ret = pm_runtime_get_sync(core->dev_dec); diff --git a/drivers/media/platform/qcom/venus/vdec_ctrls.c b/drivers/media/platform/qcom/venus/vdec_ctrls.c index 300350bfe8bd..3a963cbd342a 100644 --- a/drivers/media/platform/qcom/venus/vdec_ctrls.c +++ b/drivers/media/platform/qcom/venus/vdec_ctrls.c @@ -7,6 +7,7 @@ #include <media/v4l2-ctrls.h> #include "core.h" +#include "helpers.h" #include "vdec.h" static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) @@ -38,7 +39,9 @@ static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { struct venus_inst *inst = ctrl_to_inst(ctrl); struct vdec_controls *ctr = &inst->controls.dec; + struct hfi_buffer_requirements bufreq; union hfi_get_property hprop; + enum hfi_version ver = inst->core->res->hfi_version; u32 ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT; int ret; @@ -62,7 +65,9 @@ static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ctrl->val = ctr->post_loop_deb_mode; break; case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: - ctrl->val = inst->num_output_bufs; + ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq); + if (!ret) + ctrl->val = HFI_BUFREQ_COUNT_MIN(&bufreq, ver); break; default: return -EINVAL; diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index a5f3d2c46bea..1b7fb2d5887c 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -294,6 +294,7 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt; const struct venus_format *fmt; + u32 sizeimage; memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved)); memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); @@ -325,9 +326,10 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) pixmp->num_planes = fmt->num_planes; pixmp->flags = 0; - pfmt[0].sizeimage = venus_helper_get_framesz(pixmp->pixelformat, - pixmp->width, - pixmp->height); + sizeimage = venus_helper_get_framesz(pixmp->pixelformat, + pixmp->width, + pixmp->height); + pfmt[0].sizeimage = max(ALIGN(pfmt[0].sizeimage, SZ_4K), sizeimage); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) pfmt[0].bytesperline = ALIGN(pixmp->width, 128); @@ -399,8 +401,10 @@ static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) inst->fmt_out = fmt; - else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { inst->fmt_cap = fmt; + inst->output_buf_size = pixmp->plane_fmt[0].sizeimage; + } return 0; } @@ -918,6 +922,7 @@ static int venc_queue_setup(struct vb2_queue *q, sizes[0] = venus_helper_get_framesz(inst->fmt_cap->pixfmt, inst->width, inst->height); + sizes[0] = max(sizes[0], inst->output_buf_size); inst->output_buf_size = sizes[0]; break; default: diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 64f9cf790445..6993484ff0f3 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -390,6 +390,28 @@ out: } /* ----------------------------------------------------------------------------- + * Controls + */ + +static int rvin_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct rvin_dev *vin = + container_of(ctrl->handler, struct rvin_dev, ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_ALPHA_COMPONENT: + rvin_set_alpha(vin, ctrl->val); + break; + } + + return 0; +} + +static const struct v4l2_ctrl_ops rvin_ctrl_ops = { + .s_ctrl = rvin_s_ctrl, +}; + +/* ----------------------------------------------------------------------------- * Async notifier */ @@ -478,6 +500,15 @@ static int rvin_parallel_subdevice_attach(struct rvin_dev *vin, if (ret < 0) return ret; + v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops, + V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); + + if (vin->ctrl_handler.error) { + ret = vin->ctrl_handler.error; + v4l2_ctrl_handler_free(&vin->ctrl_handler); + return ret; + } + ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, subdev->ctrl_handler, NULL, true); if (ret < 0) { @@ -633,7 +664,7 @@ static int rvin_parallel_init(struct rvin_dev *vin) ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier); if (ret < 0) { vin_err(vin, "Notifier registration failed\n"); - v4l2_async_notifier_cleanup(&vin->group->notifier); + v4l2_async_notifier_cleanup(&vin->notifier); return ret; } @@ -870,6 +901,21 @@ static int rvin_mc_init(struct rvin_dev *vin) if (ret) rvin_group_put(vin); + ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 1); + if (ret < 0) + return ret; + + v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops, + V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); + + if (vin->ctrl_handler.error) { + ret = vin->ctrl_handler.error; + v4l2_ctrl_handler_free(&vin->ctrl_handler); + return ret; + } + + vin->vdev.ctrl_handler = &vin->ctrl_handler; + return ret; } @@ -1245,6 +1291,7 @@ static int rcar_vin_probe(struct platform_device *pdev) vin->dev = &pdev->dev; vin->info = of_device_get_match_data(&pdev->dev); + vin->alpha = 0xff; /* * Special care is needed on r8a7795 ES1.x since it @@ -1288,6 +1335,8 @@ static int rcar_vin_probe(struct platform_device *pdev) return 0; error_group_unregister: + v4l2_ctrl_handler_free(&vin->ctrl_handler); + if (vin->info->use_mc) { mutex_lock(&vin->group->lock); if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) { @@ -1323,10 +1372,10 @@ static int rcar_vin_remove(struct platform_device *pdev) } mutex_unlock(&vin->group->lock); rvin_group_put(vin); - } else { - v4l2_ctrl_handler_free(&vin->ctrl_handler); } + v4l2_ctrl_handler_free(&vin->ctrl_handler); + rvin_dma_unregister(vin); return 0; diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 91ab064404a1..3cb29b2e0b2b 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -111,10 +111,13 @@ #define VNIE_EFE (1 << 1) /* Video n Data Mode Register bits */ +#define VNDMR_A8BIT(n) (((n) & 0xff) << 24) +#define VNDMR_A8BIT_MASK (0xff << 24) #define VNDMR_EXRGB (1 << 8) #define VNDMR_BPSM (1 << 4) +#define VNDMR_ABIT (1 << 2) #define VNDMR_DTMD_YCSEP (1 << 1) -#define VNDMR_DTMD_ARGB1555 (1 << 0) +#define VNDMR_DTMD_ARGB (1 << 0) /* Video n Data Mode Register 2 bits */ #define VNDMR2_VPS (1 << 30) @@ -574,6 +577,9 @@ static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin) void rvin_crop_scale_comp(struct rvin_dev *vin) { + const struct rvin_video_format *fmt; + u32 stride; + /* Set Start/End Pixel/Line Pre-Clip */ rvin_write(vin, vin->crop.left, VNSPPRC_REG); rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG); @@ -597,10 +603,9 @@ void rvin_crop_scale_comp(struct rvin_dev *vin) if (vin->info->model != RCAR_GEN3) rvin_crop_scale_comp_gen2(vin); - if (vin->format.pixelformat == V4L2_PIX_FMT_NV16) - rvin_write(vin, ALIGN(vin->format.width, 0x20), VNIS_REG); - else - rvin_write(vin, ALIGN(vin->format.width, 0x10), VNIS_REG); + fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); + stride = vin->format.bytesperline / fmt->bpp; + rvin_write(vin, stride, VNIS_REG); } /* ----------------------------------------------------------------------------- @@ -721,7 +726,7 @@ static int rvin_setup(struct rvin_dev *vin) output_is_yuv = true; break; case V4L2_PIX_FMT_XRGB555: - dmr = VNDMR_DTMD_ARGB1555; + dmr = VNDMR_DTMD_ARGB; break; case V4L2_PIX_FMT_RGB565: dmr = 0; @@ -730,6 +735,12 @@ static int rvin_setup(struct rvin_dev *vin) /* Note: not supported on M1 */ dmr = VNDMR_EXRGB; break; + case V4L2_PIX_FMT_ARGB555: + dmr = (vin->alpha ? VNDMR_ABIT : 0) | VNDMR_DTMD_ARGB; + break; + case V4L2_PIX_FMT_ABGR32: + dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB; + break; default: vin_err(vin, "Invalid pixelformat (0x%x)\n", vin->format.pixelformat); @@ -794,7 +805,7 @@ static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) int offsetx, offsety; dma_addr_t offset; - fmt = rvin_format_from_pixel(vin->format.pixelformat); + fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); /* * There is no HW support for composition do the beast we can @@ -1343,3 +1354,34 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel) return 0; } + +void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha) +{ + unsigned long flags; + u32 dmr; + + spin_lock_irqsave(&vin->qlock, flags); + + vin->alpha = alpha; + + if (vin->state == STOPPED) + goto out; + + switch (vin->format.pixelformat) { + case V4L2_PIX_FMT_ARGB555: + dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_ABIT; + if (vin->alpha) + dmr |= VNDMR_ABIT; + break; + case V4L2_PIX_FMT_ABGR32: + dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_A8BIT_MASK; + dmr |= VNDMR_A8BIT(vin->alpha); + break; + default: + goto out; + } + + rvin_write(vin, dmr, VNDMR_REG); +out: + spin_unlock_irqrestore(&vin->qlock, flags); +} diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index 0936bcd98df1..cbc1c07f0a96 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -54,12 +54,24 @@ static const struct rvin_video_format rvin_formats[] = { .fourcc = V4L2_PIX_FMT_XBGR32, .bpp = 4, }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, + .bpp = 2, + }, + { + .fourcc = V4L2_PIX_FMT_ABGR32, + .bpp = 4, + }, }; -const struct rvin_video_format *rvin_format_from_pixel(u32 pixelformat) +const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, + u32 pixelformat) { int i; + if (vin->info->model == RCAR_M1 && pixelformat == V4L2_PIX_FMT_XBGR32) + return NULL; + for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) if (rvin_formats[i].fourcc == pixelformat) return rvin_formats + i; @@ -67,16 +79,20 @@ const struct rvin_video_format *rvin_format_from_pixel(u32 pixelformat) return NULL; } -static u32 rvin_format_bytesperline(struct v4l2_pix_format *pix) +static u32 rvin_format_bytesperline(struct rvin_dev *vin, + struct v4l2_pix_format *pix) { const struct rvin_video_format *fmt; + u32 align; - fmt = rvin_format_from_pixel(pix->pixelformat); + fmt = rvin_format_from_pixel(vin, pix->pixelformat); if (WARN_ON(!fmt)) return -EINVAL; - return pix->width * fmt->bpp; + align = pix->pixelformat == V4L2_PIX_FMT_NV16 ? 0x20 : 0x10; + + return ALIGN(pix->width, align) * fmt->bpp; } static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix) @@ -91,9 +107,7 @@ static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix) { u32 walign; - if (!rvin_format_from_pixel(pix->pixelformat) || - (vin->info->model == RCAR_M1 && - pix->pixelformat == V4L2_PIX_FMT_XBGR32)) + if (!rvin_format_from_pixel(vin, pix->pixelformat)) pix->pixelformat = RVIN_DEFAULT_FORMAT; switch (pix->field) { @@ -125,7 +139,7 @@ static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix) v4l_bound_align_image(&pix->width, 2, vin->info->max_width, walign, &pix->height, 4, vin->info->max_height, 2, 0); - pix->bytesperline = rvin_format_bytesperline(pix); + pix->bytesperline = rvin_format_bytesperline(vin, pix); pix->sizeimage = rvin_format_sizeimage(pix); vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n", @@ -181,9 +195,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, if (pad_cfg == NULL) return -ENOMEM; - if (!rvin_format_from_pixel(pix->pixelformat) || - (vin->info->model == RCAR_M1 && - pix->pixelformat == V4L2_PIX_FMT_XBGR32)) + if (!rvin_format_from_pixel(vin, pix->pixelformat)) pix->pixelformat = RVIN_DEFAULT_FORMAT; v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code); @@ -384,7 +396,7 @@ static int rvin_s_selection(struct file *file, void *fh, while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK) r.top--; - fmt = rvin_format_from_pixel(vin->format.pixelformat); + fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); while ((r.left * fmt->bpp) & HW_BUFFER_MASK) r.left--; @@ -781,26 +793,26 @@ static int rvin_open(struct file *file) if (ret) goto err_unlock; - if (vin->info->use_mc) { + if (vin->info->use_mc) ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1); - if (ret < 0) - goto err_open; - } else { - if (v4l2_fh_is_singular_file(file)) { - ret = rvin_power_parallel(vin, true); - if (ret < 0) - goto err_open; - - ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler); - if (ret) - goto err_parallel; - } - } + else if (v4l2_fh_is_singular_file(file)) + ret = rvin_power_parallel(vin, true); + + if (ret < 0) + goto err_open; + + ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler); + if (ret) + goto err_power; + mutex_unlock(&vin->lock); return 0; -err_parallel: - rvin_power_parallel(vin, false); +err_power: + if (vin->info->use_mc) + v4l2_pipeline_pm_use(&vin->vdev.entity, 0); + else if (v4l2_fh_is_singular_file(file)) + rvin_power_parallel(vin, false); err_open: v4l2_fh_release(file); err_unlock: diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 0b13b34d03e3..e562c2ff21ec 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -178,6 +178,8 @@ struct rvin_info { * @compose: active composing * @source: active size of the video source * @std: active video standard of the video source + * + * @alpha: Alpha component to fill in for supported pixel formats */ struct rvin_dev { struct device *dev; @@ -215,6 +217,8 @@ struct rvin_dev { struct v4l2_rect compose; struct v4l2_rect source; v4l2_std_id std; + + unsigned int alpha; }; #define vin_to_source(vin) ((vin)->parallel->subdev) @@ -260,11 +264,14 @@ void rvin_dma_unregister(struct rvin_dev *vin); int rvin_v4l2_register(struct rvin_dev *vin); void rvin_v4l2_unregister(struct rvin_dev *vin); -const struct rvin_video_format *rvin_format_from_pixel(u32 pixelformat); +const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, + u32 pixelformat); + /* Cropping, composing and scaling */ void rvin_crop_scale_comp(struct rvin_dev *vin); int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel); +void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha); #endif diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c index 43aae9b6bb20..cb93a13e1777 100644 --- a/drivers/media/platform/rcar_fdp1.c +++ b/drivers/media/platform/rcar_fdp1.c @@ -2122,6 +2122,7 @@ static int fdp1_open(struct file *file) if (ctx->hdl.error) { ret = ctx->hdl.error; v4l2_ctrl_handler_free(&ctx->hdl); + kfree(ctx); goto done; } @@ -2306,7 +2307,7 @@ static int fdp1_probe(struct platform_device *pdev) fdp1->fcp = rcar_fcp_get(fcp_node); of_node_put(fcp_node); if (IS_ERR(fdp1->fcp)) { - dev_err(&pdev->dev, "FCP not found (%ld)\n", + dev_dbg(&pdev->dev, "FCP not found (%ld)\n", PTR_ERR(fdp1->fcp)); return PTR_ERR(fdp1->fcp); } diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c index 57d0c0f9fa4b..197b3991330d 100644 --- a/drivers/media/platform/renesas-ceu.c +++ b/drivers/media/platform/renesas-ceu.c @@ -1659,10 +1659,8 @@ static int ceu_probe(struct platform_device *pdev) } ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "Failed to get irq: %d\n", ret); + if (ret < 0) goto error_free_ceudev; - } irq = ret; ret = devm_request_irq(dev, irq, ceu_irq, diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 5283d4533fa0..e9ff12b6b5bb 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -831,7 +831,6 @@ static int rga_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(rga->dev, "failed to get irq\n"); ret = irq; goto err_put_clk; } diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index a876d0873ebc..2fb45db8e4ba 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -641,10 +641,6 @@ static int s3c_camif_vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, S3C_CAMIF_DRIVER_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s.%d", dev_name(vp->camif->dev), vp->id); - - cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -685,10 +681,7 @@ static int s3c_camif_vidioc_enum_fmt(struct file *file, void *priv, if (!fmt) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; - - pr_debug("fmt(%d): %s\n", f->index, f->description); return 0; } @@ -802,10 +795,10 @@ static int s3c_camif_vidioc_s_fmt(struct file *file, void *priv, if (vp->owner == NULL) vp->owner = priv; - pr_debug("%ux%u. payload: %u. fmt: %s. %d %d. sizeimage: %d. bpl: %d\n", - out_frame->f_width, out_frame->f_height, vp->payload, fmt->name, - pix->width * pix->height * fmt->depth, fmt->depth, - pix->sizeimage, pix->bytesperline); + pr_debug("%ux%u. payload: %u. fmt: 0x%08x. %d %d. sizeimage: %d. bpl: %d\n", + out_frame->f_width, out_frame->f_height, vp->payload, + fmt->fourcc, pix->width * pix->height * fmt->depth, + fmt->depth, pix->sizeimage, pix->bytesperline); return 0; } @@ -1163,6 +1156,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx) goto err_me_cleanup; vfd->ctrl_handler = &vp->ctrl_handler; + vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); if (ret) diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c index b05ce0149ca1..c6fbcd7036d6 100644 --- a/drivers/media/platform/s3c-camif/camif-core.c +++ b/drivers/media/platform/s3c-camif/camif-core.c @@ -42,7 +42,6 @@ static char *camif_clocks[CLK_MAX_NUM] = { static const struct camif_fmt camif_formats[] = { { - .name = "YUV 4:2:2 planar, Y/Cb/Cr", .fourcc = V4L2_PIX_FMT_YUV422P, .depth = 16, .ybpp = 1, @@ -51,7 +50,6 @@ static const struct camif_fmt camif_formats[] = { .flags = FMT_FL_S3C24XX_CODEC | FMT_FL_S3C64XX, }, { - .name = "YUV 4:2:0 planar, Y/Cb/Cr", .fourcc = V4L2_PIX_FMT_YUV420, .depth = 12, .ybpp = 1, @@ -60,7 +58,6 @@ static const struct camif_fmt camif_formats[] = { .flags = FMT_FL_S3C24XX_CODEC | FMT_FL_S3C64XX, }, { - .name = "YVU 4:2:0 planar, Y/Cr/Cb", .fourcc = V4L2_PIX_FMT_YVU420, .depth = 12, .ybpp = 1, @@ -69,7 +66,6 @@ static const struct camif_fmt camif_formats[] = { .flags = FMT_FL_S3C24XX_CODEC | FMT_FL_S3C64XX, }, { - .name = "RGB565, 16 bpp", .fourcc = V4L2_PIX_FMT_RGB565X, .depth = 16, .ybpp = 2, @@ -78,7 +74,6 @@ static const struct camif_fmt camif_formats[] = { .flags = FMT_FL_S3C24XX_PREVIEW | FMT_FL_S3C64XX, }, { - .name = "XRGB8888, 32 bpp", .fourcc = V4L2_PIX_FMT_RGB32, .depth = 32, .ybpp = 4, @@ -87,7 +82,6 @@ static const struct camif_fmt camif_formats[] = { .flags = FMT_FL_S3C24XX_PREVIEW | FMT_FL_S3C64XX, }, { - .name = "BGR666", .fourcc = V4L2_PIX_FMT_BGR666, .depth = 32, .ybpp = 4, @@ -386,10 +380,8 @@ static int camif_request_irqs(struct platform_device *pdev, init_waitqueue_head(&vp->irq_queue); irq = platform_get_irq(pdev, i); - if (irq <= 0) { - dev_err(&pdev->dev, "failed to get IRQ %d\n", i); + if (irq <= 0) return -ENXIO; - } ret = devm_request_irq(&pdev->dev, irq, s3c_camif_irq_handler, 0, dev_name(&pdev->dev), vp); diff --git a/drivers/media/platform/s3c-camif/camif-core.h b/drivers/media/platform/s3c-camif/camif-core.h index efdc00b4ec6f..f937e638490f 100644 --- a/drivers/media/platform/s3c-camif/camif-core.h +++ b/drivers/media/platform/s3c-camif/camif-core.h @@ -89,7 +89,6 @@ enum img_fmt { * @ybpp: number of luminance bytes per pixel */ struct camif_fmt { - char *name; u32 fourcc; u32 color; u16 colplanes; diff --git a/drivers/media/platform/s3c-camif/camif-regs.h b/drivers/media/platform/s3c-camif/camif-regs.h index 29f839cdb486..052948a7b669 100644 --- a/drivers/media/platform/s3c-camif/camif-regs.h +++ b/drivers/media/platform/s3c-camif/camif-regs.h @@ -9,6 +9,8 @@ #ifndef CAMIF_REGS_H_ #define CAMIF_REGS_H_ +#include <linux/bitops.h> + #include "camif-core.h" #include <media/drv-intf/s3c_camif.h> @@ -19,7 +21,7 @@ /* Camera input format */ #define S3C_CAMIF_REG_CISRCFMT 0x00 -#define CISRCFMT_ITU601_8BIT (1 << 31) +#define CISRCFMT_ITU601_8BIT BIT(31) #define CISRCFMT_ITU656_8BIT (0 << 31) #define CISRCFMT_ORDER422_YCBYCR (0 << 14) #define CISRCFMT_ORDER422_YCRYCB (1 << 14) @@ -30,14 +32,14 @@ /* Window offset */ #define S3C_CAMIF_REG_CIWDOFST 0x04 -#define CIWDOFST_WINOFSEN (1 << 31) -#define CIWDOFST_CLROVCOFIY (1 << 30) -#define CIWDOFST_CLROVRLB_PR (1 << 28) -/* #define CIWDOFST_CLROVPRFIY (1 << 27) */ -#define CIWDOFST_CLROVCOFICB (1 << 15) -#define CIWDOFST_CLROVCOFICR (1 << 14) -#define CIWDOFST_CLROVPRFICB (1 << 13) -#define CIWDOFST_CLROVPRFICR (1 << 12) +#define CIWDOFST_WINOFSEN BIT(31) +#define CIWDOFST_CLROVCOFIY BIT(30) +#define CIWDOFST_CLROVRLB_PR BIT(28) +/* #define CIWDOFST_CLROVPRFIY BIT(27) */ +#define CIWDOFST_CLROVCOFICB BIT(15) +#define CIWDOFST_CLROVCOFICR BIT(14) +#define CIWDOFST_CLROVPRFICB BIT(13) +#define CIWDOFST_CLROVPRFICR BIT(12) #define CIWDOFST_OFST_MASK (0x7ff << 16 | 0x7ff) /* Window offset 2 */ @@ -46,24 +48,24 @@ /* Global control */ #define S3C_CAMIF_REG_CIGCTRL 0x08 -#define CIGCTRL_SWRST (1 << 31) -#define CIGCTRL_CAMRST (1 << 30) +#define CIGCTRL_SWRST BIT(31) +#define CIGCTRL_CAMRST BIT(30) #define CIGCTRL_TESTPATTERN_NORMAL (0 << 27) #define CIGCTRL_TESTPATTERN_COLOR_BAR (1 << 27) #define CIGCTRL_TESTPATTERN_HOR_INC (2 << 27) #define CIGCTRL_TESTPATTERN_VER_INC (3 << 27) #define CIGCTRL_TESTPATTERN_MASK (3 << 27) -#define CIGCTRL_INVPOLPCLK (1 << 26) -#define CIGCTRL_INVPOLVSYNC (1 << 25) -#define CIGCTRL_INVPOLHREF (1 << 24) -#define CIGCTRL_IRQ_OVFEN (1 << 22) -#define CIGCTRL_HREF_MASK (1 << 21) -#define CIGCTRL_IRQ_LEVEL (1 << 20) +#define CIGCTRL_INVPOLPCLK BIT(26) +#define CIGCTRL_INVPOLVSYNC BIT(25) +#define CIGCTRL_INVPOLHREF BIT(24) +#define CIGCTRL_IRQ_OVFEN BIT(22) +#define CIGCTRL_HREF_MASK BIT(21) +#define CIGCTRL_IRQ_LEVEL BIT(20) /* IRQ_CLR_C, IRQ_CLR_P */ -#define CIGCTRL_IRQ_CLR(id) (1 << (19 - (id))) -#define CIGCTRL_FIELDMODE (1 << 2) -#define CIGCTRL_INVPOLFIELD (1 << 1) -#define CIGCTRL_CAM_INTERLACE (1 << 0) +#define CIGCTRL_IRQ_CLR(id) BIT(19 - (id)) +#define CIGCTRL_FIELDMODE BIT(2) +#define CIGCTRL_INVPOLFIELD BIT(1) +#define CIGCTRL_CAM_INTERLACE BIT(0) /* Y DMA output frame start address. n = 0..3. */ #define S3C_CAMIF_REG_CIYSA(id, n) (0x18 + (id) * 0x54 + (n) * 4) @@ -74,8 +76,8 @@ /* CICOTRGFMT, CIPRTRGFMT - Target format */ #define S3C_CAMIF_REG_CITRGFMT(id, _offs) (0x48 + (id) * (0x34 + (_offs))) -#define CITRGFMT_IN422 (1 << 31) /* only for s3c24xx */ -#define CITRGFMT_OUT422 (1 << 30) /* only for s3c24xx */ +#define CITRGFMT_IN422 BIT(31) /* only for s3c24xx */ +#define CITRGFMT_OUT422 BIT(30) /* only for s3c24xx */ #define CITRGFMT_OUTFORMAT_YCBCR420 (0 << 29) /* only for s3c6410 */ #define CITRGFMT_OUTFORMAT_YCBCR422 (1 << 29) /* only for s3c6410 */ #define CITRGFMT_OUTFORMAT_YCBCR422I (2 << 29) /* only for s3c6410 */ @@ -88,7 +90,7 @@ #define CITRGFMT_FLIP_180 (3 << 14) #define CITRGFMT_FLIP_MASK (3 << 14) /* Preview path only */ -#define CITRGFMT_ROT90_PR (1 << 13) +#define CITRGFMT_ROT90_PR BIT(13) #define CITRGFMT_TARGETVSIZE(x) ((x) << 0) #define CITRGFMT_TARGETSIZE_MASK ((0x1fff << 16) | 0x1fff) @@ -102,7 +104,7 @@ #define CICTRL_RGBBURST2(x) ((x) << 14) #define CICTRL_CBURST1(x) ((x) << 9) #define CICTRL_CBURST2(x) ((x) << 4) -#define CICTRL_LASTIRQ_ENABLE (1 << 2) +#define CICTRL_LASTIRQ_ENABLE BIT(2) #define CICTRL_ORDER422_MASK (3 << 0) /* CICOSCPRERATIO, CIPRSCPRERATIO. Pre-scaler control 1. */ @@ -113,22 +115,22 @@ /* CICOSCCTRL, CIPRSCCTRL. Main scaler control. */ #define S3C_CAMIF_REG_CISCCTRL(id, _offs) (0x58 + (id) * (0x34 + (_offs))) -#define CISCCTRL_SCALERBYPASS (1 << 31) +#define CISCCTRL_SCALERBYPASS BIT(31) /* s3c244x preview path only, s3c64xx both */ -#define CIPRSCCTRL_SAMPLE (1 << 31) +#define CIPRSCCTRL_SAMPLE BIT(31) /* 0 - 16-bit RGB, 1 - 24-bit RGB */ -#define CIPRSCCTRL_RGB_FORMAT_24BIT (1 << 30) /* only for s3c244x */ -#define CIPRSCCTRL_SCALEUP_H (1 << 29) /* only for s3c244x */ -#define CIPRSCCTRL_SCALEUP_V (1 << 28) /* only for s3c244x */ +#define CIPRSCCTRL_RGB_FORMAT_24BIT BIT(30) /* only for s3c244x */ +#define CIPRSCCTRL_SCALEUP_H BIT(29) /* only for s3c244x */ +#define CIPRSCCTRL_SCALEUP_V BIT(28) /* only for s3c244x */ /* s3c64xx */ -#define CISCCTRL_SCALEUP_H (1 << 30) -#define CISCCTRL_SCALEUP_V (1 << 29) +#define CISCCTRL_SCALEUP_H BIT(30) +#define CISCCTRL_SCALEUP_V BIT(29) #define CISCCTRL_SCALEUP_MASK (0x3 << 29) -#define CISCCTRL_CSCR2Y_WIDE (1 << 28) -#define CISCCTRL_CSCY2R_WIDE (1 << 27) -#define CISCCTRL_LCDPATHEN_FIFO (1 << 26) -#define CISCCTRL_INTERLACE (1 << 25) -#define CISCCTRL_SCALERSTART (1 << 15) +#define CISCCTRL_CSCR2Y_WIDE BIT(28) +#define CISCCTRL_CSCY2R_WIDE BIT(27) +#define CISCCTRL_LCDPATHEN_FIFO BIT(26) +#define CISCCTRL_INTERLACE BIT(25) +#define CISCCTRL_SCALERSTART BIT(15) #define CISCCTRL_INRGB_FMT_RGB565 (0 << 13) #define CISCCTRL_INRGB_FMT_RGB666 (1 << 13) #define CISCCTRL_INRGB_FMT_RGB888 (2 << 13) @@ -137,8 +139,8 @@ #define CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11) #define CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11) #define CISCCTRL_OUTRGB_FMT_MASK (3 << 11) -#define CISCCTRL_EXTRGB_EXTENSION (1 << 10) -#define CISCCTRL_ONE2ONE (1 << 9) +#define CISCCTRL_EXTRGB_EXTENSION BIT(10) +#define CISCCTRL_ONE2ONE BIT(9) #define CISCCTRL_MAIN_RATIO_MASK (0x1ff << 16 | 0x1ff) /* CICOTAREA, CIPRTAREA. Target area for DMA (Hsize x Vsize). */ @@ -147,38 +149,38 @@ /* Codec (id = 0) or preview (id = 1) path status. */ #define S3C_CAMIF_REG_CISTATUS(id, _offs) (0x64 + (id) * (0x34 + (_offs))) -#define CISTATUS_OVFIY_STATUS (1 << 31) -#define CISTATUS_OVFICB_STATUS (1 << 30) -#define CISTATUS_OVFICR_STATUS (1 << 29) +#define CISTATUS_OVFIY_STATUS BIT(31) +#define CISTATUS_OVFICB_STATUS BIT(30) +#define CISTATUS_OVFICR_STATUS BIT(29) #define CISTATUS_OVF_MASK (0x7 << 29) #define CIPRSTATUS_OVF_MASK (0x3 << 30) -#define CISTATUS_VSYNC_STATUS (1 << 28) +#define CISTATUS_VSYNC_STATUS BIT(28) #define CISTATUS_FRAMECNT_MASK (3 << 26) #define CISTATUS_FRAMECNT(__reg) (((__reg) >> 26) & 0x3) -#define CISTATUS_WINOFSTEN_STATUS (1 << 25) -#define CISTATUS_IMGCPTEN_STATUS (1 << 22) -#define CISTATUS_IMGCPTENSC_STATUS (1 << 21) -#define CISTATUS_VSYNC_A_STATUS (1 << 20) -#define CISTATUS_FRAMEEND_STATUS (1 << 19) /* 17 on s3c64xx */ +#define CISTATUS_WINOFSTEN_STATUS BIT(25) +#define CISTATUS_IMGCPTEN_STATUS BIT(22) +#define CISTATUS_IMGCPTENSC_STATUS BIT(21) +#define CISTATUS_VSYNC_A_STATUS BIT(20) +#define CISTATUS_FRAMEEND_STATUS BIT(19) /* 17 on s3c64xx */ /* Image capture enable */ #define S3C_CAMIF_REG_CIIMGCPT(_offs) (0xa0 + (_offs)) -#define CIIMGCPT_IMGCPTEN (1 << 31) -#define CIIMGCPT_IMGCPTEN_SC(id) (1 << (30 - (id))) +#define CIIMGCPT_IMGCPTEN BIT(31) +#define CIIMGCPT_IMGCPTEN_SC(id) BIT(30 - (id)) /* Frame control: 1 - one-shot, 0 - free run */ -#define CIIMGCPT_CPT_FREN_ENABLE(id) (1 << (25 - (id))) +#define CIIMGCPT_CPT_FREN_ENABLE(id) BIT(25 - (id)) #define CIIMGCPT_CPT_FRMOD_ENABLE (0 << 18) -#define CIIMGCPT_CPT_FRMOD_CNT (1 << 18) +#define CIIMGCPT_CPT_FRMOD_CNT BIT(18) /* Capture sequence */ #define S3C_CAMIF_REG_CICPTSEQ 0xc4 /* Image effects */ #define S3C_CAMIF_REG_CIIMGEFF(_offs) (0xb0 + (_offs)) -#define CIIMGEFF_IE_ENABLE(id) (1 << (30 + (id))) +#define CIIMGEFF_IE_ENABLE(id) BIT(30 + (id)) #define CIIMGEFF_IE_ENABLE_MASK (3 << 30) /* Image effect: 1 - after scaler, 0 - before scaler */ -#define CIIMGEFF_IE_AFTER_SC (1 << 29) +#define CIIMGEFF_IE_AFTER_SC BIT(29) #define CIIMGEFF_FIN_MASK (7 << 26) #define CIIMGEFF_FIN_BYPASS (0 << 26) #define CIIMGEFF_FIN_ARBITRARY (1 << 26) @@ -207,8 +209,8 @@ /* Real input DMA data size. n = 0 - codec, 1 - preview. */ #define S3C_CAMIF_REG_MSWIDTH(id) (0xf8 + (id) * 0x2c) -#define AUTOLOAD_ENABLE (1 << 31) -#define ADDR_CH_DIS (1 << 30) +#define AUTOLOAD_ENABLE BIT(31) +#define ADDR_CH_DIS BIT(30) #define MSHEIGHT(x) (((x) & 0x3ff) << 16) #define MSWIDTH(x) ((x) & 0x3ff) @@ -219,12 +221,12 @@ #define MSCTRL_ORDER422_M_CBYCRY (2 << 4) #define MSCTRL_ORDER422_M_CRYCBY (3 << 4) /* 0 - camera, 1 - DMA */ -#define MSCTRL_SEL_DMA_CAM (1 << 3) +#define MSCTRL_SEL_DMA_CAM BIT(3) #define MSCTRL_INFORMAT_M_YCBCR420 (0 << 1) #define MSCTRL_INFORMAT_M_YCBCR422 (1 << 1) #define MSCTRL_INFORMAT_M_YCBCR422I (2 << 1) #define MSCTRL_INFORMAT_M_RGB (3 << 1) -#define MSCTRL_ENVID_M (1 << 0) +#define MSCTRL_ENVID_M BIT(0) /* CICOSCOSY, CIPRSCOSY. Scan line Y/Cb/Cr offset. */ #define S3C_CAMIF_REG_CISSY(id) (0x12c + (id) * 0x0c) diff --git a/drivers/media/platform/s5p-cec/s5p_cec.c b/drivers/media/platform/s5p-cec/s5p_cec.c index ea6231b387ed..6ddcc35b0bbd 100644 --- a/drivers/media/platform/s5p-cec/s5p_cec.c +++ b/drivers/media/platform/s5p-cec/s5p_cec.c @@ -214,21 +214,23 @@ static int s5p_cec_probe(struct platform_device *pdev) if (IS_ERR(cec->reg)) return PTR_ERR(cec->reg); - cec->notifier = cec_notifier_get(hdmi_dev); - if (cec->notifier == NULL) - return -ENOMEM; - cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec, CEC_NAME, - CEC_CAP_DEFAULTS | (needs_hpd ? CEC_CAP_NEEDS_HPD : 0), 1); + CEC_CAP_DEFAULTS | (needs_hpd ? CEC_CAP_NEEDS_HPD : 0) | + CEC_CAP_CONNECTOR_INFO, 1); ret = PTR_ERR_OR_ZERO(cec->adap); if (ret) return ret; - ret = cec_register_adapter(cec->adap, &pdev->dev); - if (ret) + cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL, + cec->adap); + if (!cec->notifier) { + ret = -ENOMEM; goto err_delete_adapter; + } - cec_register_cec_notifier(cec->adap, cec->notifier); + ret = cec_register_adapter(cec->adap, &pdev->dev); + if (ret) + goto err_notifier; platform_set_drvdata(pdev, cec); pm_runtime_enable(dev); @@ -236,6 +238,9 @@ static int s5p_cec_probe(struct platform_device *pdev) dev_dbg(dev, "successfully probed\n"); return 0; +err_notifier: + cec_notifier_cec_adap_unregister(cec->notifier); + err_delete_adapter: cec_delete_adapter(cec->adap); return ret; @@ -245,8 +250,8 @@ static int s5p_cec_remove(struct platform_device *pdev) { struct s5p_cec_dev *cec = platform_get_drvdata(pdev); + cec_notifier_cec_adap_unregister(cec->notifier); cec_unregister_adapter(cec->adap); - cec_notifier_put(cec->notifier); pm_runtime_disable(&pdev->dev); return 0; } diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 152d192d5c3f..f5f05ea9f521 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -29,31 +29,26 @@ static struct g2d_fmt formats[] = { { - .name = "XRGB_8888", .fourcc = V4L2_PIX_FMT_RGB32, .depth = 32, .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_8888), }, { - .name = "RGB_565", .fourcc = V4L2_PIX_FMT_RGB565X, .depth = 16, .hw = COLOR_MODE(ORDER_XRGB, MODE_RGB_565), }, { - .name = "XRGB_1555", .fourcc = V4L2_PIX_FMT_RGB555X, .depth = 16, .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_1555), }, { - .name = "XRGB_4444", .fourcc = V4L2_PIX_FMT_RGB444, .depth = 16, .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_4444), }, { - .name = "PACKED_RGB_888", .fourcc = V4L2_PIX_FMT_RGB24, .depth = 24, .hw = COLOR_MODE(ORDER_XRGB, MODE_PACKED_RGB_888), @@ -296,19 +291,14 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, G2D_NAME, sizeof(cap->driver)); strscpy(cap->card, G2D_NAME, sizeof(cap->card)); cap->bus_info[0] = 0; - cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) { - struct g2d_fmt *fmt; if (f->index >= NUM_FORMATS) return -EINVAL; - fmt = &formats[f->index]; - f->pixelformat = fmt->fourcc; - strscpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = formats[f->index].fourcc; return 0; } @@ -704,6 +694,7 @@ static int g2d_probe(struct platform_device *pdev) set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags); vfd->lock = &dev->mutex; vfd->v4l2_dev = &dev->v4l2_dev; + vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); diff --git a/drivers/media/platform/s5p-g2d/g2d.h b/drivers/media/platform/s5p-g2d/g2d.h index def0ec0dabeb..c2309c1370da 100644 --- a/drivers/media/platform/s5p-g2d/g2d.h +++ b/drivers/media/platform/s5p-g2d/g2d.h @@ -61,7 +61,6 @@ struct g2d_ctx { }; struct g2d_fmt { - char *name; u32 fourcc; int depth; u32 hw; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index a3bc884b7df1..8dbbd5f2a40a 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -35,7 +35,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { { - .name = "JPEG JFIF", .fourcc = V4L2_PIX_FMT_JPEG, .flags = SJPEG_FMT_FLAG_ENC_CAPTURE | SJPEG_FMT_FLAG_DEC_OUTPUT | @@ -44,7 +43,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { SJPEG_FMT_FLAG_EXYNOS4, }, { - .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .colplanes = 1, @@ -57,7 +55,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, }, { - .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .colplanes = 1, @@ -70,7 +67,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, }, { - .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .colplanes = 1, @@ -83,7 +79,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_YVYU, .depth = 16, .colplanes = 1, @@ -96,7 +91,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_YVYU, .depth = 16, .colplanes = 1, @@ -109,7 +103,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16, .colplanes = 1, @@ -122,7 +115,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_VYUY, .depth = 16, .colplanes = 1, @@ -135,7 +127,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, }, { - .name = "RGB565", .fourcc = V4L2_PIX_FMT_RGB565, .depth = 16, .colplanes = 1, @@ -148,7 +139,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, }, { - .name = "RGB565", .fourcc = V4L2_PIX_FMT_RGB565, .depth = 16, .colplanes = 1, @@ -161,7 +151,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, }, { - .name = "RGB565X", .fourcc = V4L2_PIX_FMT_RGB565X, .depth = 16, .colplanes = 1, @@ -174,7 +163,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, }, { - .name = "RGB565", .fourcc = V4L2_PIX_FMT_RGB565, .depth = 16, .colplanes = 1, @@ -186,7 +174,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, }, { - .name = "ARGB8888, 32 bpp", .fourcc = V4L2_PIX_FMT_RGB32, .depth = 32, .colplanes = 1, @@ -199,7 +186,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, }, { - .name = "ARGB8888, 32 bpp", .fourcc = V4L2_PIX_FMT_RGB32, .depth = 32, .colplanes = 1, @@ -212,7 +198,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, }, { - .name = "YUV 4:4:4 planar, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV24, .depth = 24, .colplanes = 2, @@ -225,7 +210,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, }, { - .name = "YUV 4:4:4 planar, Y/CrCb", .fourcc = V4L2_PIX_FMT_NV42, .depth = 24, .colplanes = 2, @@ -238,7 +222,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, }, { - .name = "YUV 4:2:2 planar, Y/CrCb", .fourcc = V4L2_PIX_FMT_NV61, .depth = 16, .colplanes = 2, @@ -251,7 +234,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, }, { - .name = "YUV 4:2:2 planar, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV16, .depth = 16, .colplanes = 2, @@ -264,7 +246,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, }, { - .name = "YUV 4:2:0 planar, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV12, .depth = 12, .colplanes = 2, @@ -277,7 +258,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, }, { - .name = "YUV 4:2:0 planar, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV12, .depth = 12, .colplanes = 2, @@ -290,7 +270,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, }, { - .name = "YUV 4:2:0 planar, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV12, .depth = 12, .colplanes = 2, @@ -303,7 +282,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, }, { - .name = "YUV 4:2:0 planar, Y/CrCb", .fourcc = V4L2_PIX_FMT_NV21, .depth = 12, .colplanes = 2, @@ -316,7 +294,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, }, { - .name = "YUV 4:2:0 planar, Y/CrCb", .fourcc = V4L2_PIX_FMT_NV21, .depth = 12, .colplanes = 2, @@ -330,7 +307,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, }, { - .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr", .fourcc = V4L2_PIX_FMT_YUV420, .depth = 12, .colplanes = 3, @@ -343,7 +319,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, }, { - .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr", .fourcc = V4L2_PIX_FMT_YUV420, .depth = 12, .colplanes = 3, @@ -356,7 +331,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, }, { - .name = "Gray", .fourcc = V4L2_PIX_FMT_GREY, .depth = 8, .colplanes = 1, @@ -1285,8 +1259,6 @@ static int s5p_jpeg_querycap(struct file *file, void *priv, } snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(ctx->jpeg->dev)); - cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1314,7 +1286,6 @@ static int enum_fmt(struct s5p_jpeg_ctx *ctx, if (i >= n) return -EINVAL; - strscpy(f->description, sjpeg_formats[i].name, sizeof(f->description)); f->pixelformat = sjpeg_formats[i].fourcc; return 0; @@ -2974,6 +2945,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) jpeg->vfd_encoder->lock = &jpeg->lock; jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev; jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M; + jpeg->vfd_encoder->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1); if (ret) { @@ -3003,6 +2975,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) jpeg->vfd_decoder->lock = &jpeg->lock; jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev; jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M; + jpeg->vfd_decoder->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1); if (ret) { diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index 34f87f6c02f2..3bc52f83f5bc 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h @@ -150,7 +150,6 @@ struct s5p_jpeg_variant { /** * struct jpeg_fmt - driver's internal color format data - * @name: format description * @fourcc: the fourcc code, 0 if not applicable * @depth: number of bits per pixel * @colplanes: number of color planes (1 for packed formats) @@ -159,7 +158,6 @@ struct s5p_jpeg_variant { * @flags: flags describing format applicability */ struct s5p_jpeg_fmt { - char *name; u32 fourcc; int depth; int colplanes; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h index bab7fa46b89a..86f376b50581 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h @@ -121,14 +121,14 @@ /* JPEG timer setting register */ #define S5P_JPG_TIMER_SE 0x7c -#define S5P_TIMER_INT_EN_MASK (0x1 << 31) -#define S5P_TIMER_INT_EN (0x1 << 31) +#define S5P_TIMER_INT_EN_MASK (0x1UL << 31) +#define S5P_TIMER_INT_EN (0x1UL << 31) #define S5P_TIMER_INIT_MASK 0x7fffffff /* JPEG timer status register */ #define S5P_JPG_TIMER_ST 0x80 #define S5P_TIMER_INT_STAT_SHIFT 31 -#define S5P_TIMER_INT_STAT_MASK (0x1 << S5P_TIMER_INT_STAT_SHIFT) +#define S5P_TIMER_INT_STAT_MASK (0x1UL << S5P_TIMER_INT_STAT_SHIFT) #define S5P_TIMER_CNT_SHIFT 0 #define S5P_TIMER_CNT_MASK 0x7fffffff @@ -562,13 +562,13 @@ /* JPEG timer setting register */ #define EXYNOS3250_TIMER_SE 0x148 #define EXYNOS3250_TIMER_INT_EN_SHIFT 31 -#define EXYNOS3250_TIMER_INT_EN (1 << EXYNOS3250_TIMER_INT_EN_SHIFT) +#define EXYNOS3250_TIMER_INT_EN (1UL << EXYNOS3250_TIMER_INT_EN_SHIFT) #define EXYNOS3250_TIMER_INIT_MASK 0x7fffffff /* JPEG timer status register */ #define EXYNOS3250_TIMER_ST 0x14c #define EXYNOS3250_TIMER_INT_STAT_SHIFT 31 -#define EXYNOS3250_TIMER_INT_STAT (1 << EXYNOS3250_TIMER_INT_STAT_SHIFT) +#define EXYNOS3250_TIMER_INT_STAT (1UL << EXYNOS3250_TIMER_INT_STAT_SHIFT) #define EXYNOS3250_TIMER_CNT_SHIFT 0 #define EXYNOS3250_TIMER_CNT_MASK 0x7fffffff diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 5dc086516360..96d1ecd1521b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -718,7 +718,6 @@ struct s5p_mfc_ctx { * used by the MFC */ struct s5p_mfc_fmt { - char *name; u32 fourcc; u32 codec_mode; enum s5p_mfc_fmt_type type; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 4017c8b471f4..61e144a35201 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -29,7 +29,6 @@ static struct s5p_mfc_fmt formats[] = { { - .name = "4:2:0 2 Planes 16x16 Tiles", .fourcc = V4L2_PIX_FMT_NV12MT_16X16, .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, @@ -37,7 +36,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V6_BIT | MFC_V7_BIT, }, { - .name = "4:2:0 2 Planes 64x32 Tiles", .fourcc = V4L2_PIX_FMT_NV12MT, .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, @@ -45,7 +43,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5_BIT, }, { - .name = "4:2:0 2 Planes Y/CbCr", .fourcc = V4L2_PIX_FMT_NV12M, .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, @@ -53,7 +50,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V6PLUS_BITS, }, { - .name = "4:2:0 2 Planes Y/CrCb", .fourcc = V4L2_PIX_FMT_NV21M, .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, @@ -61,7 +57,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V6PLUS_BITS, }, { - .name = "H264 Encoded Stream", .fourcc = V4L2_PIX_FMT_H264, .codec_mode = S5P_MFC_CODEC_H264_DEC, .type = MFC_FMT_DEC, @@ -69,7 +64,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "H264/MVC Encoded Stream", .fourcc = V4L2_PIX_FMT_H264_MVC, .codec_mode = S5P_MFC_CODEC_H264_MVC_DEC, .type = MFC_FMT_DEC, @@ -77,7 +71,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V6PLUS_BITS, }, { - .name = "H263 Encoded Stream", .fourcc = V4L2_PIX_FMT_H263, .codec_mode = S5P_MFC_CODEC_H263_DEC, .type = MFC_FMT_DEC, @@ -85,7 +78,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "MPEG1 Encoded Stream", .fourcc = V4L2_PIX_FMT_MPEG1, .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, .type = MFC_FMT_DEC, @@ -93,7 +85,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "MPEG2 Encoded Stream", .fourcc = V4L2_PIX_FMT_MPEG2, .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, .type = MFC_FMT_DEC, @@ -101,7 +92,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "MPEG4 Encoded Stream", .fourcc = V4L2_PIX_FMT_MPEG4, .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, .type = MFC_FMT_DEC, @@ -109,7 +99,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "XviD Encoded Stream", .fourcc = V4L2_PIX_FMT_XVID, .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, .type = MFC_FMT_DEC, @@ -117,7 +106,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "VC1 Encoded Stream", .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, .codec_mode = S5P_MFC_CODEC_VC1_DEC, .type = MFC_FMT_DEC, @@ -125,7 +113,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "VC1 RCV Encoded Stream", .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, .type = MFC_FMT_DEC, @@ -133,7 +120,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "VP8 Encoded Stream", .fourcc = V4L2_PIX_FMT_VP8, .codec_mode = S5P_MFC_CODEC_VP8_DEC, .type = MFC_FMT_DEC, @@ -279,7 +265,6 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, bool out) { struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_fmt *fmt; int i, j = 0; for (i = 0; i < ARRAY_SIZE(formats); ++i) { @@ -296,9 +281,7 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, } if (i == ARRAY_SIZE(formats)) return -EINVAL; - fmt = &formats[i]; - strscpy(f->description, fmt->name, sizeof(f->description)); - f->pixelformat = fmt->fourcc; + f->pixelformat = formats[i].fourcc; return 0; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 97e76480e942..912fe0c5ab18 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -32,7 +32,6 @@ static struct s5p_mfc_fmt formats[] = { { - .name = "4:2:0 2 Planes 16x16 Tiles", .fourcc = V4L2_PIX_FMT_NV12MT_16X16, .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, @@ -40,7 +39,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V6_BIT | MFC_V7_BIT, }, { - .name = "4:2:0 2 Planes 64x32 Tiles", .fourcc = V4L2_PIX_FMT_NV12MT, .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, @@ -48,7 +46,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5_BIT, }, { - .name = "4:2:0 2 Planes Y/CbCr", .fourcc = V4L2_PIX_FMT_NV12M, .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, @@ -56,7 +53,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "4:2:0 2 Planes Y/CrCb", .fourcc = V4L2_PIX_FMT_NV21M, .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, @@ -64,7 +60,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V6PLUS_BITS, }, { - .name = "H264 Encoded Stream", .fourcc = V4L2_PIX_FMT_H264, .codec_mode = S5P_MFC_CODEC_H264_ENC, .type = MFC_FMT_ENC, @@ -72,7 +67,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "MPEG4 Encoded Stream", .fourcc = V4L2_PIX_FMT_MPEG4, .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, .type = MFC_FMT_ENC, @@ -80,7 +74,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "H263 Encoded Stream", .fourcc = V4L2_PIX_FMT_H263, .codec_mode = S5P_MFC_CODEC_H263_ENC, .type = MFC_FMT_ENC, @@ -88,7 +81,6 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V5PLUS_BITS, }, { - .name = "VP8 Encoded Stream", .fourcc = V4L2_PIX_FMT_VP8, .codec_mode = S5P_MFC_CODEC_VP8_ENC, .type = MFC_FMT_ENC, @@ -1320,7 +1312,6 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, bool out) { struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_fmt *fmt; int i, j = 0; for (i = 0; i < ARRAY_SIZE(formats); ++i) { @@ -1332,10 +1323,7 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, continue; if (j == f->index) { - fmt = &formats[i]; - strscpy(f->description, fmt->name, - sizeof(f->description)); - f->pixelformat = fmt->fourcc; + f->pixelformat = formats[i].fourcc; return 0; } ++j; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index f76a07400966..49503c20d320 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -711,7 +711,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL); if (p->pad) { /** enable */ - reg |= (1 << 31); + reg |= (1UL << 31); /** cr value */ reg &= ~(0xFF << 16); reg |= (p->pad_cr << 16); @@ -955,7 +955,7 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) S5P_FIMV_ENC_RC_FRAME_RATE); shm = s5p_mfc_read_info_v5(ctx, RC_VOP_TIMING); shm &= ~(0xFFFFFFFF); - shm |= (1 << 31); + shm |= (1UL << 31); shm |= ((p->rc_framerate_num & 0x7FFF) << 16); shm |= (p->rc_framerate_denom & 0xFFFF); s5p_mfc_write_info_v5(ctx, shm, RC_VOP_TIMING); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index f7621a9051cb..a1453053e31a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -840,7 +840,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) if (p->pad) { reg = 0; /** enable */ - reg |= (1 << 31); + reg |= (1UL << 31); /** cr value */ reg |= ((p->pad_cr & 0xFF) << 16); /** cb value */ diff --git a/drivers/media/platform/seco-cec/seco-cec.c b/drivers/media/platform/seco-cec/seco-cec.c index 1d0133f01e00..9cd60fe1867c 100644 --- a/drivers/media/platform/seco-cec/seco-cec.c +++ b/drivers/media/platform/seco-cec/seco-cec.c @@ -507,10 +507,10 @@ err: } struct cec_dmi_match { - char *sys_vendor; - char *product_name; - char *devname; - char *conn; + const char *sys_vendor; + const char *product_name; + const char *devname; + const char *conn; }; static const struct cec_dmi_match secocec_dmi_match_table[] = { @@ -518,7 +518,8 @@ static const struct cec_dmi_match secocec_dmi_match_table[] = { { "SECO", "UDOO x86", "0000:00:02.0", "Port B" }, }; -static int secocec_cec_get_notifier(struct cec_notifier **notify) +static struct device *secocec_cec_find_hdmi_dev(struct device *dev, + const char **conn) { int i; @@ -533,16 +534,15 @@ static int secocec_cec_get_notifier(struct cec_notifier **notify) d = bus_find_device_by_name(&pci_bus_type, NULL, m->devname); if (!d) - return -EPROBE_DEFER; + return ERR_PTR(-EPROBE_DEFER); - *notify = cec_notifier_get_conn(d, m->conn); put_device(d); - - return 0; + *conn = m->conn; + return d; } } - return -EINVAL; + return ERR_PTR(-EINVAL); } static int secocec_acpi_probe(struct secocec_data *sdev) @@ -573,9 +573,15 @@ static int secocec_probe(struct platform_device *pdev) { struct secocec_data *secocec; struct device *dev = &pdev->dev; + struct device *hdmi_dev; + const char *conn = NULL; int ret; u16 val; + hdmi_dev = secocec_cec_find_hdmi_dev(&pdev->dev, &conn); + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); + secocec = devm_kzalloc(dev, sizeof(*secocec), GFP_KERNEL); if (!secocec) return -ENOMEM; @@ -617,12 +623,6 @@ static int secocec_probe(struct platform_device *pdev) goto err; } - ret = secocec_cec_get_notifier(&secocec->notifier); - if (ret) { - dev_err(dev, "no CEC notifier available\n"); - goto err; - } - ret = devm_request_threaded_irq(dev, secocec->irq, NULL, @@ -640,7 +640,8 @@ static int secocec_probe(struct platform_device *pdev) secocec->cec_adap = cec_allocate_adapter(&secocec_cec_adap_ops, secocec, dev_name(dev), - CEC_CAP_DEFAULTS, + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, SECOCEC_MAX_ADDRS); if (IS_ERR(secocec->cec_adap)) { @@ -648,16 +649,20 @@ static int secocec_probe(struct platform_device *pdev) goto err; } - ret = cec_register_adapter(secocec->cec_adap, dev); - if (ret) + secocec->notifier = cec_notifier_cec_adap_register(hdmi_dev, conn, + secocec->cec_adap); + if (!secocec->notifier) { + ret = -ENOMEM; goto err_delete_adapter; + } - if (secocec->notifier) - cec_register_cec_notifier(secocec->cec_adap, secocec->notifier); + ret = cec_register_adapter(secocec->cec_adap, dev); + if (ret) + goto err_notifier; ret = secocec_ir_probe(secocec); if (ret) - goto err_delete_adapter; + goto err_notifier; platform_set_drvdata(pdev, secocec); @@ -665,6 +670,8 @@ static int secocec_probe(struct platform_device *pdev) return ret; +err_notifier: + cec_notifier_cec_adap_unregister(secocec->notifier); err_delete_adapter: cec_delete_adapter(secocec->cec_adap); err: @@ -685,11 +692,9 @@ static int secocec_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "IR disabled"); } + cec_notifier_cec_adap_unregister(secocec->notifier); cec_unregister_adapter(secocec->cec_adap); - if (secocec->notifier) - cec_notifier_put(secocec->notifier); - release_region(BRA_SMB_BASE_ADDR, 7); dev_dbg(&pdev->dev, "CEC device removed"); diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 5a9ba05c996e..2b4c0d9d6928 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -81,12 +81,12 @@ struct sh_veu_dev; struct sh_veu_file { + struct v4l2_fh fh; struct sh_veu_dev *veu_dev; bool cfg_needed; }; struct sh_veu_format { - char *name; u32 fourcc; unsigned int depth; unsigned int ydepth; @@ -144,14 +144,14 @@ enum sh_veu_fmt_idx { * aligned for NV24. */ static const struct sh_veu_format sh_veu_fmt[] = { - [SH_VEU_FMT_NV12] = { .ydepth = 8, .depth = 12, .name = "NV12", .fourcc = V4L2_PIX_FMT_NV12 }, - [SH_VEU_FMT_NV16] = { .ydepth = 8, .depth = 16, .name = "NV16", .fourcc = V4L2_PIX_FMT_NV16 }, - [SH_VEU_FMT_NV24] = { .ydepth = 8, .depth = 24, .name = "NV24", .fourcc = V4L2_PIX_FMT_NV24 }, - [SH_VEU_FMT_RGB332] = { .ydepth = 8, .depth = 8, .name = "RGB332", .fourcc = V4L2_PIX_FMT_RGB332 }, - [SH_VEU_FMT_RGB444] = { .ydepth = 16, .depth = 16, .name = "RGB444", .fourcc = V4L2_PIX_FMT_RGB444 }, - [SH_VEU_FMT_RGB565] = { .ydepth = 16, .depth = 16, .name = "RGB565", .fourcc = V4L2_PIX_FMT_RGB565 }, - [SH_VEU_FMT_RGB666] = { .ydepth = 32, .depth = 32, .name = "BGR666", .fourcc = V4L2_PIX_FMT_BGR666 }, - [SH_VEU_FMT_RGB24] = { .ydepth = 24, .depth = 24, .name = "RGB24", .fourcc = V4L2_PIX_FMT_RGB24 }, + [SH_VEU_FMT_NV12] = { .ydepth = 8, .depth = 12, .fourcc = V4L2_PIX_FMT_NV12 }, + [SH_VEU_FMT_NV16] = { .ydepth = 8, .depth = 16, .fourcc = V4L2_PIX_FMT_NV16 }, + [SH_VEU_FMT_NV24] = { .ydepth = 8, .depth = 24, .fourcc = V4L2_PIX_FMT_NV24 }, + [SH_VEU_FMT_RGB332] = { .ydepth = 8, .depth = 8, .fourcc = V4L2_PIX_FMT_RGB332 }, + [SH_VEU_FMT_RGB444] = { .ydepth = 16, .depth = 16, .fourcc = V4L2_PIX_FMT_RGB444 }, + [SH_VEU_FMT_RGB565] = { .ydepth = 16, .depth = 16, .fourcc = V4L2_PIX_FMT_RGB565 }, + [SH_VEU_FMT_RGB666] = { .ydepth = 32, .depth = 32, .fourcc = V4L2_PIX_FMT_BGR666 }, + [SH_VEU_FMT_RGB24] = { .ydepth = 24, .depth = 24, .fourcc = V4L2_PIX_FMT_RGB24 }, }; #define DEFAULT_IN_VFMT (struct sh_veu_vfmt){ \ @@ -348,9 +348,6 @@ static int sh_veu_querycap(struct file *file, void *priv, strscpy(cap->driver, "sh-veu", sizeof(cap->driver)); strscpy(cap->card, "sh-mobile VEU", sizeof(cap->card)); strscpy(cap->bus_info, "platform:sh-veu", sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -359,8 +356,6 @@ static int sh_veu_enum_fmt(struct v4l2_fmtdesc *f, const int *fmt, int fmt_num) if (f->index >= fmt_num) return -EINVAL; - strscpy(f->description, sh_veu_fmt[fmt[f->index]].name, - sizeof(f->description)); f->pixelformat = sh_veu_fmt[fmt[f->index]].fourcc; return 0; } @@ -967,12 +962,14 @@ static int sh_veu_open(struct file *file) if (!veu_file) return -ENOMEM; + v4l2_fh_init(&veu_file->fh, video_devdata(file)); veu_file->veu_dev = veu; veu_file->cfg_needed = true; file->private_data = veu_file; pm_runtime_get_sync(veu->dev); + v4l2_fh_add(&veu_file->fh); dev_dbg(veu->dev, "Created instance %p\n", veu_file); @@ -1002,6 +999,8 @@ static int sh_veu_release(struct file *file) } pm_runtime_put(veu->dev); + v4l2_fh_del(&veu_file->fh); + v4l2_fh_exit(&veu_file->fh); kfree(veu_file); @@ -1039,6 +1038,7 @@ static const struct video_device sh_veu_videodev = { .minor = -1, .release = video_device_release_empty, .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, }; static const struct v4l2_m2m_ops sh_veu_m2m_ops = { diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 5799aa4b9323..2236702c21b4 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -138,7 +138,6 @@ static void sh_vou_reg_ab_set(struct sh_vou_device *vou_dev, unsigned int reg, struct sh_vou_fmt { u32 pfmt; - char *desc; unsigned char bpp; unsigned char bpl; unsigned char rgb; @@ -152,7 +151,6 @@ static struct sh_vou_fmt vou_fmt[] = { .pfmt = V4L2_PIX_FMT_NV12, .bpp = 12, .bpl = 1, - .desc = "YVU420 planar", .yf = 0, .rgb = 0, }, @@ -160,7 +158,6 @@ static struct sh_vou_fmt vou_fmt[] = { .pfmt = V4L2_PIX_FMT_NV16, .bpp = 16, .bpl = 1, - .desc = "YVYU planar", .yf = 1, .rgb = 0, }, @@ -168,7 +165,6 @@ static struct sh_vou_fmt vou_fmt[] = { .pfmt = V4L2_PIX_FMT_RGB24, .bpp = 24, .bpl = 3, - .desc = "RGB24", .pkf = 2, .rgb = 1, }, @@ -176,7 +172,6 @@ static struct sh_vou_fmt vou_fmt[] = { .pfmt = V4L2_PIX_FMT_RGB565, .bpp = 16, .bpl = 2, - .desc = "RGB565", .pkf = 3, .rgb = 1, }, @@ -184,7 +179,6 @@ static struct sh_vou_fmt vou_fmt[] = { .pfmt = V4L2_PIX_FMT_RGB565X, .bpp = 16, .bpl = 2, - .desc = "RGB565 byteswapped", .pkf = 3, .rgb = 1, }, @@ -381,9 +375,6 @@ static int sh_vou_querycap(struct file *file, void *priv, strscpy(cap->card, "SuperH VOU", sizeof(cap->card)); strscpy(cap->driver, "sh-vou", sizeof(cap->driver)); strscpy(cap->bus_info, "platform:sh-vou", sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -398,9 +389,6 @@ static int sh_vou_enum_fmt_vid_out(struct file *file, void *priv, dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - strscpy(fmt->description, vou_fmt[fmt->index].desc, - sizeof(fmt->description)); fmt->pixelformat = vou_fmt[fmt->index].pfmt; return 0; @@ -494,7 +482,8 @@ static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev, if (h_idx) vouvcr |= (1 << 14) | vou_scale_v_fld[h_idx - 1]; - dev_dbg(vou_dev->v4l2_dev.dev, "%s: scaling 0x%x\n", fmt->desc, vouvcr); + dev_dbg(vou_dev->v4l2_dev.dev, "0x%08x: scaling 0x%x\n", + fmt->pfmt, vouvcr); /* To produce a colour bar for testing set bit 23 of VOUVCR */ sh_vou_reg_ab_write(vou_dev, VOUVCR, vouvcr); @@ -1218,6 +1207,8 @@ static const struct video_device sh_vou_video_template = { .ioctl_ops = &sh_vou_ioctl_ops, .tvnorms = V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */ .vfl_dir = VFL_DIR_TX, + .device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; static int sh_vou_probe(struct platform_device *pdev) diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index 79f7db1a9d18..e90f1ba30574 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -692,11 +692,6 @@ static int bdisp_querycap(struct file *file, void *fh, strscpy(cap->card, bdisp->pdev->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s%d", BDISP_NAME, bdisp->id); - - cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; - - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1059,6 +1054,7 @@ static int bdisp_register_device(struct bdisp_dev *bdisp) bdisp->vdev.lock = &bdisp->lock; bdisp->vdev.vfl_dir = VFL_DIR_M2M; bdisp->vdev.v4l2_dev = &bdisp->v4l2_dev; + bdisp->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; snprintf(bdisp->vdev.name, sizeof(bdisp->vdev.name), "%s.%d", BDISP_NAME, bdisp->id); diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 3c05b3dc49ec..5baada4f65e5 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -693,16 +693,12 @@ static int c8sectpfe_probe(struct platform_device *pdev) fei->sram_size = resource_size(res); fei->idle_irq = platform_get_irq_byname(pdev, "c8sectpfe-idle-irq"); - if (fei->idle_irq < 0) { - dev_err(dev, "Can't get c8sectpfe-idle-irq\n"); + if (fei->idle_irq < 0) return fei->idle_irq; - } fei->error_irq = platform_get_irq_byname(pdev, "c8sectpfe-error-irq"); - if (fei->error_irq < 0) { - dev_err(dev, "Can't get c8sectpfe-error-irq\n"); + if (fei->error_irq < 0) return fei->error_irq; - } platform_set_drvdata(pdev, fei); diff --git a/drivers/media/platform/sti/cec/stih-cec.c b/drivers/media/platform/sti/cec/stih-cec.c index fc37efe1d554..8118c7365d3f 100644 --- a/drivers/media/platform/sti/cec/stih-cec.c +++ b/drivers/media/platform/sti/cec/stih-cec.c @@ -313,10 +313,6 @@ static int stih_cec_probe(struct platform_device *pdev) if (!cec) return -ENOMEM; - cec->notifier = cec_notifier_get(hdmi_dev); - if (!cec->notifier) - return -ENOMEM; - cec->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -340,30 +336,42 @@ static int stih_cec_probe(struct platform_device *pdev) return PTR_ERR(cec->clk); } - cec->adap = cec_allocate_adapter(&sti_cec_adap_ops, cec, - CEC_NAME, CEC_CAP_DEFAULTS, CEC_MAX_LOG_ADDRS); + cec->adap = cec_allocate_adapter(&sti_cec_adap_ops, cec, CEC_NAME, + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, + CEC_MAX_LOG_ADDRS); ret = PTR_ERR_OR_ZERO(cec->adap); if (ret) return ret; - ret = cec_register_adapter(cec->adap, &pdev->dev); - if (ret) { - cec_delete_adapter(cec->adap); - return ret; + cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL, + cec->adap); + if (!cec->notifier) { + ret = -ENOMEM; + goto err_delete_adapter; } - cec_register_cec_notifier(cec->adap, cec->notifier); + ret = cec_register_adapter(cec->adap, &pdev->dev); + if (ret) + goto err_notifier; platform_set_drvdata(pdev, cec); return 0; + +err_notifier: + cec_notifier_cec_adap_unregister(cec->notifier); + +err_delete_adapter: + cec_delete_adapter(cec->adap); + return ret; } static int stih_cec_remove(struct platform_device *pdev) { struct stih_cec *cec = platform_get_drvdata(pdev); + cec_notifier_cec_adap_unregister(cec->notifier); cec_unregister_adapter(cec->adap); - cec_notifier_put(cec->notifier); return 0; } diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c index 7917fd2c4bd4..401aaafa1710 100644 --- a/drivers/media/platform/sti/hva/hva-hw.c +++ b/drivers/media/platform/sti/hva/hva-hw.c @@ -341,10 +341,8 @@ int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva) /* get status interruption resource */ ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "%s failed to get status IRQ\n", HVA_PREFIX); + if (ret < 0) goto err_clk; - } hva->irq_its = ret; ret = devm_request_threaded_irq(dev, hva->irq_its, hva_hw_its_interrupt, @@ -360,10 +358,8 @@ int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva) /* get error interruption resource */ ret = platform_get_irq(pdev, 1); - if (ret < 0) { - dev_err(dev, "%s failed to get error IRQ\n", HVA_PREFIX); + if (ret < 0) goto err_clk; - } hva->irq_err = ret; ret = devm_request_threaded_irq(dev, hva->irq_err, hva_hw_err_interrupt, diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index d855e9c09c08..9392e3409fba 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -100,10 +100,10 @@ enum state { #define OVERRUN_ERROR_THRESHOLD 3 struct dcmi_graph_entity { - struct device_node *node; - struct v4l2_async_subdev asd; - struct v4l2_subdev *subdev; + + struct device_node *remote_node; + struct v4l2_subdev *source; }; struct dcmi_format { @@ -169,6 +169,10 @@ struct stm32_dcmi { /* Ensure DMA operations atomicity */ struct mutex dma_lock; + + struct media_device mdev; + struct media_pad vid_cap_pad; + struct media_pipeline pipeline; }; static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n) @@ -580,6 +584,144 @@ static void dcmi_buf_queue(struct vb2_buffer *vb) spin_unlock_irq(&dcmi->irqlock); } +static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi) +{ + struct media_entity *entity = &dcmi->vdev->entity; + struct media_pad *pad; + + /* Walk searching for entity having no sink */ + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + break; + + entity = pad->entity; + } + + return entity; +} + +static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi, + struct v4l2_subdev_pad_config *pad_cfg, + struct v4l2_subdev_format *format) +{ + struct media_entity *entity = &dcmi->entity.source->entity; + struct v4l2_subdev *subdev; + struct media_pad *sink_pad = NULL; + struct media_pad *src_pad = NULL; + struct media_pad *pad = NULL; + struct v4l2_subdev_format fmt = *format; + bool found = false; + int ret; + + /* + * Starting from sensor subdevice, walk within + * pipeline and set format on each subdevice + */ + while (1) { + unsigned int i; + + /* Search if current entity has a source pad */ + for (i = 0; i < entity->num_pads; i++) { + pad = &entity->pads[i]; + if (pad->flags & MEDIA_PAD_FL_SOURCE) { + src_pad = pad; + found = true; + break; + } + } + if (!found) + break; + + subdev = media_entity_to_v4l2_subdev(entity); + + /* Propagate format on sink pad if any, otherwise source pad */ + if (sink_pad) + pad = sink_pad; + + dev_dbg(dcmi->dev, "\"%s\":%d pad format set to 0x%x %ux%u\n", + subdev->name, pad->index, format->format.code, + format->format.width, format->format.height); + + fmt.pad = pad->index; + ret = v4l2_subdev_call(subdev, pad, set_fmt, pad_cfg, &fmt); + if (ret < 0) { + dev_err(dcmi->dev, "%s: Failed to set format 0x%x %ux%u on \"%s\":%d pad (%d)\n", + __func__, format->format.code, + format->format.width, format->format.height, + subdev->name, pad->index, ret); + return ret; + } + + if (fmt.format.code != format->format.code || + fmt.format.width != format->format.width || + fmt.format.height != format->format.height) { + dev_dbg(dcmi->dev, "\"%s\":%d pad format has been changed to 0x%x %ux%u\n", + subdev->name, pad->index, fmt.format.code, + fmt.format.width, fmt.format.height); + } + + /* Walk to next entity */ + sink_pad = media_entity_remote_pad(src_pad); + if (!sink_pad || !is_media_entity_v4l2_subdev(sink_pad->entity)) + break; + + entity = sink_pad->entity; + } + *format = fmt; + + return 0; +} + +static int dcmi_pipeline_s_stream(struct stm32_dcmi *dcmi, int state) +{ + struct media_entity *entity = &dcmi->vdev->entity; + struct v4l2_subdev *subdev; + struct media_pad *pad; + int ret; + + /* Start/stop all entities within pipeline */ + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + ret = v4l2_subdev_call(subdev, video, s_stream, state); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_err(dcmi->dev, "%s: \"%s\" failed to %s streaming (%d)\n", + __func__, subdev->name, + state ? "start" : "stop", ret); + return ret; + } + + dev_dbg(dcmi->dev, "\"%s\" is %s\n", + subdev->name, state ? "started" : "stopped"); + } + + return 0; +} + +static int dcmi_pipeline_start(struct stm32_dcmi *dcmi) +{ + return dcmi_pipeline_s_stream(dcmi, 1); +} + +static void dcmi_pipeline_stop(struct stm32_dcmi *dcmi) +{ + dcmi_pipeline_s_stream(dcmi, 0); +} + static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) { struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); @@ -594,14 +736,17 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) goto err_release_buffers; } - /* Enable stream on the sub device */ - ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 1); - if (ret && ret != -ENOIOCTLCMD) { - dev_err(dcmi->dev, "%s: Failed to start streaming, subdev streamon error", - __func__); + ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline); + if (ret < 0) { + dev_err(dcmi->dev, "%s: Failed to start streaming, media pipeline start error (%d)\n", + __func__, ret); goto err_pm_put; } + ret = dcmi_pipeline_start(dcmi); + if (ret) + goto err_media_pipeline_stop; + spin_lock_irq(&dcmi->irqlock); /* Set bus width */ @@ -673,7 +818,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) if (ret) { dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n", __func__); - goto err_subdev_streamoff; + goto err_pipeline_stop; } /* Enable interruptions */ @@ -684,8 +829,11 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) return 0; -err_subdev_streamoff: - v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); +err_pipeline_stop: + dcmi_pipeline_stop(dcmi); + +err_media_pipeline_stop: + media_pipeline_stop(&dcmi->vdev->entity); err_pm_put: pm_runtime_put(dcmi->dev); @@ -710,13 +858,10 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) { struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); struct dcmi_buf *buf, *node; - int ret; - /* Disable stream on the sub device */ - ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); - if (ret && ret != -ENOIOCTLCMD) - dev_err(dcmi->dev, "%s: Failed to stop streaming, subdev streamoff error (%d)\n", - __func__, ret); + dcmi_pipeline_stop(dcmi); + + media_pipeline_stop(&dcmi->vdev->entity); spin_lock_irq(&dcmi->irqlock); @@ -857,7 +1002,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, } v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt, + ret = v4l2_subdev_call(dcmi->entity.source, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; @@ -934,8 +1079,7 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) mf->width = sd_framesize.width; mf->height = sd_framesize.height; - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, - set_fmt, NULL, &format); + ret = dcmi_pipeline_s_fmt(dcmi, NULL, &format); if (ret < 0) return ret; @@ -991,7 +1135,7 @@ static int dcmi_get_sensor_format(struct stm32_dcmi *dcmi, }; int ret; - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_fmt, NULL, &fmt); + ret = v4l2_subdev_call(dcmi->entity.source, pad, get_fmt, NULL, &fmt); if (ret) return ret; @@ -1020,7 +1164,7 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi, } v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt, + ret = v4l2_subdev_call(dcmi->entity.source, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; @@ -1043,7 +1187,7 @@ static int dcmi_get_sensor_bounds(struct stm32_dcmi *dcmi, /* * Get sensor bounds first */ - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_selection, + ret = v4l2_subdev_call(dcmi->entity.source, pad, get_selection, NULL, &bounds); if (!ret) *r = bounds.r; @@ -1224,7 +1368,7 @@ static int dcmi_enum_framesizes(struct file *file, void *fh, fse.code = sd_fmt->mbus_code; - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, enum_frame_size, + ret = v4l2_subdev_call(dcmi->entity.source, pad, enum_frame_size, NULL, &fse); if (ret) return ret; @@ -1241,7 +1385,7 @@ static int dcmi_g_parm(struct file *file, void *priv, { struct stm32_dcmi *dcmi = video_drvdata(file); - return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.subdev, p); + return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.source, p); } static int dcmi_s_parm(struct file *file, void *priv, @@ -1249,7 +1393,7 @@ static int dcmi_s_parm(struct file *file, void *priv, { struct stm32_dcmi *dcmi = video_drvdata(file); - return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.subdev, p); + return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.source, p); } static int dcmi_enum_frameintervals(struct file *file, void *fh, @@ -1271,7 +1415,7 @@ static int dcmi_enum_frameintervals(struct file *file, void *fh, fie.code = sd_fmt->mbus_code; - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, + ret = v4l2_subdev_call(dcmi->entity.source, pad, enum_frame_interval, NULL, &fie); if (ret) return ret; @@ -1291,7 +1435,7 @@ MODULE_DEVICE_TABLE(of, stm32_dcmi_of_match); static int dcmi_open(struct file *file) { struct stm32_dcmi *dcmi = video_drvdata(file); - struct v4l2_subdev *sd = dcmi->entity.subdev; + struct v4l2_subdev *sd = dcmi->entity.source; int ret; if (mutex_lock_interruptible(&dcmi->lock)) @@ -1322,7 +1466,7 @@ unlock: static int dcmi_release(struct file *file) { struct stm32_dcmi *dcmi = video_drvdata(file); - struct v4l2_subdev *sd = dcmi->entity.subdev; + struct v4l2_subdev *sd = dcmi->entity.source; bool fh_singular; int ret; @@ -1409,6 +1553,12 @@ static int dcmi_set_default_fmt(struct stm32_dcmi *dcmi) return 0; } +/* + * FIXME: For the time being we only support subdevices + * which expose RGB & YUV "parallel form" mbus code (_2X8). + * Nevertheless, this allows to support serial source subdevices + * and serial to parallel bridges which conform to this. + */ static const struct dcmi_format dcmi_formats[] = { { .fourcc = V4L2_PIX_FMT_RGB565, @@ -1433,7 +1583,7 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) { const struct dcmi_format *sd_fmts[ARRAY_SIZE(dcmi_formats)]; unsigned int num_fmts = 0, i, j; - struct v4l2_subdev *subdev = dcmi->entity.subdev; + struct v4l2_subdev *subdev = dcmi->entity.source; struct v4l2_subdev_mbus_code_enum mbus_code = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; @@ -1447,12 +1597,20 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) /* Code supported, have we got this fourcc yet? */ for (j = 0; j < num_fmts; j++) if (sd_fmts[j]->fourcc == - dcmi_formats[i].fourcc) + dcmi_formats[i].fourcc) { /* Already available */ + dev_dbg(dcmi->dev, "Skipping fourcc/code: %4.4s/0x%x\n", + (char *)&sd_fmts[j]->fourcc, + mbus_code.code); break; - if (j == num_fmts) + } + if (j == num_fmts) { /* New */ sd_fmts[num_fmts++] = dcmi_formats + i; + dev_dbg(dcmi->dev, "Supported fourcc/code: %4.4s/0x%x\n", + (char *)&sd_fmts[num_fmts - 1]->fourcc, + sd_fmts[num_fmts - 1]->mbus_code); + } } mbus_code.index++; } @@ -1479,7 +1637,7 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) static int dcmi_framesizes_init(struct stm32_dcmi *dcmi) { unsigned int num_fsize = 0; - struct v4l2_subdev *subdev = dcmi->entity.subdev; + struct v4l2_subdev *subdev = dcmi->entity.source; struct v4l2_subdev_frame_size_enum fse = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, .code = dcmi->sd_format->mbus_code, @@ -1526,7 +1684,20 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier) struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier); int ret; - dcmi->vdev->ctrl_handler = dcmi->entity.subdev->ctrl_handler; + /* + * Now that the graph is complete, + * we search for the source subdevice + * in order to expose it through V4L2 interface + */ + dcmi->entity.source = + media_entity_to_v4l2_subdev(dcmi_find_source(dcmi)); + if (!dcmi->entity.source) { + dev_err(dcmi->dev, "Source subdevice not found\n"); + return -ENODEV; + } + + dcmi->vdev->ctrl_handler = dcmi->entity.source->ctrl_handler; + ret = dcmi_formats_init(dcmi); if (ret) { dev_err(dcmi->dev, "No supported mediabus format found\n"); @@ -1551,14 +1722,6 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier) return ret; } - ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1); - if (ret) { - dev_err(dcmi->dev, "Failed to register video device\n"); - return ret; - } - - dev_dbg(dcmi->dev, "Device registered as %s\n", - video_device_node_name(dcmi->vdev)); return 0; } @@ -1579,12 +1742,31 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, struct v4l2_async_subdev *asd) { struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier); + unsigned int ret; + int src_pad; - dev_dbg(dcmi->dev, "Subdev %s bound\n", subdev->name); + dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name); - dcmi->entity.subdev = subdev; + /* + * Link this sub-device to DCMI, it could be + * a parallel camera sensor or a bridge + */ + src_pad = media_entity_get_fwnode_pad(&subdev->entity, + subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + + ret = media_create_pad_link(&subdev->entity, src_pad, + &dcmi->vdev->entity, 0, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + dev_err(dcmi->dev, "Failed to create media pad link with subdev \"%s\"\n", + subdev->name); + else + dev_dbg(dcmi->dev, "DCMI is now linked to \"%s\"\n", + subdev->name); - return 0; + return ret; } static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = { @@ -1608,7 +1790,7 @@ static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node) return -EINVAL; /* Remote node to connect */ - dcmi->entity.node = remote; + dcmi->entity.remote_node = remote; dcmi->entity.asd.match_type = V4L2_ASYNC_MATCH_FWNODE; dcmi->entity.asd.match.fwnode = of_fwnode_handle(remote); return 0; @@ -1631,7 +1813,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) &dcmi->entity.asd); if (ret) { dev_err(dcmi->dev, "Failed to add subdev notifier\n"); - of_node_put(dcmi->entity.node); + of_node_put(dcmi->entity.remote_node); return ret; } @@ -1679,7 +1861,6 @@ static int dcmi_probe(struct platform_device *pdev) np = of_graph_get_next_endpoint(np, NULL); if (!np) { dev_err(&pdev->dev, "Could not find the endpoint\n"); - of_node_put(np); return -ENODEV; } @@ -1699,11 +1880,8 @@ static int dcmi_probe(struct platform_device *pdev) dcmi->bus.data_shift = ep.bus.parallel.data_shift; irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - if (irq != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get irq\n"); + if (irq <= 0) return irq ? irq : -ENXIO; - } dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!dcmi->res) { @@ -1751,10 +1929,19 @@ static int dcmi_probe(struct platform_device *pdev) q = &dcmi->queue; + dcmi->v4l2_dev.mdev = &dcmi->mdev; + + /* Initialize media device */ + strscpy(dcmi->mdev.model, DRV_NAME, sizeof(dcmi->mdev.model)); + snprintf(dcmi->mdev.bus_info, sizeof(dcmi->mdev.bus_info), + "platform:%s", DRV_NAME); + dcmi->mdev.dev = &pdev->dev; + media_device_init(&dcmi->mdev); + /* Initialize the top-level structure */ ret = v4l2_device_register(&pdev->dev, &dcmi->v4l2_dev); if (ret) - goto err_dma_release; + goto err_media_device_cleanup; dcmi->vdev = video_device_alloc(); if (!dcmi->vdev) { @@ -1774,6 +1961,25 @@ static int dcmi_probe(struct platform_device *pdev) V4L2_CAP_READWRITE; video_set_drvdata(dcmi->vdev, dcmi); + /* Media entity pads */ + dcmi->vid_cap_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&dcmi->vdev->entity, + 1, &dcmi->vid_cap_pad); + if (ret) { + dev_err(dcmi->dev, "Failed to init media entity pad\n"); + goto err_device_release; + } + dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; + + ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1); + if (ret) { + dev_err(dcmi->dev, "Failed to register video device\n"); + goto err_media_entity_cleanup; + } + + dev_dbg(dcmi->dev, "Device registered as %s\n", + video_device_node_name(dcmi->vdev)); + /* Buffer queue */ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; @@ -1789,12 +1995,12 @@ static int dcmi_probe(struct platform_device *pdev) ret = vb2_queue_init(q); if (ret < 0) { dev_err(&pdev->dev, "Failed to initialize vb2 queue\n"); - goto err_device_release; + goto err_media_entity_cleanup; } ret = dcmi_graph_init(dcmi); if (ret < 0) - goto err_device_release; + goto err_media_entity_cleanup; /* Reset device */ ret = reset_control_assert(dcmi->rstc); @@ -1821,11 +2027,14 @@ static int dcmi_probe(struct platform_device *pdev) err_cleanup: v4l2_async_notifier_cleanup(&dcmi->notifier); +err_media_entity_cleanup: + media_entity_cleanup(&dcmi->vdev->entity); err_device_release: video_device_release(dcmi->vdev); err_device_unregister: v4l2_device_unregister(&dcmi->v4l2_dev); -err_dma_release: +err_media_device_cleanup: + media_device_cleanup(&dcmi->mdev); dma_release_channel(dcmi->dma_chan); return ret; @@ -1839,7 +2048,9 @@ static int dcmi_remove(struct platform_device *pdev) v4l2_async_notifier_unregister(&dcmi->notifier); v4l2_async_notifier_cleanup(&dcmi->notifier); + media_entity_cleanup(&dcmi->vdev->entity); v4l2_device_unregister(&dcmi->v4l2_dev); + media_device_cleanup(&dcmi->mdev); dma_release_channel(dcmi->dma_chan); diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig new file mode 100644 index 000000000000..71808e93ac2e --- /dev/null +++ b/drivers/media/platform/sunxi/Kconfig @@ -0,0 +1,2 @@ +source "drivers/media/platform/sunxi/sun4i-csi/Kconfig" +source "drivers/media/platform/sunxi/sun6i-csi/Kconfig" diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile new file mode 100644 index 000000000000..a05127529006 --- /dev/null +++ b/drivers/media/platform/sunxi/Makefile @@ -0,0 +1,2 @@ +obj-y += sun4i-csi/ +obj-y += sun6i-csi/ diff --git a/drivers/media/platform/sunxi/sun4i-csi/Kconfig b/drivers/media/platform/sunxi/sun4i-csi/Kconfig new file mode 100644 index 000000000000..e86e29b6a603 --- /dev/null +++ b/drivers/media/platform/sunxi/sun4i-csi/Kconfig @@ -0,0 +1,11 @@ +config VIDEO_SUN4I_CSI + tristate "Allwinner A10 CMOS Sensor Interface Support" + depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API && HAS_DMA + depends on ARCH_SUNXI || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + help + This is a V4L2 driver for the Allwinner A10 CSI + + To compile this driver as a module, choose M here: the module + will be called sun4i_csi. diff --git a/drivers/media/platform/sunxi/sun4i-csi/Makefile b/drivers/media/platform/sunxi/sun4i-csi/Makefile new file mode 100644 index 000000000000..7c790a57f5ee --- /dev/null +++ b/drivers/media/platform/sunxi/sun4i-csi/Makefile @@ -0,0 +1,5 @@ +sun4i-csi-y += sun4i_csi.o +sun4i-csi-y += sun4i_dma.o +sun4i-csi-y += sun4i_v4l2.o + +obj-$(CONFIG_VIDEO_SUN4I_CSI) += sun4i-csi.o diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c new file mode 100644 index 000000000000..f36dc6258900 --- /dev/null +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 NextThing Co + * Copyright (C) 2016-2019 Bootlin + * + * Author: Maxime Ripard <maxime.ripard@bootlin.com> + */ + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> +#include <linux/videodev2.h> + +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mediabus.h> + +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "sun4i_csi.h" + +static const struct media_entity_operations sun4i_csi_video_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int sun4i_csi_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct sun4i_csi *csi = container_of(notifier, struct sun4i_csi, + notifier); + + csi->src_subdev = subdev; + csi->src_pad = media_entity_get_fwnode_pad(&subdev->entity, + subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + if (csi->src_pad < 0) { + dev_err(csi->dev, "Couldn't find output pad for subdev %s\n", + subdev->name); + return csi->src_pad; + } + + dev_dbg(csi->dev, "Bound %s pad: %d\n", subdev->name, csi->src_pad); + return 0; +} + +static int sun4i_csi_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct sun4i_csi *csi = container_of(notifier, struct sun4i_csi, + notifier); + struct v4l2_subdev *subdev = &csi->subdev; + struct video_device *vdev = &csi->vdev; + int ret; + + ret = v4l2_device_register_subdev(&csi->v4l, subdev); + if (ret < 0) + return ret; + + ret = sun4i_csi_v4l2_register(csi); + if (ret < 0) + return ret; + + ret = media_device_register(&csi->mdev); + if (ret) + return ret; + + /* Create link from subdev to main device */ + ret = media_create_pad_link(&subdev->entity, CSI_SUBDEV_SOURCE, + &vdev->entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) + goto err_clean_media; + + ret = media_create_pad_link(&csi->src_subdev->entity, csi->src_pad, + &subdev->entity, CSI_SUBDEV_SINK, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) + goto err_clean_media; + + ret = v4l2_device_register_subdev_nodes(&csi->v4l); + if (ret < 0) + goto err_clean_media; + + return 0; + +err_clean_media: + media_device_unregister(&csi->mdev); + + return ret; +} + +static const struct v4l2_async_notifier_operations sun4i_csi_notify_ops = { + .bound = sun4i_csi_notify_bound, + .complete = sun4i_csi_notify_complete, +}; + +static int sun4i_csi_notifier_init(struct sun4i_csi *csi) +{ + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_PARALLEL, + }; + struct fwnode_handle *ep; + int ret; + + v4l2_async_notifier_init(&csi->notifier); + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!ep) + return -EINVAL; + + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + if (ret) + goto out; + + csi->bus = vep.bus.parallel; + + ret = v4l2_async_notifier_add_fwnode_remote_subdev(&csi->notifier, + ep, &csi->asd); + if (ret) + goto out; + + csi->notifier.ops = &sun4i_csi_notify_ops; + +out: + fwnode_handle_put(ep); + return ret; +} + +static int sun4i_csi_probe(struct platform_device *pdev) +{ + struct v4l2_subdev *subdev; + struct video_device *vdev; + struct sun4i_csi *csi; + struct resource *res; + int ret; + int irq; + + csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); + if (!csi) + return -ENOMEM; + platform_set_drvdata(pdev, csi); + csi->dev = &pdev->dev; + subdev = &csi->subdev; + vdev = &csi->vdev; + + csi->mdev.dev = csi->dev; + strscpy(csi->mdev.model, "Allwinner Video Capture Device", + sizeof(csi->mdev.model)); + csi->mdev.hw_revision = 0; + media_device_init(&csi->mdev); + csi->v4l.mdev = &csi->mdev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + csi->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(csi->regs)) + return PTR_ERR(csi->regs); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + csi->bus_clk = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(csi->bus_clk)) { + dev_err(&pdev->dev, "Couldn't get our bus clock\n"); + return PTR_ERR(csi->bus_clk); + } + + csi->isp_clk = devm_clk_get(&pdev->dev, "isp"); + if (IS_ERR(csi->isp_clk)) { + dev_err(&pdev->dev, "Couldn't get our ISP clock\n"); + return PTR_ERR(csi->isp_clk); + } + + csi->ram_clk = devm_clk_get(&pdev->dev, "ram"); + if (IS_ERR(csi->ram_clk)) { + dev_err(&pdev->dev, "Couldn't get our ram clock\n"); + return PTR_ERR(csi->ram_clk); + } + + csi->rst = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(csi->rst)) { + dev_err(&pdev->dev, "Couldn't get our reset line\n"); + return PTR_ERR(csi->rst); + } + + /* Initialize subdev */ + v4l2_subdev_init(subdev, &sun4i_csi_subdev_ops); + subdev->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + subdev->owner = THIS_MODULE; + snprintf(subdev->name, sizeof(subdev->name), "sun4i-csi-0"); + v4l2_set_subdevdata(subdev, csi); + + csi->subdev_pads[CSI_SUBDEV_SINK].flags = + MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; + csi->subdev_pads[CSI_SUBDEV_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&subdev->entity, CSI_SUBDEV_PADS, + csi->subdev_pads); + if (ret < 0) + return ret; + + csi->vdev_pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; + vdev->entity.ops = &sun4i_csi_video_entity_ops; + ret = media_entity_pads_init(&vdev->entity, 1, &csi->vdev_pad); + if (ret < 0) + return ret; + + ret = sun4i_csi_dma_register(csi, irq); + if (ret) + goto err_clean_pad; + + ret = sun4i_csi_notifier_init(csi); + if (ret) + goto err_unregister_media; + + ret = v4l2_async_notifier_register(&csi->v4l, &csi->notifier); + if (ret) { + dev_err(csi->dev, "Couldn't register our notifier.\n"); + goto err_unregister_media; + } + + pm_runtime_enable(&pdev->dev); + + return 0; + +err_unregister_media: + media_device_unregister(&csi->mdev); + sun4i_csi_dma_unregister(csi); + +err_clean_pad: + media_device_cleanup(&csi->mdev); + + return ret; +} + +static int sun4i_csi_remove(struct platform_device *pdev) +{ + struct sun4i_csi *csi = platform_get_drvdata(pdev); + + v4l2_async_notifier_unregister(&csi->notifier); + v4l2_async_notifier_cleanup(&csi->notifier); + media_device_unregister(&csi->mdev); + sun4i_csi_dma_unregister(csi); + media_device_cleanup(&csi->mdev); + + return 0; +} + +static const struct of_device_id sun4i_csi_of_match[] = { + { .compatible = "allwinner,sun7i-a20-csi0" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sun4i_csi_of_match); + +static int __maybe_unused sun4i_csi_runtime_resume(struct device *dev) +{ + struct sun4i_csi *csi = dev_get_drvdata(dev); + + reset_control_deassert(csi->rst); + clk_prepare_enable(csi->bus_clk); + clk_prepare_enable(csi->ram_clk); + clk_set_rate(csi->isp_clk, 80000000); + clk_prepare_enable(csi->isp_clk); + + writel(1, csi->regs + CSI_EN_REG); + + return 0; +} + +static int __maybe_unused sun4i_csi_runtime_suspend(struct device *dev) +{ + struct sun4i_csi *csi = dev_get_drvdata(dev); + + clk_disable_unprepare(csi->isp_clk); + clk_disable_unprepare(csi->ram_clk); + clk_disable_unprepare(csi->bus_clk); + + reset_control_assert(csi->rst); + + return 0; +} + +static const struct dev_pm_ops sun4i_csi_pm_ops = { + SET_RUNTIME_PM_OPS(sun4i_csi_runtime_suspend, + sun4i_csi_runtime_resume, + NULL) +}; + +static struct platform_driver sun4i_csi_driver = { + .probe = sun4i_csi_probe, + .remove = sun4i_csi_remove, + .driver = { + .name = "sun4i-csi", + .of_match_table = sun4i_csi_of_match, + .pm = &sun4i_csi_pm_ops, + }, +}; +module_platform_driver(sun4i_csi_driver); + +MODULE_DESCRIPTION("Allwinner A10 Camera Sensor Interface driver"); +MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h new file mode 100644 index 000000000000..001c8bde006c --- /dev/null +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2016 NextThing Co + * Copyright (C) 2016-2019 Bootlin + * + * Author: Maxime Ripard <maxime.ripard@bootlin.com> + */ + +#ifndef _SUN4I_CSI_H_ +#define _SUN4I_CSI_H_ + +#include <media/media-device.h> +#include <media/v4l2-async.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/videobuf2-core.h> + +#define CSI_EN_REG 0x00 + +#define CSI_CFG_REG 0x04 +#define CSI_CFG_INPUT_FMT(fmt) ((fmt) << 20) +#define CSI_CFG_OUTPUT_FMT(fmt) ((fmt) << 16) +#define CSI_CFG_YUV_DATA_SEQ(seq) ((seq) << 8) +#define CSI_CFG_VSYNC_POL(pol) ((pol) << 2) +#define CSI_CFG_HSYNC_POL(pol) ((pol) << 1) +#define CSI_CFG_PCLK_POL(pol) ((pol) << 0) + +#define CSI_CPT_CTRL_REG 0x08 +#define CSI_CPT_CTRL_VIDEO_START BIT(1) +#define CSI_CPT_CTRL_IMAGE_START BIT(0) + +#define CSI_BUF_ADDR_REG(fifo, buf) (0x10 + (0x8 * (fifo)) + (0x4 * (buf))) + +#define CSI_BUF_CTRL_REG 0x28 +#define CSI_BUF_CTRL_DBN BIT(2) +#define CSI_BUF_CTRL_DBS BIT(1) +#define CSI_BUF_CTRL_DBE BIT(0) + +#define CSI_INT_EN_REG 0x30 +#define CSI_INT_FRM_DONE BIT(1) +#define CSI_INT_CPT_DONE BIT(0) + +#define CSI_INT_STA_REG 0x34 + +#define CSI_WIN_CTRL_W_REG 0x40 +#define CSI_WIN_CTRL_W_ACTIVE(w) ((w) << 16) + +#define CSI_WIN_CTRL_H_REG 0x44 +#define CSI_WIN_CTRL_H_ACTIVE(h) ((h) << 16) + +#define CSI_BUF_LEN_REG 0x48 + +#define CSI_MAX_BUFFER 2 +#define CSI_MAX_HEIGHT 8192U +#define CSI_MAX_WIDTH 8192U + +enum csi_input { + CSI_INPUT_RAW = 0, + CSI_INPUT_BT656 = 2, + CSI_INPUT_YUV = 3, +}; + +enum csi_output_raw { + CSI_OUTPUT_RAW_PASSTHROUGH = 0, +}; + +enum csi_output_yuv { + CSI_OUTPUT_YUV_422_PLANAR = 0, + CSI_OUTPUT_YUV_420_PLANAR = 1, + CSI_OUTPUT_YUV_422_UV = 4, + CSI_OUTPUT_YUV_420_UV = 5, + CSI_OUTPUT_YUV_422_MACRO = 8, + CSI_OUTPUT_YUV_420_MACRO = 9, +}; + +enum csi_yuv_data_seq { + CSI_YUV_DATA_SEQ_YUYV = 0, + CSI_YUV_DATA_SEQ_YVYU = 1, + CSI_YUV_DATA_SEQ_UYVY = 2, + CSI_YUV_DATA_SEQ_VYUY = 3, +}; + +enum csi_subdev_pads { + CSI_SUBDEV_SINK, + CSI_SUBDEV_SOURCE, + + CSI_SUBDEV_PADS, +}; + +extern const struct v4l2_subdev_ops sun4i_csi_subdev_ops; + +struct sun4i_csi_format { + u32 mbus; + u32 fourcc; + enum csi_input input; + u32 output; + unsigned int num_planes; + u8 bpp[3]; + unsigned int hsub; + unsigned int vsub; +}; + +const struct sun4i_csi_format *sun4i_csi_find_format(const u32 *fourcc, + const u32 *mbus); + +struct sun4i_csi { + /* Device resources */ + struct device *dev; + + void __iomem *regs; + struct clk *bus_clk; + struct clk *isp_clk; + struct clk *ram_clk; + struct reset_control *rst; + + struct vb2_v4l2_buffer *current_buf[CSI_MAX_BUFFER]; + + struct { + size_t size; + void *vaddr; + dma_addr_t paddr; + } scratch; + + struct v4l2_fwnode_bus_parallel bus; + + /* Main Device */ + struct v4l2_device v4l; + struct media_device mdev; + struct video_device vdev; + struct media_pad vdev_pad; + struct v4l2_pix_format_mplane fmt; + + /* Local subdev */ + struct v4l2_subdev subdev; + struct media_pad subdev_pads[CSI_SUBDEV_PADS]; + struct v4l2_mbus_framefmt subdev_fmt; + + /* V4L2 Async variables */ + struct v4l2_async_subdev asd; + struct v4l2_async_notifier notifier; + struct v4l2_subdev *src_subdev; + int src_pad; + + /* V4L2 variables */ + struct mutex lock; + + /* Videobuf2 */ + struct vb2_queue queue; + struct list_head buf_list; + spinlock_t qlock; + unsigned int sequence; +}; + +int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq); +void sun4i_csi_dma_unregister(struct sun4i_csi *csi); + +int sun4i_csi_v4l2_register(struct sun4i_csi *csi); + +#endif /* _SUN4I_CSI_H_ */ diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c new file mode 100644 index 000000000000..d6979e11a67b --- /dev/null +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 NextThing Co + * Copyright (C) 2016-2019 Bootlin + * + * Author: Maxime Ripard <maxime.ripard@bootlin.com> + */ + +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <media/videobuf2-dma-contig.h> +#include <media/videobuf2-v4l2.h> + +#include "sun4i_csi.h" + +struct sun4i_csi_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +static inline struct sun4i_csi_buffer * +vb2_v4l2_to_csi_buffer(const struct vb2_v4l2_buffer *p) +{ + return container_of(p, struct sun4i_csi_buffer, vb); +} + +static inline struct sun4i_csi_buffer * +vb2_to_csi_buffer(const struct vb2_buffer *p) +{ + return vb2_v4l2_to_csi_buffer(to_vb2_v4l2_buffer(p)); +} + +static void sun4i_csi_capture_start(struct sun4i_csi *csi) +{ + writel(CSI_CPT_CTRL_VIDEO_START, csi->regs + CSI_CPT_CTRL_REG); +} + +static void sun4i_csi_capture_stop(struct sun4i_csi *csi) +{ + writel(0, csi->regs + CSI_CPT_CTRL_REG); +} + +static int sun4i_csi_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct sun4i_csi *csi = vb2_get_drv_priv(vq); + unsigned int num_planes = csi->fmt.num_planes; + unsigned int i; + + if (*nplanes) { + if (*nplanes != num_planes) + return -EINVAL; + + for (i = 0; i < num_planes; i++) + if (sizes[i] < csi->fmt.plane_fmt[i].sizeimage) + return -EINVAL; + return 0; + } + + *nplanes = num_planes; + for (i = 0; i < num_planes; i++) + sizes[i] = csi->fmt.plane_fmt[i].sizeimage; + + return 0; +}; + +static int sun4i_csi_buffer_prepare(struct vb2_buffer *vb) +{ + struct sun4i_csi *csi = vb2_get_drv_priv(vb->vb2_queue); + unsigned int i; + + for (i = 0; i < csi->fmt.num_planes; i++) { + unsigned long size = csi->fmt.plane_fmt[i].sizeimage; + + if (vb2_plane_size(vb, i) < size) { + dev_err(csi->dev, "buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, i), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, i, size); + } + + return 0; +} + +static int sun4i_csi_setup_scratch_buffer(struct sun4i_csi *csi, + unsigned int slot) +{ + dma_addr_t addr = csi->scratch.paddr; + unsigned int plane; + + dev_dbg(csi->dev, + "No more available buffer, using the scratch buffer\n"); + + for (plane = 0; plane < csi->fmt.num_planes; plane++) { + writel(addr, csi->regs + CSI_BUF_ADDR_REG(plane, slot)); + addr += csi->fmt.plane_fmt[plane].sizeimage; + } + + csi->current_buf[slot] = NULL; + return 0; +} + +static int sun4i_csi_buffer_fill_slot(struct sun4i_csi *csi, unsigned int slot) +{ + struct sun4i_csi_buffer *c_buf; + struct vb2_v4l2_buffer *v_buf; + unsigned int plane; + + /* + * We should never end up in a situation where we overwrite an + * already filled slot. + */ + if (WARN_ON(csi->current_buf[slot])) + return -EINVAL; + + if (list_empty(&csi->buf_list)) + return sun4i_csi_setup_scratch_buffer(csi, slot); + + c_buf = list_first_entry(&csi->buf_list, struct sun4i_csi_buffer, list); + list_del_init(&c_buf->list); + + v_buf = &c_buf->vb; + csi->current_buf[slot] = v_buf; + + for (plane = 0; plane < csi->fmt.num_planes; plane++) { + dma_addr_t buf_addr; + + buf_addr = vb2_dma_contig_plane_dma_addr(&v_buf->vb2_buf, + plane); + writel(buf_addr, csi->regs + CSI_BUF_ADDR_REG(plane, slot)); + } + + return 0; +} + +static int sun4i_csi_buffer_fill_all(struct sun4i_csi *csi) +{ + unsigned int slot; + int ret; + + for (slot = 0; slot < CSI_MAX_BUFFER; slot++) { + ret = sun4i_csi_buffer_fill_slot(csi, slot); + if (ret) + return ret; + } + + return 0; +} + +static void sun4i_csi_buffer_mark_done(struct sun4i_csi *csi, + unsigned int slot, + unsigned int sequence) +{ + struct vb2_v4l2_buffer *v_buf; + + if (!csi->current_buf[slot]) { + dev_dbg(csi->dev, "Scratch buffer was used, ignoring..\n"); + return; + } + + v_buf = csi->current_buf[slot]; + v_buf->field = csi->fmt.field; + v_buf->sequence = sequence; + v_buf->vb2_buf.timestamp = ktime_get_ns(); + vb2_buffer_done(&v_buf->vb2_buf, VB2_BUF_STATE_DONE); + + csi->current_buf[slot] = NULL; +} + +static int sun4i_csi_buffer_flip(struct sun4i_csi *csi, unsigned int sequence) +{ + u32 reg = readl(csi->regs + CSI_BUF_CTRL_REG); + unsigned int next; + + /* Our next buffer is not the current buffer */ + next = !(reg & CSI_BUF_CTRL_DBS); + + /* Report the previous buffer as done */ + sun4i_csi_buffer_mark_done(csi, next, sequence); + + /* Put a new buffer in there */ + return sun4i_csi_buffer_fill_slot(csi, next); +} + +static void sun4i_csi_buffer_queue(struct vb2_buffer *vb) +{ + struct sun4i_csi *csi = vb2_get_drv_priv(vb->vb2_queue); + struct sun4i_csi_buffer *buf = vb2_to_csi_buffer(vb); + unsigned long flags; + + spin_lock_irqsave(&csi->qlock, flags); + list_add_tail(&buf->list, &csi->buf_list); + spin_unlock_irqrestore(&csi->qlock, flags); +} + +static void return_all_buffers(struct sun4i_csi *csi, + enum vb2_buffer_state state) +{ + struct sun4i_csi_buffer *buf, *node; + unsigned int slot; + + list_for_each_entry_safe(buf, node, &csi->buf_list, list) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->list); + } + + for (slot = 0; slot < CSI_MAX_BUFFER; slot++) { + struct vb2_v4l2_buffer *v_buf = csi->current_buf[slot]; + + if (!v_buf) + continue; + + vb2_buffer_done(&v_buf->vb2_buf, state); + csi->current_buf[slot] = NULL; + } +} + +static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct sun4i_csi *csi = vb2_get_drv_priv(vq); + struct v4l2_fwnode_bus_parallel *bus = &csi->bus; + const struct sun4i_csi_format *csi_fmt; + unsigned long hsync_pol, pclk_pol, vsync_pol; + unsigned long flags; + unsigned int i; + int ret; + + csi_fmt = sun4i_csi_find_format(&csi->fmt.pixelformat, NULL); + if (!csi_fmt) + return -EINVAL; + + dev_dbg(csi->dev, "Starting capture\n"); + + csi->sequence = 0; + + /* + * We need a scratch buffer in case where we'll not have any + * more buffer queued so that we don't error out. One of those + * cases is when you end up at the last frame to capture, you + * don't havea any buffer queued any more, and yet it doesn't + * really matter since you'll never reach the next buffer. + * + * Since we support the multi-planar API, we need to have a + * buffer for each plane. Allocating a single one large enough + * to hold all the buffers is simpler, so let's go for that. + */ + csi->scratch.size = 0; + for (i = 0; i < csi->fmt.num_planes; i++) + csi->scratch.size += csi->fmt.plane_fmt[i].sizeimage; + + csi->scratch.vaddr = dma_alloc_coherent(csi->dev, + csi->scratch.size, + &csi->scratch.paddr, + GFP_KERNEL); + if (!csi->scratch.vaddr) { + dev_err(csi->dev, "Failed to allocate scratch buffer\n"); + ret = -ENOMEM; + goto err_clear_dma_queue; + } + + ret = media_pipeline_start(&csi->vdev.entity, &csi->vdev.pipe); + if (ret < 0) + goto err_free_scratch_buffer; + + spin_lock_irqsave(&csi->qlock, flags); + + /* Setup timings */ + writel(CSI_WIN_CTRL_W_ACTIVE(csi->fmt.width * 2), + csi->regs + CSI_WIN_CTRL_W_REG); + writel(CSI_WIN_CTRL_H_ACTIVE(csi->fmt.height), + csi->regs + CSI_WIN_CTRL_H_REG); + + hsync_pol = !!(bus->flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH); + pclk_pol = !!(bus->flags & V4L2_MBUS_DATA_ACTIVE_HIGH); + vsync_pol = !!(bus->flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH); + writel(CSI_CFG_INPUT_FMT(csi_fmt->input) | + CSI_CFG_OUTPUT_FMT(csi_fmt->output) | + CSI_CFG_VSYNC_POL(vsync_pol) | + CSI_CFG_HSYNC_POL(hsync_pol) | + CSI_CFG_PCLK_POL(pclk_pol), + csi->regs + CSI_CFG_REG); + + /* Setup buffer length */ + writel(csi->fmt.plane_fmt[0].bytesperline, + csi->regs + CSI_BUF_LEN_REG); + + /* Prepare our buffers in hardware */ + ret = sun4i_csi_buffer_fill_all(csi); + if (ret) { + spin_unlock_irqrestore(&csi->qlock, flags); + goto err_disable_pipeline; + } + + /* Enable double buffering */ + writel(CSI_BUF_CTRL_DBE, csi->regs + CSI_BUF_CTRL_REG); + + /* Clear the pending interrupts */ + writel(CSI_INT_FRM_DONE, csi->regs + 0x34); + + /* Enable frame done interrupt */ + writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_EN_REG); + + sun4i_csi_capture_start(csi); + + spin_unlock_irqrestore(&csi->qlock, flags); + + ret = v4l2_subdev_call(csi->src_subdev, video, s_stream, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) + goto err_disable_device; + + return 0; + +err_disable_device: + sun4i_csi_capture_stop(csi); + +err_disable_pipeline: + media_pipeline_stop(&csi->vdev.entity); + +err_free_scratch_buffer: + dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr, + csi->scratch.paddr); + +err_clear_dma_queue: + spin_lock_irqsave(&csi->qlock, flags); + return_all_buffers(csi, VB2_BUF_STATE_QUEUED); + spin_unlock_irqrestore(&csi->qlock, flags); + + return ret; +} + +static void sun4i_csi_stop_streaming(struct vb2_queue *vq) +{ + struct sun4i_csi *csi = vb2_get_drv_priv(vq); + unsigned long flags; + + dev_dbg(csi->dev, "Stopping capture\n"); + + v4l2_subdev_call(csi->src_subdev, video, s_stream, 0); + sun4i_csi_capture_stop(csi); + + /* Release all active buffers */ + spin_lock_irqsave(&csi->qlock, flags); + return_all_buffers(csi, VB2_BUF_STATE_ERROR); + spin_unlock_irqrestore(&csi->qlock, flags); + + media_pipeline_stop(&csi->vdev.entity); + + dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr, + csi->scratch.paddr); +} + +static const struct vb2_ops sun4i_csi_qops = { + .queue_setup = sun4i_csi_queue_setup, + .buf_prepare = sun4i_csi_buffer_prepare, + .buf_queue = sun4i_csi_buffer_queue, + .start_streaming = sun4i_csi_start_streaming, + .stop_streaming = sun4i_csi_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static irqreturn_t sun4i_csi_irq(int irq, void *data) +{ + struct sun4i_csi *csi = data; + u32 reg; + + reg = readl(csi->regs + CSI_INT_STA_REG); + + /* Acknowledge the interrupts */ + writel(reg, csi->regs + CSI_INT_STA_REG); + + if (!(reg & CSI_INT_FRM_DONE)) + return IRQ_HANDLED; + + spin_lock(&csi->qlock); + if (sun4i_csi_buffer_flip(csi, csi->sequence++)) { + dev_warn(csi->dev, "%s: Flip failed\n", __func__); + sun4i_csi_capture_stop(csi); + } + spin_unlock(&csi->qlock); + + return IRQ_HANDLED; +} + +int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq) +{ + struct vb2_queue *q = &csi->queue; + int ret; + int i; + + spin_lock_init(&csi->qlock); + mutex_init(&csi->lock); + + INIT_LIST_HEAD(&csi->buf_list); + for (i = 0; i < CSI_MAX_BUFFER; i++) + csi->current_buf[i] = NULL; + + q->min_buffers_needed = 3; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_MMAP; + q->lock = &csi->lock; + q->drv_priv = csi; + q->buf_struct_size = sizeof(struct sun4i_csi_buffer); + q->ops = &sun4i_csi_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->dev = csi->dev; + + ret = vb2_queue_init(q); + if (ret < 0) { + dev_err(csi->dev, "failed to initialize VB2 queue\n"); + goto err_free_mutex; + } + + ret = v4l2_device_register(csi->dev, &csi->v4l); + if (ret) { + dev_err(csi->dev, "Couldn't register the v4l2 device\n"); + goto err_free_queue; + } + + ret = devm_request_irq(csi->dev, irq, sun4i_csi_irq, 0, + dev_name(csi->dev), csi); + if (ret) { + dev_err(csi->dev, "Couldn't register our interrupt\n"); + goto err_unregister_device; + } + + return 0; + +err_unregister_device: + v4l2_device_unregister(&csi->v4l); + +err_free_queue: + vb2_queue_release(q); + +err_free_mutex: + mutex_destroy(&csi->lock); + return ret; +} + +void sun4i_csi_dma_unregister(struct sun4i_csi *csi) +{ + v4l2_device_unregister(&csi->v4l); + vb2_queue_release(&csi->queue); + mutex_destroy(&csi->lock); +} diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c new file mode 100644 index 000000000000..83a3a0257c7b --- /dev/null +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 NextThing Co + * Copyright (C) 2016-2019 Bootlin + * + * Author: Maxime Ripard <maxime.ripard@bootlin.com> + */ + +#include <linux/device.h> +#include <linux/pm_runtime.h> + +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mc.h> +#include <media/videobuf2-v4l2.h> + +#include "sun4i_csi.h" + +#define CSI_DEFAULT_WIDTH 640 +#define CSI_DEFAULT_HEIGHT 480 + +static const struct sun4i_csi_format sun4i_csi_formats[] = { + /* YUV422 inputs */ + { + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + .fourcc = V4L2_PIX_FMT_YUV420M, + .input = CSI_INPUT_YUV, + .output = CSI_OUTPUT_YUV_420_PLANAR, + .num_planes = 3, + .bpp = { 8, 8, 8 }, + .hsub = 2, + .vsub = 2, + }, +}; + +const struct sun4i_csi_format *sun4i_csi_find_format(const u32 *fourcc, + const u32 *mbus) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sun4i_csi_formats); i++) { + if (fourcc && *fourcc != sun4i_csi_formats[i].fourcc) + continue; + + if (mbus && *mbus != sun4i_csi_formats[i].mbus) + continue; + + return &sun4i_csi_formats[i]; + } + + return NULL; +} + +static int sun4i_csi_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct sun4i_csi *csi = video_drvdata(file); + + strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->card, "sun4i-csi", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(csi->dev)); + + return 0; +} + +static int sun4i_csi_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + if (inp->index != 0) + return -EINVAL; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + strscpy(inp->name, "Camera", sizeof(inp->name)); + + return 0; +} + +static int sun4i_csi_g_input(struct file *file, void *fh, + unsigned int *i) +{ + *i = 0; + + return 0; +} + +static int sun4i_csi_s_input(struct file *file, void *fh, + unsigned int i) +{ + if (i != 0) + return -EINVAL; + + return 0; +} + +static void _sun4i_csi_try_fmt(struct sun4i_csi *csi, + struct v4l2_pix_format_mplane *pix) +{ + const struct sun4i_csi_format *_fmt; + unsigned int height, width; + unsigned int i; + + _fmt = sun4i_csi_find_format(&pix->pixelformat, NULL); + if (!_fmt) + _fmt = &sun4i_csi_formats[0]; + + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_SRGB; + pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace); + pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace); + pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace, + pix->ycbcr_enc); + + pix->num_planes = _fmt->num_planes; + pix->pixelformat = _fmt->fourcc; + + memset(pix->reserved, 0, sizeof(pix->reserved)); + + /* Align the width and height on the subsampling */ + width = ALIGN(pix->width, _fmt->hsub); + height = ALIGN(pix->height, _fmt->vsub); + + /* Clamp the width and height to our capabilities */ + pix->width = clamp(width, _fmt->hsub, CSI_MAX_WIDTH); + pix->height = clamp(height, _fmt->vsub, CSI_MAX_HEIGHT); + + for (i = 0; i < _fmt->num_planes; i++) { + unsigned int hsub = i > 0 ? _fmt->hsub : 1; + unsigned int vsub = i > 0 ? _fmt->vsub : 1; + unsigned int bpl; + + bpl = pix->width / hsub * _fmt->bpp[i] / 8; + pix->plane_fmt[i].bytesperline = bpl; + pix->plane_fmt[i].sizeimage = bpl * pix->height / vsub; + memset(pix->plane_fmt[i].reserved, 0, + sizeof(pix->plane_fmt[i].reserved)); + } +} + +static int sun4i_csi_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct sun4i_csi *csi = video_drvdata(file); + + _sun4i_csi_try_fmt(csi, &f->fmt.pix_mp); + + return 0; +} + +static int sun4i_csi_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct sun4i_csi *csi = video_drvdata(file); + + _sun4i_csi_try_fmt(csi, &f->fmt.pix_mp); + csi->fmt = f->fmt.pix_mp; + + return 0; +} + +static int sun4i_csi_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct sun4i_csi *csi = video_drvdata(file); + + f->fmt.pix_mp = csi->fmt; + + return 0; +} + +static int sun4i_csi_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index >= ARRAY_SIZE(sun4i_csi_formats)) + return -EINVAL; + + f->pixelformat = sun4i_csi_formats[f->index].fourcc; + + return 0; +} + +static const struct v4l2_ioctl_ops sun4i_csi_ioctl_ops = { + .vidioc_querycap = sun4i_csi_querycap, + + .vidioc_enum_fmt_vid_cap = sun4i_csi_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap_mplane = sun4i_csi_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap_mplane = sun4i_csi_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap_mplane = sun4i_csi_try_fmt_vid_cap, + + .vidioc_enum_input = sun4i_csi_enum_input, + .vidioc_g_input = sun4i_csi_g_input, + .vidioc_s_input = sun4i_csi_s_input, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static int sun4i_csi_open(struct file *file) +{ + struct sun4i_csi *csi = video_drvdata(file); + int ret; + + ret = mutex_lock_interruptible(&csi->lock); + if (ret) + return ret; + + ret = pm_runtime_get_sync(csi->dev); + if (ret < 0) + goto err_pm_put; + + ret = v4l2_pipeline_pm_use(&csi->vdev.entity, 1); + if (ret) + goto err_pm_put; + + ret = v4l2_fh_open(file); + if (ret) + goto err_pipeline_pm_put; + + mutex_unlock(&csi->lock); + + return 0; + +err_pipeline_pm_put: + v4l2_pipeline_pm_use(&csi->vdev.entity, 0); + +err_pm_put: + pm_runtime_put(csi->dev); + mutex_unlock(&csi->lock); + + return ret; +} + +static int sun4i_csi_release(struct file *file) +{ + struct sun4i_csi *csi = video_drvdata(file); + + mutex_lock(&csi->lock); + + v4l2_fh_release(file); + v4l2_pipeline_pm_use(&csi->vdev.entity, 0); + pm_runtime_put(csi->dev); + + mutex_unlock(&csi->lock); + + return 0; +} + +static const struct v4l2_file_operations sun4i_csi_fops = { + .owner = THIS_MODULE, + .open = sun4i_csi_open, + .release = sun4i_csi_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .write = vb2_fop_write, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +static const struct v4l2_mbus_framefmt sun4i_csi_pad_fmt_default = { + .width = CSI_DEFAULT_WIDTH, + .height = CSI_DEFAULT_HEIGHT, + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_RAW, + .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, + .quantization = V4L2_QUANTIZATION_DEFAULT, + .xfer_func = V4L2_XFER_FUNC_DEFAULT, +}; + +static int sun4i_csi_subdev_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg) +{ + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_get_try_format(subdev, cfg, CSI_SUBDEV_SINK); + *fmt = sun4i_csi_pad_fmt_default; + + return 0; +} + +static int sun4i_csi_subdev_get_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev); + struct v4l2_mbus_framefmt *subdev_fmt; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad); + else + subdev_fmt = &csi->subdev_fmt; + + fmt->format = *subdev_fmt; + + return 0; +} + +static int sun4i_csi_subdev_set_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev); + struct v4l2_mbus_framefmt *subdev_fmt; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad); + else + subdev_fmt = &csi->subdev_fmt; + + /* We can only set the format on the sink pad */ + if (fmt->pad == CSI_SUBDEV_SINK) { + /* It's the sink, only allow changing the frame size */ + subdev_fmt->width = fmt->format.width; + subdev_fmt->height = fmt->format.height; + subdev_fmt->code = fmt->format.code; + } + + fmt->format = *subdev_fmt; + + return 0; +} + +static int +sun4i_csi_subdev_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *mbus) +{ + if (mbus->index >= ARRAY_SIZE(sun4i_csi_formats)) + return -EINVAL; + + mbus->code = sun4i_csi_formats[mbus->index].mbus; + + return 0; +} + +static const struct v4l2_subdev_pad_ops sun4i_csi_subdev_pad_ops = { + .link_validate = v4l2_subdev_link_validate_default, + .init_cfg = sun4i_csi_subdev_init_cfg, + .get_fmt = sun4i_csi_subdev_get_fmt, + .set_fmt = sun4i_csi_subdev_set_fmt, + .enum_mbus_code = sun4i_csi_subdev_enum_mbus_code, +}; + +const struct v4l2_subdev_ops sun4i_csi_subdev_ops = { + .pad = &sun4i_csi_subdev_pad_ops, +}; + +int sun4i_csi_v4l2_register(struct sun4i_csi *csi) +{ + struct video_device *vdev = &csi->vdev; + int ret; + + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING; + vdev->v4l2_dev = &csi->v4l; + vdev->queue = &csi->queue; + strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name)); + vdev->release = video_device_release_empty; + vdev->lock = &csi->lock; + + /* Set a default format */ + csi->fmt.pixelformat = sun4i_csi_formats[0].fourcc, + csi->fmt.width = CSI_DEFAULT_WIDTH; + csi->fmt.height = CSI_DEFAULT_HEIGHT; + _sun4i_csi_try_fmt(csi, &csi->fmt); + csi->subdev_fmt = sun4i_csi_pad_fmt_default; + + vdev->fops = &sun4i_csi_fops; + vdev->ioctl_ops = &sun4i_csi_ioctl_ops; + video_set_drvdata(vdev, csi); + + ret = video_register_device(&csi->vdev, VFL_TYPE_GRABBER, -1); + if (ret) + return ret; + + dev_info(csi->dev, "Device registered as %s\n", + video_device_node_name(vdev)); + + return 0; +} diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 6e0e894154f4..055eb0b8e396 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -866,11 +866,8 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "No csi IRQ specified\n"); - ret = -ENXIO; - return ret; - } + if (irq < 0) + return -ENXIO; ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, MODULE_NAME, sdev); diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c index 6498b2d0492e..a632602131f2 100644 --- a/drivers/media/platform/tegra-cec/tegra_cec.c +++ b/drivers/media/platform/tegra-cec/tegra_cec.c @@ -380,38 +380,39 @@ static int tegra_cec_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Unable to request interrupt for device\n"); - goto clk_error; - } - - cec->notifier = cec_notifier_get(hdmi_dev); - if (!cec->notifier) { - ret = -ENOMEM; - goto clk_error; + goto err_clk; } cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME, - CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL, + CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | + CEC_CAP_CONNECTOR_INFO, CEC_MAX_LOG_ADDRS); if (IS_ERR(cec->adap)) { ret = -ENOMEM; dev_err(&pdev->dev, "Couldn't create cec adapter\n"); - goto cec_error; + goto err_clk; + } + + cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL, + cec->adap); + if (!cec->notifier) { + ret = -ENOMEM; + goto err_adapter; } + ret = cec_register_adapter(cec->adap, &pdev->dev); if (ret) { dev_err(&pdev->dev, "Couldn't register device\n"); - goto cec_error; + goto err_notifier; } - cec_register_cec_notifier(cec->adap, cec->notifier); - return 0; -cec_error: - if (cec->notifier) - cec_notifier_put(cec->notifier); +err_notifier: + cec_notifier_cec_adap_unregister(cec->notifier); +err_adapter: cec_delete_adapter(cec->adap); -clk_error: +err_clk: clk_disable_unprepare(cec->clk); return ret; } @@ -422,8 +423,8 @@ static int tegra_cec_remove(struct platform_device *pdev) clk_disable_unprepare(cec->clk); + cec_notifier_cec_adap_unregister(cec->notifier); cec_unregister_adapter(cec->adap); - cec_notifier_put(cec->notifier); return 0; } diff --git a/drivers/media/platform/tegra-cec/tegra_cec.h b/drivers/media/platform/tegra-cec/tegra_cec.h index 32d7d69f9491..8c370be38e1e 100644 --- a/drivers/media/platform/tegra-cec/tegra_cec.h +++ b/drivers/media/platform/tegra-cec/tegra_cec.h @@ -34,24 +34,24 @@ #define TEGRA_CEC_HWCTRL_RX_LADDR_MASK 0x7fff #define TEGRA_CEC_HWCTRL_RX_LADDR(x) \ ((x) & TEGRA_CEC_HWCTRL_RX_LADDR_MASK) -#define TEGRA_CEC_HWCTRL_RX_SNOOP (1 << 15) -#define TEGRA_CEC_HWCTRL_RX_NAK_MODE (1 << 16) -#define TEGRA_CEC_HWCTRL_TX_NAK_MODE (1 << 24) -#define TEGRA_CEC_HWCTRL_FAST_SIM_MODE (1 << 30) -#define TEGRA_CEC_HWCTRL_TX_RX_MODE (1 << 31) +#define TEGRA_CEC_HWCTRL_RX_SNOOP BIT(15) +#define TEGRA_CEC_HWCTRL_RX_NAK_MODE BIT(16) +#define TEGRA_CEC_HWCTRL_TX_NAK_MODE BIT(24) +#define TEGRA_CEC_HWCTRL_FAST_SIM_MODE BIT(30) +#define TEGRA_CEC_HWCTRL_TX_RX_MODE BIT(31) -#define TEGRA_CEC_INPUT_FILTER_MODE (1 << 31) +#define TEGRA_CEC_INPUT_FILTER_MODE BIT(31) #define TEGRA_CEC_INPUT_FILTER_FIFO_LENGTH_SHIFT 0 #define TEGRA_CEC_TX_REG_DATA_SHIFT 0 -#define TEGRA_CEC_TX_REG_EOM (1 << 8) -#define TEGRA_CEC_TX_REG_BCAST (1 << 12) -#define TEGRA_CEC_TX_REG_START_BIT (1 << 16) -#define TEGRA_CEC_TX_REG_RETRY (1 << 17) +#define TEGRA_CEC_TX_REG_EOM BIT(8) +#define TEGRA_CEC_TX_REG_BCAST BIT(12) +#define TEGRA_CEC_TX_REG_START_BIT BIT(16) +#define TEGRA_CEC_TX_REG_RETRY BIT(17) #define TEGRA_CEC_RX_REGISTER_SHIFT 0 -#define TEGRA_CEC_RX_REGISTER_EOM (1 << 8) -#define TEGRA_CEC_RX_REGISTER_ACK (1 << 9) +#define TEGRA_CEC_RX_REGISTER_EOM BIT(8) +#define TEGRA_CEC_RX_REGISTER_ACK BIT(9) #define TEGRA_CEC_RX_TIM0_START_BIT_MAX_LO_TIME_SHIFT 0 #define TEGRA_CEC_RX_TIM0_START_BIT_MIN_LO_TIME_SHIFT 8 @@ -79,38 +79,38 @@ #define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_NEW_FRAME_SHIFT 4 #define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_RETRY_FRAME_SHIFT 8 -#define TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY (1 << 0) -#define TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN (1 << 1) -#define TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD (1 << 2) -#define TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED (1 << 3) -#define TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED (1 << 4) -#define TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED (1 << 5) -#define TEGRA_CEC_INT_STAT_RX_REGISTER_FULL (1 << 8) -#define TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN (1 << 9) -#define TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED (1 << 10) -#define TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED (1 << 11) -#define TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED (1 << 12) -#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_H2L (1 << 13) -#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_L2H (1 << 14) - -#define TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY (1 << 0) -#define TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN (1 << 1) -#define TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD (1 << 2) -#define TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED (1 << 3) -#define TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED (1 << 4) -#define TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED (1 << 5) -#define TEGRA_CEC_INT_MASK_RX_REGISTER_FULL (1 << 8) -#define TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN (1 << 9) -#define TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED (1 << 10) -#define TEGRA_CEC_INT_MASK_RX_BUS_ANOMALY_DETECTED (1 << 11) -#define TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED (1 << 12) -#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_H2L (1 << 13) -#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_L2H (1 << 14) +#define TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY BIT(0) +#define TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN BIT(1) +#define TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD BIT(2) +#define TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED BIT(3) +#define TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED BIT(4) +#define TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED BIT(5) +#define TEGRA_CEC_INT_STAT_RX_REGISTER_FULL BIT(8) +#define TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN BIT(9) +#define TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED BIT(10) +#define TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED BIT(11) +#define TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED BIT(12) +#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_H2L BIT(13) +#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_L2H BIT(14) + +#define TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY BIT(0) +#define TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN BIT(1) +#define TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD BIT(2) +#define TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED BIT(3) +#define TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED BIT(4) +#define TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED BIT(5) +#define TEGRA_CEC_INT_MASK_RX_REGISTER_FULL BIT(8) +#define TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN BIT(9) +#define TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED BIT(10) +#define TEGRA_CEC_INT_MASK_RX_BUS_ANOMALY_DETECTED BIT(11) +#define TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED BIT(12) +#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_H2L BIT(13) +#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_L2H BIT(14) #define TEGRA_CEC_HW_DEBUG_TX_DURATION_COUNT_SHIFT 0 #define TEGRA_CEC_HW_DEBUG_TX_TXBIT_COUNT_SHIFT 17 #define TEGRA_CEC_HW_DEBUG_TX_STATE_SHIFT 21 -#define TEGRA_CEC_HW_DEBUG_TX_FORCELOOUT (1 << 25) -#define TEGRA_CEC_HW_DEBUG_TX_TXDATABIT_SAMPLE_TIMER (1 << 26) +#define TEGRA_CEC_HW_DEBUG_TX_FORCELOOUT BIT(25) +#define TEGRA_CEC_HW_DEBUG_TX_TXDATABIT_SAMPLE_TIMER BIT(26) #endif /* TEGRA_CEC_H */ diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 9e86d761546b..223161f9c403 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -913,9 +913,6 @@ static int cal_querycap(struct file *file, void *priv, snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", ctx->v4l2_dev.name); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1419,6 +1416,8 @@ static const struct video_device cal_videodev = { .ioctl_ops = &cal_ioctl_ops, .minor = -1, .release = video_device_release_empty, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE, }; /* ----------------------------------------------------------------- @@ -1613,6 +1612,7 @@ of_get_next_port(const struct device_node *parent, } prev = port; } while (!of_node_name_eq(port, "port")); + of_node_put(ports); } return port; diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index fd37d79e1619..53d27cd6e10a 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -445,23 +445,25 @@ int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num, ret = vpdma_map_desc_buf(vpdma, &abort_list.buf); if (ret) - return ret; + goto free_desc; ret = vpdma_submit_descs(vpdma, &abort_list, list_num); if (ret) - return ret; + goto unmap_desc; while (vpdma_list_busy(vpdma, list_num) && --timeout) ; if (timeout == 0) { dev_err(&vpdma->pdev->dev, "Timed out cleaning up VPDMA list\n"); - return -EBUSY; + ret = -EBUSY; } +unmap_desc: vpdma_unmap_desc_buf(vpdma, &abort_list.buf); +free_desc: vpdma_free_desc_buf(&abort_list.buf); - return 0; + return ret; } EXPORT_SYMBOL(vpdma_list_cleanup); diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index dda04498ac56..60b575bb44c4 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -224,7 +224,6 @@ static const struct vpe_port_data port_data[11] = { /* driver info for each of the supported video formats */ struct vpe_fmt { - char *name; /* human-readable name */ u32 fourcc; /* standard format identifier */ u8 types; /* CAPTURE and/or OUTPUT */ u8 coplanar; /* set for unpacked Luma and Chroma */ @@ -234,7 +233,6 @@ struct vpe_fmt { static struct vpe_fmt vpe_formats[] = { { - .name = "NV16 YUV 422 co-planar", .fourcc = V4L2_PIX_FMT_NV16, .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, .coplanar = 1, @@ -243,7 +241,6 @@ static struct vpe_fmt vpe_formats[] = { }, }, { - .name = "NV12 YUV 420 co-planar", .fourcc = V4L2_PIX_FMT_NV12, .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, .coplanar = 1, @@ -252,7 +249,6 @@ static struct vpe_fmt vpe_formats[] = { }, }, { - .name = "YUYV 422 packed", .fourcc = V4L2_PIX_FMT_YUYV, .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, .coplanar = 0, @@ -260,7 +256,6 @@ static struct vpe_fmt vpe_formats[] = { }, }, { - .name = "UYVY 422 packed", .fourcc = V4L2_PIX_FMT_UYVY, .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, .coplanar = 0, @@ -268,7 +263,6 @@ static struct vpe_fmt vpe_formats[] = { }, }, { - .name = "RGB888 packed", .fourcc = V4L2_PIX_FMT_RGB24, .types = VPE_FMT_TYPE_CAPTURE, .coplanar = 0, @@ -276,7 +270,6 @@ static struct vpe_fmt vpe_formats[] = { }, }, { - .name = "ARGB32", .fourcc = V4L2_PIX_FMT_RGB32, .types = VPE_FMT_TYPE_CAPTURE, .coplanar = 0, @@ -284,7 +277,6 @@ static struct vpe_fmt vpe_formats[] = { }, }, { - .name = "BGR888 packed", .fourcc = V4L2_PIX_FMT_BGR24, .types = VPE_FMT_TYPE_CAPTURE, .coplanar = 0, @@ -292,7 +284,6 @@ static struct vpe_fmt vpe_formats[] = { }, }, { - .name = "ABGR32", .fourcc = V4L2_PIX_FMT_BGR32, .types = VPE_FMT_TYPE_CAPTURE, .coplanar = 0, @@ -300,7 +291,6 @@ static struct vpe_fmt vpe_formats[] = { }, }, { - .name = "RGB565", .fourcc = V4L2_PIX_FMT_RGB565, .types = VPE_FMT_TYPE_CAPTURE, .coplanar = 0, @@ -308,7 +298,6 @@ static struct vpe_fmt vpe_formats[] = { }, }, { - .name = "RGB5551", .fourcc = V4L2_PIX_FMT_RGB555, .types = VPE_FMT_TYPE_CAPTURE, .coplanar = 0, @@ -1514,7 +1503,6 @@ static int __enum_fmt(struct v4l2_fmtdesc *f, u32 type) if (!fmt) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; } diff --git a/drivers/media/platform/ti-vpe/vpe_regs.h b/drivers/media/platform/ti-vpe/vpe_regs.h index 9969bea0dded..1a1ad5ae1228 100644 --- a/drivers/media/platform/ti-vpe/vpe_regs.h +++ b/drivers/media/platform/ti-vpe/vpe_regs.h @@ -48,24 +48,24 @@ #define VPE_INT0_ENABLE0_SET 0x0030 #define VPE_INT0_ENABLE0 VPE_INT0_ENABLE0_SET #define VPE_INT0_ENABLE0_CLR 0x0038 -#define VPE_INT0_LIST0_COMPLETE (1 << 0) -#define VPE_INT0_LIST0_NOTIFY (1 << 1) -#define VPE_INT0_LIST1_COMPLETE (1 << 2) -#define VPE_INT0_LIST1_NOTIFY (1 << 3) -#define VPE_INT0_LIST2_COMPLETE (1 << 4) -#define VPE_INT0_LIST2_NOTIFY (1 << 5) -#define VPE_INT0_LIST3_COMPLETE (1 << 6) -#define VPE_INT0_LIST3_NOTIFY (1 << 7) -#define VPE_INT0_LIST4_COMPLETE (1 << 8) -#define VPE_INT0_LIST4_NOTIFY (1 << 9) -#define VPE_INT0_LIST5_COMPLETE (1 << 10) -#define VPE_INT0_LIST5_NOTIFY (1 << 11) -#define VPE_INT0_LIST6_COMPLETE (1 << 12) -#define VPE_INT0_LIST6_NOTIFY (1 << 13) -#define VPE_INT0_LIST7_COMPLETE (1 << 14) -#define VPE_INT0_LIST7_NOTIFY (1 << 15) -#define VPE_INT0_DESCRIPTOR (1 << 16) -#define VPE_DEI_FMD_INT (1 << 18) +#define VPE_INT0_LIST0_COMPLETE BIT(0) +#define VPE_INT0_LIST0_NOTIFY BIT(1) +#define VPE_INT0_LIST1_COMPLETE BIT(2) +#define VPE_INT0_LIST1_NOTIFY BIT(3) +#define VPE_INT0_LIST2_COMPLETE BIT(4) +#define VPE_INT0_LIST2_NOTIFY BIT(5) +#define VPE_INT0_LIST3_COMPLETE BIT(6) +#define VPE_INT0_LIST3_NOTIFY BIT(7) +#define VPE_INT0_LIST4_COMPLETE BIT(8) +#define VPE_INT0_LIST4_NOTIFY BIT(9) +#define VPE_INT0_LIST5_COMPLETE BIT(10) +#define VPE_INT0_LIST5_NOTIFY BIT(11) +#define VPE_INT0_LIST6_COMPLETE BIT(12) +#define VPE_INT0_LIST6_NOTIFY BIT(13) +#define VPE_INT0_LIST7_COMPLETE BIT(14) +#define VPE_INT0_LIST7_NOTIFY BIT(15) +#define VPE_INT0_DESCRIPTOR BIT(16) +#define VPE_DEI_FMD_INT BIT(18) #define VPE_INT0_STATUS1_RAW_SET 0x0024 #define VPE_INT0_STATUS1_RAW VPE_INT0_STATUS1_RAW_SET @@ -74,21 +74,21 @@ #define VPE_INT0_ENABLE1_SET 0x0034 #define VPE_INT0_ENABLE1 VPE_INT0_ENABLE1_SET #define VPE_INT0_ENABLE1_CLR 0x003c -#define VPE_INT0_CHANNEL_GROUP0 (1 << 0) -#define VPE_INT0_CHANNEL_GROUP1 (1 << 1) -#define VPE_INT0_CHANNEL_GROUP2 (1 << 2) -#define VPE_INT0_CHANNEL_GROUP3 (1 << 3) -#define VPE_INT0_CHANNEL_GROUP4 (1 << 4) -#define VPE_INT0_CHANNEL_GROUP5 (1 << 5) -#define VPE_INT0_CLIENT (1 << 7) -#define VPE_DEI_ERROR_INT (1 << 16) -#define VPE_DS1_UV_ERROR_INT (1 << 22) +#define VPE_INT0_CHANNEL_GROUP0 BIT(0) +#define VPE_INT0_CHANNEL_GROUP1 BIT(1) +#define VPE_INT0_CHANNEL_GROUP2 BIT(2) +#define VPE_INT0_CHANNEL_GROUP3 BIT(3) +#define VPE_INT0_CHANNEL_GROUP4 BIT(4) +#define VPE_INT0_CHANNEL_GROUP5 BIT(5) +#define VPE_INT0_CLIENT BIT(7) +#define VPE_DEI_ERROR_INT BIT(16) +#define VPE_DS1_UV_ERROR_INT BIT(22) #define VPE_INTC_EOI 0x00a0 #define VPE_CLK_ENABLE 0x0100 -#define VPE_VPEDMA_CLK_ENABLE (1 << 0) -#define VPE_DATA_PATH_CLK_ENABLE (1 << 1) +#define VPE_VPEDMA_CLK_ENABLE BIT(0) +#define VPE_DATA_PATH_CLK_ENABLE BIT(1) #define VPE_CLK_RESET 0x0104 #define VPE_VPDMA_CLK_RESET_MASK 0x1 @@ -101,11 +101,11 @@ #define VPE_CLK_FORMAT_SELECT 0x010c #define VPE_CSC_SRC_SELECT_MASK 0x03 #define VPE_CSC_SRC_SELECT_SHIFT 0 -#define VPE_RGB_OUT_SELECT (1 << 8) +#define VPE_RGB_OUT_SELECT BIT(8) #define VPE_DS_SRC_SELECT_MASK 0x07 #define VPE_DS_SRC_SELECT_SHIFT 9 -#define VPE_DS_BYPASS (1 << 16) -#define VPE_COLOR_SEPARATE_422 (1 << 18) +#define VPE_DS_BYPASS BIT(16) +#define VPE_COLOR_SEPARATE_422 BIT(18) #define VPE_DS_SRC_DEI_SCALER (5 << VPE_DS_SRC_SELECT_SHIFT) #define VPE_CSC_SRC_DEI_SCALER (3 << VPE_CSC_SRC_SELECT_SHIFT) @@ -115,8 +115,8 @@ #define VPE_RANGE_RANGE_MAP_Y_SHIFT 0 #define VPE_RANGE_RANGE_MAP_UV_MASK 0x07 #define VPE_RANGE_RANGE_MAP_UV_SHIFT 3 -#define VPE_RANGE_MAP_ON (1 << 6) -#define VPE_RANGE_REDUCTION_ON (1 << 28) +#define VPE_RANGE_MAP_ON BIT(6) +#define VPE_RANGE_REDUCTION_ON BIT(28) /* VPE chrominance upsampler regs */ #define VPE_US1_R0 0x0304 @@ -195,13 +195,13 @@ #define VPE_DEI_WIDTH_SHIFT 0 #define VPE_DEI_HEIGHT_MASK 0x07ff #define VPE_DEI_HEIGHT_SHIFT 16 -#define VPE_DEI_INTERLACE_BYPASS (1 << 29) -#define VPE_DEI_FIELD_FLUSH (1 << 30) -#define VPE_DEI_PROGRESSIVE (1 << 31) +#define VPE_DEI_INTERLACE_BYPASS BIT(29) +#define VPE_DEI_FIELD_FLUSH BIT(30) +#define VPE_DEI_PROGRESSIVE BIT(31) #define VPE_MDT_BYPASS 0x0604 -#define VPE_MDT_TEMPMAX_BYPASS (1 << 0) -#define VPE_MDT_SPATMAX_BYPASS (1 << 1) +#define VPE_MDT_TEMPMAX_BYPASS BIT(0) +#define VPE_MDT_SPATMAX_BYPASS BIT(1) #define VPE_MDT_SF_THRESHOLD 0x0608 #define VPE_MDT_SF_SC_THR1_MASK 0xff @@ -214,8 +214,8 @@ #define VPE_EDI_CONFIG 0x060c #define VPE_EDI_INP_MODE_MASK 0x03 #define VPE_EDI_INP_MODE_SHIFT 0 -#define VPE_EDI_ENABLE_3D (1 << 2) -#define VPE_EDI_ENABLE_CHROMA_3D (1 << 3) +#define VPE_EDI_ENABLE_3D BIT(2) +#define VPE_EDI_ENABLE_CHROMA_3D BIT(3) #define VPE_EDI_CHROMA3D_COR_THR_MASK 0xff #define VPE_EDI_CHROMA3D_COR_THR_SHIFT 8 #define VPE_EDI_DIR_COR_LOWER_THR_MASK 0xff @@ -268,7 +268,7 @@ #define VPE_FMD_WINDOW_MINX_SHIFT 0 #define VPE_FMD_WINDOW_MAXX_MASK 0x07ff #define VPE_FMD_WINDOW_MAXX_SHIFT 16 -#define VPE_FMD_WINDOW_ENABLE (1 << 31) +#define VPE_FMD_WINDOW_ENABLE BIT(31) #define VPE_DEI_FMD_WINDOW_R1 0x0624 #define VPE_FMD_WINDOW_MINY_MASK 0x07ff @@ -277,10 +277,10 @@ #define VPE_FMD_WINDOW_MAXY_SHIFT 16 #define VPE_DEI_FMD_CONTROL_R0 0x0628 -#define VPE_FMD_ENABLE (1 << 0) -#define VPE_FMD_LOCK (1 << 1) -#define VPE_FMD_JAM_DIR (1 << 2) -#define VPE_FMD_BED_ENABLE (1 << 3) +#define VPE_FMD_ENABLE BIT(0) +#define VPE_FMD_LOCK BIT(1) +#define VPE_FMD_JAM_DIR BIT(2) +#define VPE_FMD_BED_ENABLE BIT(3) #define VPE_FMD_CAF_FIELD_THR_MASK 0xff #define VPE_FMD_CAF_FIELD_THR_SHIFT 16 #define VPE_FMD_CAF_LINE_THR_MASK 0xff @@ -293,7 +293,7 @@ #define VPE_DEI_FMD_STATUS_R0 0x0630 #define VPE_FMD_CAF_MASK 0x000fffff #define VPE_FMD_CAF_SHIFT 0 -#define VPE_FMD_RESET (1 << 24) +#define VPE_FMD_RESET BIT(24) #define VPE_DEI_FMD_STATUS_R1 0x0634 #define VPE_FMD_FIELD_DIFF_MASK 0x0fffffff diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index 038de7a2027a..78841b9015ce 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -18,9 +18,10 @@ #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> #include <media/v4l2-image-sizes.h> #include <media/i2c/ov7670.h> -#include <media/videobuf-dma-sg.h> +#include <media/videobuf2-dma-sg.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/pm_qos.h> @@ -84,16 +85,11 @@ struct via_camera { * live in frame buffer memory, so we don't call them "DMA". */ unsigned int cb_offsets[3]; /* offsets into fb mem */ - u8 __iomem *cb_addrs[3]; /* Kernel-space addresses */ + u8 __iomem *cb_addrs[3]; /* Kernel-space addresses */ int n_cap_bufs; /* How many are we using? */ - int next_buf; - struct videobuf_queue vb_queue; - struct list_head buffer_queue; /* prot. by reg_lock */ - /* - * User tracking. - */ - int users; - struct file *owner; + struct vb2_queue vq; + struct list_head buffer_queue; + u32 sequence; /* * Video format information. sensor_format is kept in a form * that we can use to pass to the sensor. We always run the @@ -106,6 +102,13 @@ struct via_camera { u32 mbus_code; }; +/* buffer for one video frame */ +struct via_buffer { + /* common v4l buffer stuff -- must be first */ + struct vb2_v4l2_buffer vbuf; + struct list_head queue; +}; + /* * Yes, this is a hack, but there's only going to be one of these * on any system we know of. @@ -142,13 +145,11 @@ static struct via_camera *via_cam_info; * now this information must be managed at this level too. */ static struct via_format { - __u8 *desc; __u32 pixelformat; int bpp; /* Bytes per pixel */ u32 mbus_code; } via_formats[] = { { - .desc = "YUYV 4:2:2", .pixelformat = V4L2_PIX_FMT_YUYV, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, @@ -324,28 +325,15 @@ static irqreturn_t viacam_quick_irq(int irq, void *data) } /* - * Find the next videobuf buffer which has somebody waiting on it. + * Find the next buffer which has somebody waiting on it. */ -static struct videobuf_buffer *viacam_next_buffer(struct via_camera *cam) +static struct via_buffer *viacam_next_buffer(struct via_camera *cam) { - unsigned long flags; - struct videobuf_buffer *buf = NULL; - - spin_lock_irqsave(&cam->viadev->reg_lock, flags); if (cam->opstate != S_RUNNING) - goto out; + return NULL; if (list_empty(&cam->buffer_queue)) - goto out; - buf = list_entry(cam->buffer_queue.next, struct videobuf_buffer, queue); - if (!waitqueue_active(&buf->done)) {/* Nobody waiting */ - buf = NULL; - goto out; - } - list_del(&buf->queue); - buf->state = VIDEOBUF_ACTIVE; -out: - spin_unlock_irqrestore(&cam->viadev->reg_lock, flags); - return buf; + return NULL; + return list_entry(cam->buffer_queue.next, struct via_buffer, queue); } /* @@ -353,11 +341,12 @@ out: */ static irqreturn_t viacam_irq(int irq, void *data) { - int bufn; - struct videobuf_buffer *vb; struct via_camera *cam = data; - struct videobuf_dmabuf *vdma; + struct via_buffer *vb; + int bufn; + struct sg_table *sgt; + mutex_lock(&cam->lock); /* * If there is no place to put the data frame, don't bother * with anything else. @@ -375,12 +364,15 @@ static irqreturn_t viacam_irq(int irq, void *data) /* * Copy over the data and let any waiters know. */ - vdma = videobuf_to_dma(vb); - viafb_dma_copy_out_sg(cam->cb_offsets[bufn], vdma->sglist, vdma->sglen); - vb->state = VIDEOBUF_DONE; - vb->size = cam->user_format.sizeimage; - wake_up(&vb->done); + sgt = vb2_dma_sg_plane_desc(&vb->vbuf.vb2_buf, 0); + vb->vbuf.vb2_buf.timestamp = ktime_get_ns(); + viafb_dma_copy_out_sg(cam->cb_offsets[bufn], sgt->sgl, sgt->nents); + vb->vbuf.sequence = cam->sequence++; + vb->vbuf.field = V4L2_FIELD_NONE; + list_del(&vb->queue); + vb2_buffer_done(&vb->vbuf.vb2_buf, VB2_BUF_STATE_DONE); done: + mutex_unlock(&cam->lock); return IRQ_HANDLED; } @@ -556,7 +548,6 @@ static int viacam_config_controller(struct via_camera *cam) static void viacam_start_engine(struct via_camera *cam) { spin_lock_irq(&cam->viadev->reg_lock); - cam->next_buf = 0; viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_ENABLE, VCR_CI_ENABLE); viacam_int_enable(cam); (void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */ @@ -577,81 +568,117 @@ static void viacam_stop_engine(struct via_camera *cam) /* --------------------------------------------------------------------------*/ -/* Videobuf callback ops */ +/* vb2 callback ops */ -/* - * buffer_setup. The purpose of this one would appear to be to tell - * videobuf how big a single image is. It's also evidently up to us - * to put some sort of limit on the maximum number of buffers allowed. - */ -static int viacam_vb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) +static struct via_buffer *vb2_to_via_buffer(struct vb2_buffer *vb) { - struct via_camera *cam = q->priv_data; + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - *size = cam->user_format.sizeimage; - if (*count == 0 || *count > 6) /* Arbitrary number */ - *count = 6; - return 0; + return container_of(vbuf, struct via_buffer, vbuf); } -/* - * Prepare a buffer. - */ -static int viacam_vb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) +static void viacam_vb2_queue(struct vb2_buffer *vb) { - struct via_camera *cam = q->priv_data; - - vb->size = cam->user_format.sizeimage; - vb->width = cam->user_format.width; /* bytesperline???? */ - vb->height = cam->user_format.height; - vb->field = field; - if (vb->state == VIDEOBUF_NEEDS_INIT) { - int ret = videobuf_iolock(q, vb, NULL); - if (ret) - return ret; + struct via_camera *cam = vb2_get_drv_priv(vb->vb2_queue); + struct via_buffer *via = vb2_to_via_buffer(vb); + + list_add_tail(&via->queue, &cam->buffer_queue); +} + +static int viacam_vb2_prepare(struct vb2_buffer *vb) +{ + struct via_camera *cam = vb2_get_drv_priv(vb->vb2_queue); + + if (vb2_plane_size(vb, 0) < cam->user_format.sizeimage) { + cam_dbg(cam, + "Plane size too small (%lu < %u)\n", + vb2_plane_size(vb, 0), + cam->user_format.sizeimage); + return -EINVAL; } - vb->state = VIDEOBUF_PREPARED; + + vb2_set_plane_payload(vb, 0, cam->user_format.sizeimage); + return 0; } -/* - * We've got a buffer to put data into. - * - * FIXME: check for a running engine and valid buffers? - */ -static void viacam_vb_buf_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static int viacam_vb2_queue_setup(struct vb2_queue *vq, + unsigned int *nbufs, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) { - struct via_camera *cam = q->priv_data; + struct via_camera *cam = vb2_get_drv_priv(vq); + int size = cam->user_format.sizeimage; + if (*num_planes) + return sizes[0] < size ? -EINVAL : 0; + + *num_planes = 1; + sizes[0] = size; + return 0; +} + +static int viacam_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct via_camera *cam = vb2_get_drv_priv(vq); + struct via_buffer *buf, *tmp; + int ret = 0; + + if (cam->opstate != S_IDLE) { + ret = -EBUSY; + goto out; + } + /* + * Configure things if need be. + */ + if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) { + ret = viacam_configure_sensor(cam); + if (ret) + goto out; + ret = viacam_config_controller(cam); + if (ret) + goto out; + } + cam->sequence = 0; /* - * Note that videobuf holds the lock when it calls - * us, so we need not (indeed, cannot) take it here. + * If the CPU goes into C3, the DMA transfer gets corrupted and + * users start filing unsightly bug reports. Put in a "latency" + * requirement which will keep the CPU out of the deeper sleep + * states. */ - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &cam->buffer_queue); + pm_qos_add_request(&cam->qos_request, PM_QOS_CPU_DMA_LATENCY, 50); + viacam_start_engine(cam); + return 0; +out: + list_for_each_entry_safe(buf, tmp, &cam->buffer_queue, queue) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); + } + return ret; } -/* - * Free a buffer. - */ -static void viacam_vb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void viacam_vb2_stop_streaming(struct vb2_queue *vq) { - struct via_camera *cam = q->priv_data; + struct via_camera *cam = vb2_get_drv_priv(vq); + struct via_buffer *buf, *tmp; - videobuf_dma_unmap(&cam->platdev->dev, videobuf_to_dma(vb)); - videobuf_dma_free(videobuf_to_dma(vb)); - vb->state = VIDEOBUF_NEEDS_INIT; + pm_qos_remove_request(&cam->qos_request); + viacam_stop_engine(cam); + + list_for_each_entry_safe(buf, tmp, &cam->buffer_queue, queue) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); + } } -static const struct videobuf_queue_ops viacam_vb_ops = { - .buf_setup = viacam_vb_buf_setup, - .buf_prepare = viacam_vb_buf_prepare, - .buf_queue = viacam_vb_buf_queue, - .buf_release = viacam_vb_buf_release, +static const struct vb2_ops viacam_vb2_ops = { + .queue_setup = viacam_vb2_queue_setup, + .buf_queue = viacam_vb2_queue, + .buf_prepare = viacam_vb2_prepare, + .start_streaming = viacam_vb2_start_streaming, + .stop_streaming = viacam_vb2_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; /* --------------------------------------------------------------------------*/ @@ -660,62 +687,43 @@ static const struct videobuf_queue_ops viacam_vb_ops = { static int viacam_open(struct file *filp) { struct via_camera *cam = video_drvdata(filp); + int ret; - filp->private_data = cam; /* * Note the new user. If this is the first one, we'll also * need to power up the sensor. */ mutex_lock(&cam->lock); - if (cam->users == 0) { - int ret = viafb_request_dma(); + ret = v4l2_fh_open(filp); + if (ret) + goto out; + if (v4l2_fh_is_singular_file(filp)) { + ret = viafb_request_dma(); if (ret) { - mutex_unlock(&cam->lock); - return ret; + v4l2_fh_release(filp); + goto out; } via_sensor_power_up(cam); set_bit(CF_CONFIG_NEEDED, &cam->flags); - /* - * Hook into videobuf. Evidently this cannot fail. - */ - videobuf_queue_sg_init(&cam->vb_queue, &viacam_vb_ops, - &cam->platdev->dev, &cam->viadev->reg_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - sizeof(struct videobuf_buffer), cam, NULL); } - (cam->users)++; +out: mutex_unlock(&cam->lock); - return 0; + return ret; } static int viacam_release(struct file *filp) { struct via_camera *cam = video_drvdata(filp); + bool last_open; mutex_lock(&cam->lock); - (cam->users)--; - /* - * If the "owner" is closing, shut down any ongoing - * operations. - */ - if (filp == cam->owner) { - videobuf_stop(&cam->vb_queue); - /* - * We don't hold the spinlock here, but, if release() - * is being called by the owner, nobody else will - * be changing the state. And an extra stop would - * not hurt anyway. - */ - if (cam->opstate != S_IDLE) - viacam_stop_engine(cam); - cam->owner = NULL; - } + last_open = v4l2_fh_is_singular_file(filp); + _vb2_fop_release(filp, NULL); /* * Last one out needs to turn out the lights. */ - if (cam->users == 0) { - videobuf_mmap_free(&cam->vb_queue); + if (last_open) { via_sensor_power_down(cam); viafb_release_dma(); } @@ -723,77 +731,14 @@ static int viacam_release(struct file *filp) return 0; } -/* - * Read a frame from the device. - */ -static ssize_t viacam_read(struct file *filp, char __user *buffer, - size_t len, loff_t *pos) -{ - struct via_camera *cam = video_drvdata(filp); - int ret; - - mutex_lock(&cam->lock); - /* - * Enforce the V4l2 "only one owner gets to read data" rule. - */ - if (cam->owner && cam->owner != filp) { - ret = -EBUSY; - goto out_unlock; - } - cam->owner = filp; - /* - * Do we need to configure the hardware? - */ - if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) { - ret = viacam_configure_sensor(cam); - if (!ret) - ret = viacam_config_controller(cam); - if (ret) - goto out_unlock; - } - /* - * Fire up the capture engine, then have videobuf do - * the heavy lifting. Someday it would be good to avoid - * stopping and restarting the engine each time. - */ - INIT_LIST_HEAD(&cam->buffer_queue); - viacam_start_engine(cam); - ret = videobuf_read_stream(&cam->vb_queue, buffer, len, pos, 0, - filp->f_flags & O_NONBLOCK); - viacam_stop_engine(cam); - /* videobuf_stop() ?? */ - -out_unlock: - mutex_unlock(&cam->lock); - return ret; -} - - -static __poll_t viacam_poll(struct file *filp, struct poll_table_struct *pt) -{ - struct via_camera *cam = video_drvdata(filp); - - return videobuf_poll_stream(filp, &cam->vb_queue, pt); -} - - -static int viacam_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct via_camera *cam = video_drvdata(filp); - - return videobuf_mmap_mapper(&cam->vb_queue, vma); -} - - - static const struct v4l2_file_operations viacam_fops = { .owner = THIS_MODULE, .open = viacam_open, .release = viacam_release, - .read = viacam_read, - .poll = viacam_poll, - .mmap = viacam_mmap, - .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, }; /*----------------------------------------------------------------------------*/ @@ -811,7 +756,6 @@ static int viacam_enum_input(struct file *filp, void *priv, return -EINVAL; input->type = V4L2_INPUT_TYPE_CAMERA; - input->std = V4L2_STD_ALL; /* Not sure what should go here */ strscpy(input->name, "Camera", sizeof(input->name)); return 0; } @@ -829,17 +773,6 @@ static int viacam_s_input(struct file *filp, void *priv, unsigned int i) return 0; } -static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id std) -{ - return 0; -} - -static int viacam_g_std(struct file *filp, void *priv, v4l2_std_id *std) -{ - *std = V4L2_STD_NTSC_M; - return 0; -} - /* * Video format stuff. Here is our default format until * user space messes with things. @@ -851,6 +784,7 @@ static const struct v4l2_pix_format viacam_def_pix_format = { .field = V4L2_FIELD_NONE, .bytesperline = VGA_WIDTH * 2, .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, + .colorspace = V4L2_COLORSPACE_SRGB, }; static const u32 via_def_mbus_code = MEDIA_BUS_FMT_YUYV8_2X8; @@ -860,8 +794,6 @@ static int viacam_enum_fmt_vid_cap(struct file *filp, void *priv, { if (fmt->index >= N_VIA_FMTS) return -EINVAL; - strscpy(fmt->description, via_formats[fmt->index].desc, - sizeof(fmt->description)); fmt->pixelformat = via_formats[fmt->index].pixelformat; return 0; } @@ -897,6 +829,10 @@ static void viacam_fmt_post(struct v4l2_pix_format *userfmt, userfmt->field = sensorfmt->field; userfmt->bytesperline = 2 * userfmt->width; userfmt->sizeimage = userfmt->bytesperline * userfmt->height; + userfmt->colorspace = sensorfmt->colorspace; + userfmt->ycbcr_enc = sensorfmt->ycbcr_enc; + userfmt->quantization = sensorfmt->quantization; + userfmt->xfer_func = sensorfmt->xfer_func; } @@ -927,32 +863,26 @@ static int viacam_do_try_fmt(struct via_camera *cam, static int viacam_try_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmt) { - struct via_camera *cam = priv; + struct via_camera *cam = video_drvdata(filp); struct v4l2_format sfmt; - int ret; - mutex_lock(&cam->lock); - ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix); - mutex_unlock(&cam->lock); - return ret; + return viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix); } static int viacam_g_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmt) { - struct via_camera *cam = priv; + struct via_camera *cam = video_drvdata(filp); - mutex_lock(&cam->lock); fmt->fmt.pix = cam->user_format; - mutex_unlock(&cam->lock); return 0; } static int viacam_s_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmt) { - struct via_camera *cam = priv; + struct via_camera *cam = video_drvdata(filp); int ret; struct v4l2_format sfmt; struct via_format *f = via_find_format(fmt->fmt.pix.pixelformat); @@ -961,18 +891,15 @@ static int viacam_s_fmt_vid_cap(struct file *filp, void *priv, * Camera must be idle or we can't mess with the * video setup. */ - mutex_lock(&cam->lock); - if (cam->opstate != S_IDLE) { - ret = -EBUSY; - goto out; - } + if (cam->opstate != S_IDLE) + return -EBUSY; /* * Let the sensor code look over and tweak the * requested formatting. */ ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix); if (ret) - goto out; + return ret; /* * OK, let's commit to the new format. */ @@ -982,8 +909,6 @@ static int viacam_s_fmt_vid_cap(struct file *filp, void *priv, ret = viacam_configure_sensor(cam); if (!ret) ret = viacam_config_controller(cam); -out: - mutex_unlock(&cam->lock); return ret; } @@ -992,155 +917,40 @@ static int viacam_querycap(struct file *filp, void *priv, { strscpy(cap->driver, "via-camera", sizeof(cap->driver)); strscpy(cap->card, "via-camera", sizeof(cap->card)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + strscpy(cap->bus_info, "platform:via-camera", sizeof(cap->bus_info)); return 0; } -/* - * Streaming operations - pure videobuf stuff. - */ -static int viacam_reqbufs(struct file *filp, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct via_camera *cam = priv; - - return videobuf_reqbufs(&cam->vb_queue, rb); -} - -static int viacam_querybuf(struct file *filp, void *priv, - struct v4l2_buffer *buf) -{ - struct via_camera *cam = priv; - - return videobuf_querybuf(&cam->vb_queue, buf); -} - -static int viacam_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf) -{ - struct via_camera *cam = priv; - - return videobuf_qbuf(&cam->vb_queue, buf); -} - -static int viacam_dqbuf(struct file *filp, void *priv, struct v4l2_buffer *buf) -{ - struct via_camera *cam = priv; - - return videobuf_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK); -} - -static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t) -{ - struct via_camera *cam = priv; - int ret = 0; - - if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - mutex_lock(&cam->lock); - if (cam->opstate != S_IDLE) { - ret = -EBUSY; - goto out; - } - /* - * Enforce the V4l2 "only one owner gets to read data" rule. - */ - if (cam->owner && cam->owner != filp) { - ret = -EBUSY; - goto out; - } - cam->owner = filp; - /* - * Configure things if need be. - */ - if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) { - ret = viacam_configure_sensor(cam); - if (ret) - goto out; - ret = viacam_config_controller(cam); - if (ret) - goto out; - } - /* - * If the CPU goes into C3, the DMA transfer gets corrupted and - * users start filing unsightly bug reports. Put in a "latency" - * requirement which will keep the CPU out of the deeper sleep - * states. - */ - pm_qos_add_request(&cam->qos_request, PM_QOS_CPU_DMA_LATENCY, 50); - /* - * Fire things up. - */ - INIT_LIST_HEAD(&cam->buffer_queue); - ret = videobuf_streamon(&cam->vb_queue); - if (!ret) - viacam_start_engine(cam); -out: - mutex_unlock(&cam->lock); - return ret; -} - -static int viacam_streamoff(struct file *filp, void *priv, enum v4l2_buf_type t) -{ - struct via_camera *cam = priv; - int ret; - - if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - mutex_lock(&cam->lock); - if (cam->opstate != S_RUNNING) { - ret = -EINVAL; - goto out; - } - pm_qos_remove_request(&cam->qos_request); - viacam_stop_engine(cam); - /* - * Videobuf will recycle all of the outstanding buffers, but - * we should be sure we don't retain any references to - * any of them. - */ - ret = videobuf_streamoff(&cam->vb_queue); - INIT_LIST_HEAD(&cam->buffer_queue); -out: - mutex_unlock(&cam->lock); - return ret; -} - /* G/S_PARM */ static int viacam_g_parm(struct file *filp, void *priv, struct v4l2_streamparm *parm) { - struct via_camera *cam = priv; - int ret; + struct via_camera *cam = video_drvdata(filp); - mutex_lock(&cam->lock); - ret = v4l2_g_parm_cap(video_devdata(filp), cam->sensor, parm); - mutex_unlock(&cam->lock); - parm->parm.capture.readbuffers = cam->n_cap_bufs; - return ret; + return v4l2_g_parm_cap(video_devdata(filp), cam->sensor, parm); } static int viacam_s_parm(struct file *filp, void *priv, struct v4l2_streamparm *parm) { - struct via_camera *cam = priv; - int ret; + struct via_camera *cam = video_drvdata(filp); - mutex_lock(&cam->lock); - ret = v4l2_s_parm_cap(video_devdata(filp), cam->sensor, parm); - mutex_unlock(&cam->lock); - parm->parm.capture.readbuffers = cam->n_cap_bufs; - return ret; + return v4l2_s_parm_cap(video_devdata(filp), cam->sensor, parm); } static int viacam_enum_framesizes(struct file *filp, void *priv, struct v4l2_frmsizeenum *sizes) { + unsigned int i; + if (sizes->index != 0) return -EINVAL; + for (i = 0; i < N_VIA_FMTS; i++) + if (sizes->pixel_format == via_formats[i].pixelformat) + break; + if (i >= N_VIA_FMTS) + return -EINVAL; sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; sizes->stepwise.min_width = QCIF_WIDTH; sizes->stepwise.min_height = QCIF_HEIGHT; @@ -1153,7 +963,7 @@ static int viacam_enum_framesizes(struct file *filp, void *priv, static int viacam_enum_frameintervals(struct file *filp, void *priv, struct v4l2_frmivalenum *interval) { - struct via_camera *cam = priv; + struct via_camera *cam = video_drvdata(filp); struct v4l2_subdev_frame_interval_enum fie = { .index = interval->index, .code = cam->mbus_code, @@ -1161,11 +971,18 @@ static int viacam_enum_frameintervals(struct file *filp, void *priv, .height = cam->sensor_format.height, .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; + unsigned int i; int ret; - mutex_lock(&cam->lock); + for (i = 0; i < N_VIA_FMTS; i++) + if (interval->pixel_format == via_formats[i].pixelformat) + break; + if (i >= N_VIA_FMTS) + return -EINVAL; + if (interval->width < QCIF_WIDTH || interval->width > VGA_WIDTH || + interval->height < QCIF_HEIGHT || interval->height > VGA_HEIGHT) + return -EINVAL; ret = sensor_call(cam, pad, enum_frame_interval, NULL, &fie); - mutex_unlock(&cam->lock); if (ret) return ret; interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; @@ -1173,29 +990,30 @@ static int viacam_enum_frameintervals(struct file *filp, void *priv, return 0; } - - static const struct v4l2_ioctl_ops viacam_ioctl_ops = { .vidioc_enum_input = viacam_enum_input, .vidioc_g_input = viacam_g_input, .vidioc_s_input = viacam_s_input, - .vidioc_s_std = viacam_s_std, - .vidioc_g_std = viacam_g_std, .vidioc_enum_fmt_vid_cap = viacam_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap = viacam_try_fmt_vid_cap, .vidioc_g_fmt_vid_cap = viacam_g_fmt_vid_cap, .vidioc_s_fmt_vid_cap = viacam_s_fmt_vid_cap, .vidioc_querycap = viacam_querycap, - .vidioc_reqbufs = viacam_reqbufs, - .vidioc_querybuf = viacam_querybuf, - .vidioc_qbuf = viacam_qbuf, - .vidioc_dqbuf = viacam_dqbuf, - .vidioc_streamon = viacam_streamon, - .vidioc_streamoff = viacam_streamoff, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_g_parm = viacam_g_parm, .vidioc_s_parm = viacam_s_parm, .vidioc_enum_framesizes = viacam_enum_framesizes, .vidioc_enum_frameintervals = viacam_enum_frameintervals, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; /*----------------------------------------------------------------------------*/ @@ -1233,7 +1051,7 @@ static int viacam_resume(void *priv) /* * Make sure the sensor's power state is correct */ - if (cam->users > 0) + if (!list_empty(&cam->vdev.fh_list)) via_sensor_power_up(cam); else via_sensor_power_down(cam); @@ -1267,10 +1085,11 @@ static struct viafb_pm_hooks viacam_pm_hooks = { static const struct video_device viacam_v4l_template = { .name = "via-camera", .minor = -1, - .tvnorms = V4L2_STD_NTSC_M, .fops = &viacam_fops, .ioctl_ops = &viacam_ioctl_ops, .release = video_device_release_empty, /* Check this */ + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; /* @@ -1317,6 +1136,7 @@ static int viacam_probe(struct platform_device *pdev) int ret; struct i2c_adapter *sensor_adapter; struct viafb_dev *viadev = pdev->dev.platform_data; + struct vb2_queue *vq; struct i2c_board_info ov7670_info = { .type = "ov7670", .addr = 0x42 >> 1, @@ -1360,8 +1180,6 @@ static int viacam_probe(struct platform_device *pdev) via_cam_info = cam; cam->platdev = pdev; cam->viadev = viadev; - cam->users = 0; - cam->owner = NULL; cam->opstate = S_IDLE; cam->user_format = cam->sensor_format = viacam_def_pix_format; mutex_init(&cam->lock); @@ -1422,15 +1240,31 @@ static int viacam_probe(struct platform_device *pdev) viacam_irq, IRQF_SHARED, "via-camera", cam); if (ret) goto out_power_down; + + vq = &cam->vq; + vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + vq->drv_priv = cam; + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vq->buf_struct_size = sizeof(struct via_buffer); + vq->dev = cam->v4l2_dev.dev; + + vq->ops = &viacam_vb2_ops; + vq->mem_ops = &vb2_dma_sg_memops; + vq->lock = &cam->lock; + + ret = vb2_queue_init(vq); /* * Tell V4l2 that we exist. */ cam->vdev = viacam_v4l_template; cam->vdev.v4l2_dev = &cam->v4l2_dev; + cam->vdev.lock = &cam->lock; + cam->vdev.queue = vq; + video_set_drvdata(&cam->vdev, cam); ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); if (ret) goto out_irq; - video_set_drvdata(&cam->vdev, cam); #ifdef CONFIG_PM /* @@ -1464,6 +1298,9 @@ static int viacam_remove(struct platform_device *pdev) video_unregister_device(&cam->vdev); v4l2_device_unregister(&cam->v4l2_dev); +#ifdef CONFIG_PM + viafb_pm_unregister(&viacam_pm_hooks); +#endif free_irq(viadev->pdev->irq, cam); via_sensor_power_release(cam); v4l2_ctrl_handler_free(&cam->ctrl_handler); diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.c b/drivers/media/platform/vicodec/codec-v4l2-fwht.c index 01e7f09efc4e..3c93d9232c3c 100644 --- a/drivers/media/platform/vicodec/codec-v4l2-fwht.c +++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.c @@ -29,11 +29,15 @@ static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = { { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV}, { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV}, { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_BGRX32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_BGRA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGBX32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGBA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV}, { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB}, }; @@ -193,6 +197,28 @@ static int prepare_raw_frame(struct fwht_raw_frame *rf, rf->luma++; rf->alpha = rf->cr + 1; break; + case V4L2_PIX_FMT_BGRX32: + rf->cb = rf->luma + 1; + rf->cr = rf->cb + 2; + rf->luma += 2; + break; + case V4L2_PIX_FMT_BGRA32: + rf->alpha = rf->luma; + rf->cb = rf->luma + 1; + rf->cr = rf->cb + 2; + rf->luma += 2; + break; + case V4L2_PIX_FMT_RGBX32: + rf->cr = rf->luma; + rf->cb = rf->cr + 2; + rf->luma++; + break; + case V4L2_PIX_FMT_RGBA32: + rf->alpha = rf->luma + 3; + rf->cr = rf->luma; + rf->cb = rf->cr + 2; + rf->luma++; + break; default: return -EINVAL; } diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 7e7c1e80f29f..0ee143ae0f6b 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -742,6 +742,9 @@ static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx, return -EINVAL; f->pixelformat = ctx->is_stateless ? V4L2_PIX_FMT_FWHT_STATELESS : V4L2_PIX_FMT_FWHT; + if (!ctx->is_enc && !ctx->is_stateless) + f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION | + V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM; } return 0; } @@ -1661,19 +1664,22 @@ static int vicodec_start_streaming(struct vb2_queue *q, kvfree(state->compressed_frame); state->compressed_frame = new_comp_frame; - if (info->components_num >= 3) { - state->ref_frame.cb = state->ref_frame.luma + size; - state->ref_frame.cr = state->ref_frame.cb + size / chroma_div; - } else { + if (info->components_num < 3) { state->ref_frame.cb = NULL; state->ref_frame.cr = NULL; + state->ref_frame.alpha = NULL; + return 0; } + state->ref_frame.cb = state->ref_frame.luma + size; + state->ref_frame.cr = state->ref_frame.cb + size / chroma_div; + if (info->components_num == 4) state->ref_frame.alpha = state->ref_frame.cr + size / chroma_div; else state->ref_frame.alpha = NULL; + return 0; } diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c index 664855708fdf..1d56b91830ba 100644 --- a/drivers/media/platform/vimc/vimc-capture.c +++ b/drivers/media/platform/vimc/vimc-capture.c @@ -18,32 +18,6 @@ #define VIMC_CAP_DRV_NAME "vimc-capture" -static const u32 vimc_cap_supported_pixfmt[] = { - V4L2_PIX_FMT_BGR24, - V4L2_PIX_FMT_RGB24, - V4L2_PIX_FMT_ARGB32, - V4L2_PIX_FMT_SBGGR8, - V4L2_PIX_FMT_SGBRG8, - V4L2_PIX_FMT_SGRBG8, - V4L2_PIX_FMT_SRGGB8, - V4L2_PIX_FMT_SBGGR10, - V4L2_PIX_FMT_SGBRG10, - V4L2_PIX_FMT_SGRBG10, - V4L2_PIX_FMT_SRGGB10, - V4L2_PIX_FMT_SBGGR10ALAW8, - V4L2_PIX_FMT_SGBRG10ALAW8, - V4L2_PIX_FMT_SGRBG10ALAW8, - V4L2_PIX_FMT_SRGGB10ALAW8, - V4L2_PIX_FMT_SBGGR10DPCM8, - V4L2_PIX_FMT_SGBRG10DPCM8, - V4L2_PIX_FMT_SGRBG10DPCM8, - V4L2_PIX_FMT_SRGGB10DPCM8, - V4L2_PIX_FMT_SBGGR12, - V4L2_PIX_FMT_SGBRG12, - V4L2_PIX_FMT_SGRBG12, - V4L2_PIX_FMT_SRGGB12, -}; - struct vimc_cap_device { struct vimc_ent_device ved; struct video_device vdev; @@ -117,25 +91,29 @@ static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format *format = &f->fmt.pix; + const struct vimc_pix_map *vpix; format->width = clamp_t(u32, format->width, VIMC_FRAME_MIN_WIDTH, VIMC_FRAME_MAX_WIDTH) & ~1; format->height = clamp_t(u32, format->height, VIMC_FRAME_MIN_HEIGHT, VIMC_FRAME_MAX_HEIGHT) & ~1; - vimc_colorimetry_clamp(format); + /* Don't accept a pixelformat that is not on the table */ + vpix = vimc_pix_map_by_pixelformat(format->pixelformat); + if (!vpix) { + format->pixelformat = fmt_default.pixelformat; + vpix = vimc_pix_map_by_pixelformat(format->pixelformat); + } + /* TODO: Add support for custom bytesperline values */ + format->bytesperline = format->width * vpix->bpp; + format->sizeimage = format->bytesperline * format->height; if (format->field == V4L2_FIELD_ANY) format->field = fmt_default.field; - /* TODO: Add support for custom bytesperline values */ - - /* Don't accept a pixelformat that is not on the table */ - if (!v4l2_format_info(format->pixelformat)) - format->pixelformat = fmt_default.pixelformat; + vimc_colorimetry_clamp(format); - return v4l2_fill_pixfmt(format, format->pixelformat, - format->width, format->height); + return 0; } static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, @@ -174,31 +152,27 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - if (f->index >= ARRAY_SIZE(vimc_cap_supported_pixfmt)) + const struct vimc_pix_map *vpix = vimc_pix_map_by_index(f->index); + + if (!vpix) return -EINVAL; - f->pixelformat = vimc_cap_supported_pixfmt[f->index]; + f->pixelformat = vpix->pixelformat; return 0; } -static bool vimc_cap_is_pixfmt_supported(u32 pixelformat) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(vimc_cap_supported_pixfmt); i++) - if (vimc_cap_supported_pixfmt[i] == pixelformat) - return true; - return false; -} - static int vimc_cap_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { + const struct vimc_pix_map *vpix; + if (fsize->index) return -EINVAL; - if (!vimc_cap_is_pixfmt_supported(fsize->pixel_format)) + /* Only accept code in the pix map table */ + vpix = vimc_pix_map_by_code(fsize->pixel_format); + if (!vpix) return -EINVAL; fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; @@ -272,7 +246,6 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) return ret; } - vcap->stream.producer_pixfmt = vcap->format.pixelformat; ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1); if (ret) { media_pipeline_stop(entity); @@ -423,6 +396,7 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, { struct v4l2_device *v4l2_dev = master_data; struct vimc_platform_data *pdata = comp->platform_data; + const struct vimc_pix_map *vpix; struct vimc_cap_device *vcap; struct video_device *vdev; struct vb2_queue *q; @@ -477,8 +451,10 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, /* Set default frame format */ vcap->format = fmt_default; - v4l2_fill_pixfmt(&vcap->format, vcap->format.pixelformat, - vcap->format.width, vcap->format.height); + vpix = vimc_pix_map_by_pixelformat(vcap->format.pixelformat); + vcap->format.bytesperline = vcap->format.width * vpix->bpp; + vcap->format.sizeimage = vcap->format.bytesperline * + vcap->format.height; /* Fill the vimc_ent_device struct */ vcap->ved.ent = &vcap->vdev.entity; diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index 03016f204d05..7e1ae0b12f1e 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c @@ -10,139 +10,192 @@ #include "vimc-common.h" -static const __u32 vimc_mbus_list[] = { - MEDIA_BUS_FMT_FIXED, - MEDIA_BUS_FMT_RGB444_1X12, - MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, - MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, - MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, - MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, - MEDIA_BUS_FMT_RGB565_1X16, - MEDIA_BUS_FMT_BGR565_2X8_BE, - MEDIA_BUS_FMT_BGR565_2X8_LE, - MEDIA_BUS_FMT_RGB565_2X8_BE, - MEDIA_BUS_FMT_RGB565_2X8_LE, - MEDIA_BUS_FMT_RGB666_1X18, - MEDIA_BUS_FMT_RBG888_1X24, - MEDIA_BUS_FMT_RGB666_1X24_CPADHI, - MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, - MEDIA_BUS_FMT_BGR888_1X24, - MEDIA_BUS_FMT_GBR888_1X24, - MEDIA_BUS_FMT_RGB888_1X24, - MEDIA_BUS_FMT_RGB888_2X12_BE, - MEDIA_BUS_FMT_RGB888_2X12_LE, - MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, - MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, - MEDIA_BUS_FMT_ARGB8888_1X32, - MEDIA_BUS_FMT_RGB888_1X32_PADHI, - MEDIA_BUS_FMT_RGB101010_1X30, - MEDIA_BUS_FMT_RGB121212_1X36, - MEDIA_BUS_FMT_RGB161616_1X48, - MEDIA_BUS_FMT_Y8_1X8, - MEDIA_BUS_FMT_UV8_1X8, - MEDIA_BUS_FMT_UYVY8_1_5X8, - MEDIA_BUS_FMT_VYUY8_1_5X8, - MEDIA_BUS_FMT_YUYV8_1_5X8, - MEDIA_BUS_FMT_YVYU8_1_5X8, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_Y10_1X10, - MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, - MEDIA_BUS_FMT_UYVY10_2X10, - MEDIA_BUS_FMT_VYUY10_2X10, - MEDIA_BUS_FMT_YUYV10_2X10, - MEDIA_BUS_FMT_YVYU10_2X10, - MEDIA_BUS_FMT_Y12_1X12, - MEDIA_BUS_FMT_UYVY12_2X12, - MEDIA_BUS_FMT_VYUY12_2X12, - MEDIA_BUS_FMT_YUYV12_2X12, - MEDIA_BUS_FMT_YVYU12_2X12, - MEDIA_BUS_FMT_UYVY8_1X16, - MEDIA_BUS_FMT_VYUY8_1X16, - MEDIA_BUS_FMT_YUYV8_1X16, - MEDIA_BUS_FMT_YVYU8_1X16, - MEDIA_BUS_FMT_YDYUYDYV8_1X16, - MEDIA_BUS_FMT_UYVY10_1X20, - MEDIA_BUS_FMT_VYUY10_1X20, - MEDIA_BUS_FMT_YUYV10_1X20, - MEDIA_BUS_FMT_YVYU10_1X20, - MEDIA_BUS_FMT_VUY8_1X24, - MEDIA_BUS_FMT_YUV8_1X24, - MEDIA_BUS_FMT_UYYVYY8_0_5X24, - MEDIA_BUS_FMT_UYVY12_1X24, - MEDIA_BUS_FMT_VYUY12_1X24, - MEDIA_BUS_FMT_YUYV12_1X24, - MEDIA_BUS_FMT_YVYU12_1X24, - MEDIA_BUS_FMT_YUV10_1X30, - MEDIA_BUS_FMT_UYYVYY10_0_5X30, - MEDIA_BUS_FMT_AYUV8_1X32, - MEDIA_BUS_FMT_UYYVYY12_0_5X36, - MEDIA_BUS_FMT_YUV12_1X36, - MEDIA_BUS_FMT_YUV16_1X48, - MEDIA_BUS_FMT_UYYVYY16_0_5X48, - MEDIA_BUS_FMT_SBGGR8_1X8, - MEDIA_BUS_FMT_SGBRG8_1X8, - MEDIA_BUS_FMT_SGRBG8_1X8, - MEDIA_BUS_FMT_SRGGB8_1X8, - MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, - MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, - MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, - MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, - MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, - MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, - MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, - MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, - MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, - MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, - MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, - MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, - MEDIA_BUS_FMT_SBGGR10_1X10, - MEDIA_BUS_FMT_SGBRG10_1X10, - MEDIA_BUS_FMT_SGRBG10_1X10, - MEDIA_BUS_FMT_SRGGB10_1X10, - MEDIA_BUS_FMT_SBGGR12_1X12, - MEDIA_BUS_FMT_SGBRG12_1X12, - MEDIA_BUS_FMT_SGRBG12_1X12, - MEDIA_BUS_FMT_SRGGB12_1X12, - MEDIA_BUS_FMT_SBGGR14_1X14, - MEDIA_BUS_FMT_SGBRG14_1X14, - MEDIA_BUS_FMT_SGRBG14_1X14, - MEDIA_BUS_FMT_SRGGB14_1X14, - MEDIA_BUS_FMT_SBGGR16_1X16, - MEDIA_BUS_FMT_SGBRG16_1X16, - MEDIA_BUS_FMT_SGRBG16_1X16, - MEDIA_BUS_FMT_SRGGB16_1X16, - MEDIA_BUS_FMT_JPEG_1X8, - MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8, - MEDIA_BUS_FMT_AHSV8888_1X32, +/* + * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code + * in the scaler) + */ +static const struct vimc_pix_map vimc_pix_map_list[] = { + /* TODO: add all missing formats */ + + /* RGB formats */ + { + .code = MEDIA_BUS_FMT_BGR888_1X24, + .pixelformat = V4L2_PIX_FMT_BGR24, + .bpp = 3, + .bayer = false, + }, + { + .code = MEDIA_BUS_FMT_RGB888_1X24, + .pixelformat = V4L2_PIX_FMT_RGB24, + .bpp = 3, + .bayer = false, + }, + { + .code = MEDIA_BUS_FMT_ARGB8888_1X32, + .pixelformat = V4L2_PIX_FMT_ARGB32, + .bpp = 4, + .bayer = false, + }, + + /* Bayer formats */ + { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .pixelformat = V4L2_PIX_FMT_SGBRG8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .pixelformat = V4L2_PIX_FMT_SGRBG8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .pixelformat = V4L2_PIX_FMT_SRGGB8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .pixelformat = V4L2_PIX_FMT_SBGGR10, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .pixelformat = V4L2_PIX_FMT_SGBRG10, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .pixelformat = V4L2_PIX_FMT_SGRBG10, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .pixelformat = V4L2_PIX_FMT_SRGGB10, + .bpp = 2, + .bayer = true, + }, + + /* 10bit raw bayer a-law compressed to 8 bits */ + { + .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, + .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, + .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, + .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, + .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8, + .bpp = 1, + .bayer = true, + }, + + /* 10bit raw bayer DPCM compressed to 8 bits */ + { + .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, + .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, + .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, + .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, + .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .pixelformat = V4L2_PIX_FMT_SBGGR12, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .pixelformat = V4L2_PIX_FMT_SGBRG12, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .pixelformat = V4L2_PIX_FMT_SGRBG12, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .pixelformat = V4L2_PIX_FMT_SRGGB12, + .bpp = 2, + .bayer = true, + }, }; -/* Helper function to check mbus codes */ -bool vimc_mbus_code_supported(__u32 code) +const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i) +{ + if (i >= ARRAY_SIZE(vimc_pix_map_list)) + return NULL; + + return &vimc_pix_map_list[i]; +} +EXPORT_SYMBOL_GPL(vimc_pix_map_by_index); + +const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(vimc_mbus_list); i++) - if (code == vimc_mbus_list[i]) - return true; - return false; + for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { + if (vimc_pix_map_list[i].code == code) + return &vimc_pix_map_list[i]; + } + return NULL; } -EXPORT_SYMBOL_GPL(vimc_mbus_code_supported); +EXPORT_SYMBOL_GPL(vimc_pix_map_by_code); -/* Helper function to enumerate mbus codes */ -int vimc_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) +const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) { - if (code->index >= ARRAY_SIZE(vimc_mbus_list)) - return -EINVAL; + unsigned int i; - code->code = vimc_mbus_list[code->index]; - return 0; + for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { + if (vimc_pix_map_list[i].pixelformat == pixelformat) + return &vimc_pix_map_list[i]; + } + return NULL; } -EXPORT_SYMBOL_GPL(vimc_enum_mbus_code); +EXPORT_SYMBOL_GPL(vimc_pix_map_by_pixelformat); /* Helper function to allocate and initialize pads */ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) @@ -214,13 +267,15 @@ static int vimc_get_mbus_format(struct media_pad *pad, struct video_device, entity); struct vimc_ent_device *ved = video_get_drvdata(vdev); + const struct vimc_pix_map *vpix; struct v4l2_pix_format vdev_fmt; if (!ved->vdev_get_format) return -ENOIOCTLCMD; ved->vdev_get_format(ved, &vdev_fmt); - v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, 0); + vpix = vimc_pix_map_by_pixelformat(vdev_fmt.pixelformat); + v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, vpix->code); } else { return -EINVAL; } @@ -260,12 +315,8 @@ int vimc_link_validate(struct media_link *link) /* The width, height and code must match. */ if (source_fmt.format.width != sink_fmt.format.width || source_fmt.format.height != sink_fmt.format.height - || (source_fmt.format.code && sink_fmt.format.code && - source_fmt.format.code != sink_fmt.format.code)) { - pr_err("vimc: format doesn't match in link %s->%s\n", - link->source->entity->name, link->sink->entity->name); + || source_fmt.format.code != sink_fmt.format.code) return -EPIPE; - } /* * The field order must match, or the sink field order must be NONE diff --git a/drivers/media/platform/vimc/vimc-common.h b/drivers/media/platform/vimc/vimc-common.h index 7b4d988b208b..9c2e0e216c6b 100644 --- a/drivers/media/platform/vimc/vimc-common.h +++ b/drivers/media/platform/vimc/vimc-common.h @@ -12,8 +12,6 @@ #include <media/media-device.h> #include <media/v4l2-device.h> -#include "vimc-streamer.h" - #define VIMC_PDEV_NAME "vimc" /* VIMC-specific controls */ @@ -70,6 +68,23 @@ struct vimc_platform_data { }; /** + * struct vimc_pix_map - maps media bus code with v4l2 pixel format + * + * @code: media bus format code defined by MEDIA_BUS_FMT_* macros + * @bbp: number of bytes each pixel occupies + * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros + * + * Struct which matches the MEDIA_BUS_FMT_* codes with the corresponding + * V4L2_PIX_FMT_* fourcc pixelformat and its bytes per pixel (bpp) + */ +struct vimc_pix_map { + unsigned int code; + unsigned int bpp; + u32 pixelformat; + bool bayer; +}; + +/** * struct vimc_ent_device - core struct that represents a node in the topology * * @ent: the pointer to struct media_entity for the node @@ -90,7 +105,6 @@ struct vimc_platform_data { struct vimc_ent_device { struct media_entity *ent; struct media_pad *pads; - struct vimc_stream *stream; void * (*process_frame)(struct vimc_ent_device *ved, const void *frame); void (*vdev_get_format)(struct vimc_ent_device *ved, @@ -98,23 +112,6 @@ struct vimc_ent_device { }; /** - * vimc_mbus_code_supported - helper to check supported mbus codes - * - * Helper function to check if mbus code is enumerated by vimc_enum_mbus_code() - */ -bool vimc_mbus_code_supported(__u32 code); - -/** - * vimc_enum_mbus_code - enumerate mbus codes - * - * Helper function to be pluged in .enum_mbus_code from - * struct v4l2_subdev_pad_ops. - */ -int vimc_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code); - -/** * vimc_pads_init - initialize pads * * @num_pads: number of pads to initialize @@ -149,6 +146,27 @@ static inline void vimc_pads_cleanup(struct media_pad *pads) int vimc_pipeline_s_stream(struct media_entity *ent, int enable); /** + * vimc_pix_map_by_index - get vimc_pix_map struct by its index + * + * @i: index of the vimc_pix_map struct in vimc_pix_map_list + */ +const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i); + +/** + * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code + * + * @code: media bus format code defined by MEDIA_BUS_FMT_* macros + */ +const struct vimc_pix_map *vimc_pix_map_by_code(u32 code); + +/** + * vimc_pix_map_by_pixelformat - get vimc_pix_map struct by v4l2 pixel format + * + * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros + */ +const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); + +/** * vimc_ent_sd_register - initialize and register a subdev node * * @ved: the vimc_ent_device struct to be initialize diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index 00598fbf3cba..b72b8385067b 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -16,11 +16,6 @@ #include "vimc-common.h" #define VIMC_DEB_DRV_NAME "vimc-debayer" -/* This module only supports transforming a bayer format - * to V4L2_PIX_FMT_RGB24 - */ -#define VIMC_DEB_SRC_PIXFMT V4L2_PIX_FMT_RGB24 -#define VIMC_DEB_SRC_MBUS_FMT_DEFAULT MEDIA_BUS_FMT_RGB888_1X24 static unsigned int deb_mean_win_size = 3; module_param(deb_mean_win_size, uint, 0000); @@ -39,7 +34,6 @@ enum vimc_deb_rgb_colors { }; struct vimc_deb_pix_map { - u32 pixelformat; u32 code; enum vimc_deb_rgb_colors order[2][2]; }; @@ -69,73 +63,61 @@ static const struct v4l2_mbus_framefmt sink_fmt_default = { static const struct vimc_deb_pix_map vimc_deb_pix_map_list[] = { { - .pixelformat = V4L2_PIX_FMT_SBGGR8, .code = MEDIA_BUS_FMT_SBGGR8_1X8, .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_RED } } }, { - .pixelformat = V4L2_PIX_FMT_SGBRG8, .code = MEDIA_BUS_FMT_SGBRG8_1X8, .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, { VIMC_DEB_RED, VIMC_DEB_GREEN } } }, { - .pixelformat = V4L2_PIX_FMT_SGRBG8, .code = MEDIA_BUS_FMT_SGRBG8_1X8, .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } }, { - .pixelformat = V4L2_PIX_FMT_SRGGB8, .code = MEDIA_BUS_FMT_SRGGB8_1X8, .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } }, { - .pixelformat = V4L2_PIX_FMT_SBGGR10, .code = MEDIA_BUS_FMT_SBGGR10_1X10, .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_RED } } }, { - .pixelformat = V4L2_PIX_FMT_SGBRG10, .code = MEDIA_BUS_FMT_SGBRG10_1X10, .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, { VIMC_DEB_RED, VIMC_DEB_GREEN } } }, { - .pixelformat = V4L2_PIX_FMT_SGRBG10, .code = MEDIA_BUS_FMT_SGRBG10_1X10, .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } }, { - .pixelformat = V4L2_PIX_FMT_SRGGB10, .code = MEDIA_BUS_FMT_SRGGB10_1X10, .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } }, { - .pixelformat = V4L2_PIX_FMT_SBGGR12, .code = MEDIA_BUS_FMT_SBGGR12_1X12, .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_RED } } }, { - .pixelformat = V4L2_PIX_FMT_SGBRG12, .code = MEDIA_BUS_FMT_SGBRG12_1X12, .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, { VIMC_DEB_RED, VIMC_DEB_GREEN } } }, { - .pixelformat = V4L2_PIX_FMT_SGRBG12, .code = MEDIA_BUS_FMT_SGRBG12_1X12, .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } }, { - .pixelformat = V4L2_PIX_FMT_SRGGB12, .code = MEDIA_BUS_FMT_SRGGB12_1X12, .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } @@ -176,32 +158,41 @@ static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { - /* For the sink pad we only support codes in the map_list */ - if (IS_SINK(code->pad)) { + /* We only support one format for source pads */ + if (IS_SRC(code->pad)) { + struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + + if (code->index) + return -EINVAL; + + code->code = vdeb->src_code; + } else { if (code->index >= ARRAY_SIZE(vimc_deb_pix_map_list)) return -EINVAL; code->code = vimc_deb_pix_map_list[code->index].code; - return 0; } - return vimc_enum_mbus_code(sd, cfg, code); + return 0; } static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { + struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + if (fse->index) return -EINVAL; - /* For the sink pad we only support codes in the map_list */ if (IS_SINK(fse->pad)) { const struct vimc_deb_pix_map *vpix = vimc_deb_pix_map_by_code(fse->code); if (!vpix) return -EINVAL; + } else if (fse->code != vdeb->src_code) { + return -EINVAL; } fse->min_width = VIMC_FRAME_MIN_WIDTH; @@ -257,12 +248,9 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; - if (!vimc_mbus_code_supported(fmt->format.code)) - fmt->format.code = sink_fmt_default.code; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ - if (vdeb->ved.stream) + if (vdeb->src_frame) return -EBUSY; sink_fmt = &vdeb->sink_fmt; @@ -272,11 +260,11 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, /* * Do not change the format of the source pad, - * it is propagated from the sink (except for the code) + * it is propagated from the sink */ if (IS_SRC(fmt->pad)) { - vdeb->src_code = fmt->format.code; fmt->format = *sink_fmt; + /* TODO: Add support for other formats */ fmt->format.code = vdeb->src_code; } else { /* Set the new format in the sink pad */ @@ -308,7 +296,7 @@ static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = { .set_fmt = vimc_deb_set_fmt, }; -static void vimc_deb_set_rgb_pix_rgb24(struct vimc_deb_device *vdeb, +static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device *vdeb, unsigned int lin, unsigned int col, unsigned int rgb[3]) @@ -325,35 +313,25 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); if (enable) { - u32 src_pixelformat = vdeb->ved.stream->producer_pixfmt; - const struct v4l2_format_info *pix_info; + const struct vimc_pix_map *vpix; unsigned int frame_size; - /* We only support translating bayer to RGB24 */ - if (src_pixelformat != V4L2_PIX_FMT_RGB24) { - dev_err(vdeb->dev, - "translating to pixfmt (0x%08x) is not supported\n", - src_pixelformat); - return -EINVAL; - } + if (vdeb->src_frame) + return 0; + + /* Calculate the frame size of the source pad */ + vpix = vimc_pix_map_by_code(vdeb->src_code); + frame_size = vdeb->sink_fmt.width * vdeb->sink_fmt.height * + vpix->bpp; + + /* Save the bytes per pixel of the sink */ + vpix = vimc_pix_map_by_code(vdeb->sink_fmt.code); + vdeb->sink_bpp = vpix->bpp; /* Get the corresponding pixel map from the table */ vdeb->sink_pix_map = vimc_deb_pix_map_by_code(vdeb->sink_fmt.code); - /* Request bayer format from the pipeline for the sink pad */ - vdeb->ved.stream->producer_pixfmt = - vdeb->sink_pix_map->pixelformat; - - /* Calculate frame_size of the source */ - pix_info = v4l2_format_info(src_pixelformat); - frame_size = vdeb->sink_fmt.width * vdeb->sink_fmt.height * - pix_info->bpp[0]; - - /* Get bpp from the sink */ - pix_info = v4l2_format_info(vdeb->sink_pix_map->pixelformat); - vdeb->sink_bpp = pix_info->bpp[0]; - /* * Allocate the frame buffer. Use vmalloc to be able to * allocate a large amount of memory @@ -554,14 +532,14 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master, /* Initialize the frame format */ vdeb->sink_fmt = sink_fmt_default; - vdeb->src_code = VIMC_DEB_SRC_MBUS_FMT_DEFAULT; /* * TODO: Add support for more output formats, we only support - * RGB24 for now. + * RGB888 for now * NOTE: the src format is always the same as the sink, except * for the code */ - vdeb->set_rgb_src = vimc_deb_set_rgb_pix_rgb24; + vdeb->src_code = MEDIA_BUS_FMT_RGB888_1X24; + vdeb->set_rgb_src = vimc_deb_set_rgb_mbus_fmt_rgb888_1x24; return 0; } diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c index c7123a45c55b..49ab8d9dd9c9 100644 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ b/drivers/media/platform/vimc/vimc-scaler.c @@ -25,12 +25,6 @@ MODULE_PARM_DESC(sca_mult, " the image size multiplier"); #define IS_SRC(pad) (pad) #define MAX_ZOOM 8 -static const u32 vimc_sca_supported_pixfmt[] = { - V4L2_PIX_FMT_BGR24, - V4L2_PIX_FMT_RGB24, - V4L2_PIX_FMT_ARGB32, -}; - struct vimc_sca_device { struct vimc_ent_device ved; struct v4l2_subdev sd; @@ -53,16 +47,6 @@ static const struct v4l2_mbus_framefmt sink_fmt_default = { .colorspace = V4L2_COLORSPACE_DEFAULT, }; -static bool vimc_sca_is_pixfmt_supported(u32 pixelformat) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(vimc_sca_supported_pixfmt); i++) - if (vimc_sca_supported_pixfmt[i] == pixelformat) - return true; - return false; -} - static int vimc_sca_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg) { @@ -82,13 +66,35 @@ static int vimc_sca_init_cfg(struct v4l2_subdev *sd, return 0; } +static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index); + + /* We don't support bayer format */ + if (!vpix || vpix->bayer) + return -EINVAL; + + code->code = vpix->code; + + return 0; +} + static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { + const struct vimc_pix_map *vpix; + if (fse->index) return -EINVAL; + /* Only accept code in the pix map table in non bayer format */ + vpix = vimc_pix_map_by_code(fse->code); + if (!vpix || vpix->bayer) + return -EINVAL; + fse->min_width = VIMC_FRAME_MIN_WIDTH; fse->min_height = VIMC_FRAME_MIN_HEIGHT; @@ -125,6 +131,13 @@ static int vimc_sca_get_fmt(struct v4l2_subdev *sd, static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) { + const struct vimc_pix_map *vpix; + + /* Only accept code in the pix map table in non bayer format */ + vpix = vimc_pix_map_by_code(fmt->code); + if (!vpix || vpix->bayer) + fmt->code = sink_fmt_default.code; + fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, VIMC_FRAME_MAX_WIDTH) & ~1; fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, @@ -143,12 +156,9 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; - if (!vimc_mbus_code_supported(fmt->format.code)) - fmt->format.code = sink_fmt_default.code; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ - if (vsca->ved.stream) + if (vsca->src_frame) return -EBUSY; sink_fmt = &vsca->sink_fmt; @@ -188,7 +198,7 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = { .init_cfg = vimc_sca_init_cfg, - .enum_mbus_code = vimc_enum_mbus_code, + .enum_mbus_code = vimc_sca_enum_mbus_code, .enum_frame_size = vimc_sca_enum_frame_size, .get_fmt = vimc_sca_get_fmt, .set_fmt = vimc_sca_set_fmt, @@ -199,19 +209,15 @@ static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); if (enable) { - u32 pixelformat = vsca->ved.stream->producer_pixfmt; - const struct v4l2_format_info *pix_info; + const struct vimc_pix_map *vpix; unsigned int frame_size; - if (!vimc_sca_is_pixfmt_supported(pixelformat)) { - dev_err(vsca->dev, "pixfmt (0x%08x) is not supported\n", - pixelformat); - return -EINVAL; - } + if (vsca->src_frame) + return 0; /* Save the bytes per pixel of the sink */ - pix_info = v4l2_format_info(pixelformat); - vsca->bpp = pix_info->bpp[0]; + vpix = vimc_pix_map_by_code(vsca->sink_fmt.code); + vsca->bpp = vpix->bpp; /* Calculate the width in bytes of the src frame */ vsca->src_line_size = vsca->sink_fmt.width * @@ -324,7 +330,7 @@ static void *vimc_sca_process_frame(struct vimc_ent_device *ved, ved); /* If the stream in this node is not active, just return */ - if (!ved->stream) + if (!vsca->src_frame) return ERR_PTR(-EINVAL); vimc_sca_fill_src_frame(vsca, sink_frame); diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 51359472eef2..6c53b9fc1617 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -55,13 +55,34 @@ static int vimc_sen_init_cfg(struct v4l2_subdev *sd, return 0; } +static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index); + + if (!vpix) + return -EINVAL; + + code->code = vpix->code; + + return 0; +} + static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { + const struct vimc_pix_map *vpix; + if (fse->index) return -EINVAL; + /* Only accept code in the pix map table */ + vpix = vimc_pix_map_by_code(fse->code); + if (!vpix) + return -EINVAL; + fse->min_width = VIMC_FRAME_MIN_WIDTH; fse->max_width = VIMC_FRAME_MAX_WIDTH; fse->min_height = VIMC_FRAME_MIN_HEIGHT; @@ -86,17 +107,14 @@ static int vimc_sen_get_fmt(struct v4l2_subdev *sd, static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) { - u32 pixelformat = vsen->ved.stream->producer_pixfmt; - const struct v4l2_format_info *pix_info; - - pix_info = v4l2_format_info(pixelformat); + const struct vimc_pix_map *vpix = + vimc_pix_map_by_code(vsen->mbus_format.code); tpg_reset_source(&vsen->tpg, vsen->mbus_format.width, vsen->mbus_format.height, vsen->mbus_format.field); - tpg_s_bytesperline(&vsen->tpg, 0, - vsen->mbus_format.width * pix_info->bpp[0]); + tpg_s_bytesperline(&vsen->tpg, 0, vsen->mbus_format.width * vpix->bpp); tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height); - tpg_s_fourcc(&vsen->tpg, pixelformat); + tpg_s_fourcc(&vsen->tpg, vpix->pixelformat); /* TODO: add support for V4L2_FIELD_ALTERNATE */ tpg_s_field(&vsen->tpg, vsen->mbus_format.field, false); tpg_s_colorspace(&vsen->tpg, vsen->mbus_format.colorspace); @@ -107,6 +125,13 @@ static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt) { + const struct vimc_pix_map *vpix; + + /* Only accept code in the pix map table */ + vpix = vimc_pix_map_by_code(fmt->code); + if (!vpix) + fmt->code = fmt_default.code; + fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, VIMC_FRAME_MAX_WIDTH) & ~1; fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, @@ -126,12 +151,9 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf; - if (!vimc_mbus_code_supported(fmt->format.code)) - fmt->format.code = fmt_default.code; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ - if (vsen->ved.stream) + if (vsen->frame) return -EBUSY; mf = &vsen->mbus_format; @@ -161,7 +183,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { .init_cfg = vimc_sen_init_cfg, - .enum_mbus_code = vimc_enum_mbus_code, + .enum_mbus_code = vimc_sen_enum_mbus_code, .enum_frame_size = vimc_sen_enum_frame_size, .get_fmt = vimc_sen_get_fmt, .set_fmt = vimc_sen_set_fmt, @@ -183,13 +205,16 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) container_of(sd, struct vimc_sen_device, sd); if (enable) { - u32 pixelformat = vsen->ved.stream->producer_pixfmt; - const struct v4l2_format_info *pix_info; + const struct vimc_pix_map *vpix; unsigned int frame_size; + if (vsen->kthread_sen) + /* tpg is already executing */ + return 0; + /* Calculate the frame size */ - pix_info = v4l2_format_info(pixelformat); - frame_size = vsen->mbus_format.width * pix_info->bpp[0] * + vpix = vimc_pix_map_by_code(vsen->mbus_format.code); + frame_size = vsen->mbus_format.width * vpix->bpp * vsen->mbus_format.height; /* diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c index 3b3f36357a0e..048d770e498b 100644 --- a/drivers/media/platform/vimc/vimc-streamer.c +++ b/drivers/media/platform/vimc/vimc-streamer.c @@ -20,6 +20,8 @@ * * Helper function that returns the media entity containing the source pad * linked with the first sink pad from the given media entity pad list. + * + * Return: The source pad or NULL, if it wasn't found. */ static struct media_entity *vimc_get_source_entity(struct media_entity *ent) { @@ -35,7 +37,7 @@ static struct media_entity *vimc_get_source_entity(struct media_entity *ent) return NULL; } -/* +/** * vimc_streamer_pipeline_terminate - Disable stream in all ved in stream * * @stream: the pointer to the stream structure with the pipeline to be @@ -52,7 +54,6 @@ static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) while (stream->pipe_size) { stream->pipe_size--; ved = stream->ved_pipeline[stream->pipe_size]; - ved->stream = NULL; stream->ved_pipeline[stream->pipe_size] = NULL; if (!is_media_entity_v4l2_subdev(ved->ent)) @@ -63,15 +64,18 @@ static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) } } -/* - * vimc_streamer_pipeline_init - initializes the stream structure +/** + * vimc_streamer_pipeline_init - Initializes the stream structure * * @stream: the pointer to the stream structure to be initialized * @ved: the pointer to the vimc entity initializing the stream * * Initializes the stream structure. Walks through the entity graph to * construct the pipeline used later on the streamer thread. - * Calls s_stream to enable stream in all entities of the pipeline. + * Calls vimc_streamer_s_stream() to enable stream in all entities of + * the pipeline. + * + * Return: 0 if success, error code otherwise. */ static int vimc_streamer_pipeline_init(struct vimc_stream *stream, struct vimc_ent_device *ved) @@ -88,7 +92,6 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream, return -EINVAL; } stream->ved_pipeline[stream->pipe_size++] = ved; - ved->stream = stream; if (is_media_entity_v4l2_subdev(ved->ent)) { sd = media_entity_to_v4l2_subdev(ved->ent); @@ -122,13 +125,17 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream, return -EINVAL; } -/* - * vimc_streamer_thread - process frames through the pipeline +/** + * vimc_streamer_thread - Process frames through the pipeline * * @data: vimc_stream struct of the current stream * * From the source to the sink, gets a frame from each subdevice and send to * the next one of the pipeline at a fixed framerate. + * + * Return: + * Always zero (created as ``int`` instead of ``void`` to comply with + * kthread API). */ static int vimc_streamer_thread(void *data) { @@ -157,19 +164,20 @@ static int vimc_streamer_thread(void *data) return 0; } -/* - * vimc_streamer_s_stream - start/stop the streaming on the media pipeline +/** + * vimc_streamer_s_stream - Start/stop the streaming on the media pipeline * * @stream: the pointer to the stream structure of the current stream * @ved: pointer to the vimc entity of the entity of the stream * @enable: flag to determine if stream should start/stop * - * When starting, check if there is no stream->kthread allocated. This should - * indicate that a stream is already running. Then, it initializes - * the pipeline, creates and runs a kthread to consume buffers through the - * pipeline. - * When stopping, analogously check if there is a stream running, stop - * the thread and terminates the pipeline. + * When starting, check if there is no ``stream->kthread`` allocated. This + * should indicate that a stream is already running. Then, it initializes the + * pipeline, creates and runs a kthread to consume buffers through the pipeline. + * When stopping, analogously check if there is a stream running, stop the + * thread and terminates the pipeline. + * + * Return: 0 if success, error code otherwise. */ int vimc_streamer_s_stream(struct vimc_stream *stream, struct vimc_ent_device *ved, diff --git a/drivers/media/platform/vimc/vimc-streamer.h b/drivers/media/platform/vimc/vimc-streamer.h index 2b3667408794..fe3c51f15fad 100644 --- a/drivers/media/platform/vimc/vimc-streamer.h +++ b/drivers/media/platform/vimc/vimc-streamer.h @@ -25,11 +25,6 @@ * processed in the pipeline. * @pipe_size: size of @ved_pipeline * @kthread: thread that generates the frames of the stream. - * @producer_pixfmt: the pixel format requested from the pipeline. This must - * be set just before calling vimc_streamer_s_stream(ent, 1). This value is - * propagated up to the source of the base image (usually a sensor node) and - * can be modified by entities during s_stream callback to request a different - * format from rest of the pipeline. * * When the user call stream_on in a video device, struct vimc_stream is * used to keep track of all entities and subdevices that generates and @@ -40,17 +35,8 @@ struct vimc_stream { struct vimc_ent_device *ved_pipeline[VIMC_STREAMER_PIPELINE_MAX_SIZE]; unsigned int pipe_size; struct task_struct *kthread; - u32 producer_pixfmt; }; -/** - * vimc_streamer_s_streamer - start/stop the stream - * - * @stream: the pointer to the stream to start or stop - * @ved: The last entity of the streamer pipeline - * @enable: any non-zero number start the stream, zero stop - * - */ int vimc_streamer_s_stream(struct vimc_stream *stream, struct vimc_ent_device *ved, int enable); diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index d535aac68ce1..53315c8dd2bb 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -792,7 +792,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (no_error_inj && ccs_cap == -1) ccs_cap = 7; - /* if ccs_cap == -1, then the use can select it using controls */ + /* if ccs_cap == -1, then the user can select it using controls */ if (ccs_cap != -1) { dev->has_crop_cap = ccs_cap & 1; dev->has_compose_cap = ccs_cap & 2; @@ -807,7 +807,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (no_error_inj && ccs_out == -1) ccs_out = 7; - /* if ccs_out == -1, then the use can select it using controls */ + /* if ccs_out == -1, then the user can select it using controls */ if (ccs_out != -1) { dev->has_crop_out = ccs_out & 1; dev->has_compose_out = ccs_out & 2; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 3e916c8befb7..cb19a9a73092 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -1473,7 +1473,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_handler_init(hdl_vid_cap, 55); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_vid_out, 26); - if (!no_error_inj || dev->has_fb) + if (!no_error_inj || dev->has_fb || dev->num_hdmi_outputs) v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_vbi_cap, 21); v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL); @@ -1613,6 +1613,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, } if (dev->num_hdmi_inputs) { + s64 hdmi_input_mask = GENMASK(dev->num_hdmi_inputs - 1, 0); + dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_dv_timings_signal_mode, NULL); @@ -1633,12 +1635,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 0, V4L2_DV_RGB_RANGE_AUTO); dev->ctrl_rx_power_present = v4l2_ctrl_new_std(hdl_vid_cap, - NULL, V4L2_CID_DV_RX_POWER_PRESENT, 0, - (2 << (dev->num_hdmi_inputs - 1)) - 1, 0, - (2 << (dev->num_hdmi_inputs - 1)) - 1); + NULL, V4L2_CID_DV_RX_POWER_PRESENT, 0, hdmi_input_mask, + 0, hdmi_input_mask); } if (dev->num_hdmi_outputs) { + s64 hdmi_output_mask = GENMASK(dev->num_hdmi_outputs - 1, 0); + /* * We aren't doing anything with this at the moment, but * HDMI outputs typically have this controls. @@ -1652,17 +1655,14 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, dev->ctrl_display_present = v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_display_present, NULL); dev->ctrl_tx_hotplug = v4l2_ctrl_new_std(hdl_vid_out, - NULL, V4L2_CID_DV_TX_HOTPLUG, 0, - (2 << (dev->num_hdmi_outputs - 1)) - 1, 0, - (2 << (dev->num_hdmi_outputs - 1)) - 1); + NULL, V4L2_CID_DV_TX_HOTPLUG, 0, hdmi_output_mask, + 0, hdmi_output_mask); dev->ctrl_tx_rxsense = v4l2_ctrl_new_std(hdl_vid_out, - NULL, V4L2_CID_DV_TX_RXSENSE, 0, - (2 << (dev->num_hdmi_outputs - 1)) - 1, 0, - (2 << (dev->num_hdmi_outputs - 1)) - 1); + NULL, V4L2_CID_DV_TX_RXSENSE, 0, hdmi_output_mask, + 0, hdmi_output_mask); dev->ctrl_tx_edid_present = v4l2_ctrl_new_std(hdl_vid_out, - NULL, V4L2_CID_DV_TX_EDID_PRESENT, 0, - (2 << (dev->num_hdmi_outputs - 1)) - 1, 0, - (2 << (dev->num_hdmi_outputs - 1)) - 1); + NULL, V4L2_CID_DV_TX_EDID_PRESENT, 0, hdmi_output_mask, + 0, hdmi_output_mask); } if ((dev->has_vid_cap && dev->has_vid_out) || (dev->has_vbi_cap && dev->has_vbi_out)) diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 6cf495a7d5cc..003319d7816d 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -232,8 +232,8 @@ static void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf, return vbuf; } -static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, - struct vivid_buffer *vid_cap_buf) +static noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, + u8 *vcapbuf, struct vivid_buffer *vid_cap_buf) { bool blank = dev->must_blank[vid_cap_buf->vb.vb2_buf.index]; struct tpg_data *tpg = &dev->tpg; @@ -658,6 +658,8 @@ static void vivid_cap_update_frame_period(struct vivid_dev *dev) u64 f_period; f_period = (u64)dev->timeperframe_vid_cap.numerator * 1000000000; + if (WARN_ON(dev->timeperframe_vid_cap.denominator == 0)) + dev->timeperframe_vid_cap.denominator = 1; do_div(f_period, dev->timeperframe_vid_cap.denominator); if (dev->field_cap == V4L2_FIELD_ALTERNATE) f_period >>= 1; @@ -670,7 +672,8 @@ static void vivid_cap_update_frame_period(struct vivid_dev *dev) dev->cap_frame_period = f_period; } -static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs) +static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, + int dropped_bufs) { struct vivid_buffer *vid_cap_buf = NULL; struct vivid_buffer *vbi_cap_buf = NULL; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 1f33eb1a76b6..8665dfd25eb4 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -262,21 +262,66 @@ struct vivid_fmt vivid_formats[] = { .can_do_overlay = true, }, { - .fourcc = V4L2_PIX_FMT_RGB444, /* xxxxrrrr ggggbbbb */ + .fourcc = V4L2_PIX_FMT_RGB444, /* ggggbbbb xxxxrrrr */ .vdownsampling = { 1 }, .bit_depth = { 16 }, .planes = 1, .buffers = 1, }, { - .fourcc = V4L2_PIX_FMT_XRGB444, /* xxxxrrrr ggggbbbb */ + .fourcc = V4L2_PIX_FMT_XRGB444, /* ggggbbbb xxxxrrrr */ .vdownsampling = { 1 }, .bit_depth = { 16 }, .planes = 1, .buffers = 1, }, { - .fourcc = V4L2_PIX_FMT_ARGB444, /* aaaarrrr ggggbbbb */ + .fourcc = V4L2_PIX_FMT_ARGB444, /* ggggbbbb aaaarrrr */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x00f0, + }, + { + .fourcc = V4L2_PIX_FMT_RGBX444, /* bbbbxxxx rrrrgggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGBA444, /* bbbbaaaa rrrrgggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x00f0, + }, + { + .fourcc = V4L2_PIX_FMT_XBGR444, /* ggggrrrr xxxxbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ABGR444, /* ggggrrrr aaaabbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x00f0, + }, + { + .fourcc = V4L2_PIX_FMT_BGRX444, /* rrrrxxxx bbbbgggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_BGRA444, /* rrrraaaa bbbbgggg */ .vdownsampling = { 1 }, .bit_depth = { 16 }, .planes = 1, @@ -309,6 +354,57 @@ struct vivid_fmt vivid_formats[] = { .alpha_mask = 0x8000, }, { + .fourcc = V4L2_PIX_FMT_RGBX555, /* ggbbbbbx rrrrrggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + }, + { + .fourcc = V4L2_PIX_FMT_RGBA555, /* ggbbbbba rrrrrggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + .alpha_mask = 0x8000, + }, + { + .fourcc = V4L2_PIX_FMT_XBGR555, /* gggrrrrr xbbbbbgg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + }, + { + .fourcc = V4L2_PIX_FMT_ABGR555, /* gggrrrrr abbbbbgg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + .alpha_mask = 0x8000, + }, + { + .fourcc = V4L2_PIX_FMT_BGRX555, /* ggrrrrrx bbbbbggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + }, + { + .fourcc = V4L2_PIX_FMT_BGRA555, /* ggrrrrra bbbbbggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + .alpha_mask = 0x8000, + }, + { .fourcc = V4L2_PIX_FMT_RGB555X, /* xrrrrrgg gggbbbbb */ .vdownsampling = { 1 }, .bit_depth = { 16 }, @@ -396,6 +492,36 @@ struct vivid_fmt vivid_formats[] = { .alpha_mask = 0xff000000, }, { + .fourcc = V4L2_PIX_FMT_RGBX32, /* rgbx */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_BGRX32, /* xbgr */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGBA32, /* rgba */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x000000ff, + }, + { + .fourcc = V4L2_PIX_FMT_BGRA32, /* abgr */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0xff000000, + }, + { .fourcc = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */ .vdownsampling = { 1 }, .bit_depth = { 8 }, diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index 104b6f514536..d7b43037e500 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c @@ -557,8 +557,10 @@ static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm) /* Get a default body for our list. */ dl->body0 = vsp1_dl_body_get(dlm->pool); - if (!dl->body0) + if (!dl->body0) { + kfree(dl); return NULL; + } header_offset = dl->body0->max_entries * sizeof(*dl->body0->entries); diff --git a/drivers/media/platform/vsp1/vsp1_histo.c b/drivers/media/platform/vsp1/vsp1_histo.c index 8b01e99acd20..30d751f2cccf 100644 --- a/drivers/media/platform/vsp1/vsp1_histo.c +++ b/drivers/media/platform/vsp1/vsp1_histo.c @@ -426,8 +426,6 @@ static int histo_v4l2_querycap(struct file *file, void *fh, | V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_META_CAPTURE; - cap->device_caps = V4L2_CAP_META_CAPTURE - | V4L2_CAP_STREAMING; strscpy(cap->driver, "vsp1", sizeof(cap->driver)); strscpy(cap->card, histo->video.name, sizeof(cap->card)); @@ -556,6 +554,7 @@ int vsp1_histogram_init(struct vsp1_device *vsp1, struct vsp1_histogram *histo, histo->video.vfl_type = VFL_TYPE_GRABBER; histo->video.release = video_device_release_empty; histo->video.ioctl_ops = &histo_v4l2_ioctl_ops; + histo->video.device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING; video_set_drvdata(&histo->video, histo); diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 1bb1d39c60d9..5c67ff92d97a 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -15,8 +15,8 @@ */ #define VI6_CMD(n) (0x0000 + (n) * 4) -#define VI6_CMD_UPDHDR (1 << 4) -#define VI6_CMD_STRCMD (1 << 0) +#define VI6_CMD_UPDHDR BIT(4) +#define VI6_CMD_STRCMD BIT(0) #define VI6_CLK_DCSWT 0x0018 #define VI6_CLK_DCSWT_CSTPW_MASK (0xff << 8) @@ -25,29 +25,29 @@ #define VI6_CLK_DCSWT_CSTRW_SHIFT 0 #define VI6_SRESET 0x0028 -#define VI6_SRESET_SRTS(n) (1 << (n)) +#define VI6_SRESET_SRTS(n) BIT(n) #define VI6_STATUS 0x0038 -#define VI6_STATUS_FLD_STD(n) (1 << ((n) + 28)) -#define VI6_STATUS_SYS_ACT(n) (1 << ((n) + 8)) +#define VI6_STATUS_FLD_STD(n) BIT((n) + 28) +#define VI6_STATUS_SYS_ACT(n) BIT((n) + 8) #define VI6_WPF_IRQ_ENB(n) (0x0048 + (n) * 12) -#define VI6_WFP_IRQ_ENB_DFEE (1 << 1) -#define VI6_WFP_IRQ_ENB_FREE (1 << 0) +#define VI6_WFP_IRQ_ENB_DFEE BIT(1) +#define VI6_WFP_IRQ_ENB_FREE BIT(0) #define VI6_WPF_IRQ_STA(n) (0x004c + (n) * 12) -#define VI6_WFP_IRQ_STA_DFE (1 << 1) -#define VI6_WFP_IRQ_STA_FRE (1 << 0) +#define VI6_WFP_IRQ_STA_DFE BIT(1) +#define VI6_WFP_IRQ_STA_FRE BIT(0) #define VI6_DISP_IRQ_ENB(n) (0x0078 + (n) * 60) -#define VI6_DISP_IRQ_ENB_DSTE (1 << 8) -#define VI6_DISP_IRQ_ENB_MAEE (1 << 5) -#define VI6_DISP_IRQ_ENB_LNEE(n) (1 << (n)) +#define VI6_DISP_IRQ_ENB_DSTE BIT(8) +#define VI6_DISP_IRQ_ENB_MAEE BIT(5) +#define VI6_DISP_IRQ_ENB_LNEE(n) BIT(n) #define VI6_DISP_IRQ_STA(n) (0x007c + (n) * 60) -#define VI6_DISP_IRQ_STA_DST (1 << 8) -#define VI6_DISP_IRQ_STA_MAE (1 << 5) -#define VI6_DISP_IRQ_STA_LNE(n) (1 << (n)) +#define VI6_DISP_IRQ_STA_DST BIT(8) +#define VI6_DISP_IRQ_STA_MAE BIT(5) +#define VI6_DISP_IRQ_STA_LNE(n) BIT(n) #define VI6_WPF_LINE_COUNT(n) (0x0084 + (n) * 4) #define VI6_WPF_LINE_COUNT_MASK (0x1fffff << 0) @@ -59,32 +59,32 @@ #define VI6_DL_CTRL 0x0100 #define VI6_DL_CTRL_AR_WAIT_MASK (0xffff << 16) #define VI6_DL_CTRL_AR_WAIT_SHIFT 16 -#define VI6_DL_CTRL_DC2 (1 << 12) -#define VI6_DL_CTRL_DC1 (1 << 8) -#define VI6_DL_CTRL_DC0 (1 << 4) -#define VI6_DL_CTRL_CFM0 (1 << 2) -#define VI6_DL_CTRL_NH0 (1 << 1) -#define VI6_DL_CTRL_DLE (1 << 0) +#define VI6_DL_CTRL_DC2 BIT(12) +#define VI6_DL_CTRL_DC1 BIT(8) +#define VI6_DL_CTRL_DC0 BIT(4) +#define VI6_DL_CTRL_CFM0 BIT(2) +#define VI6_DL_CTRL_NH0 BIT(1) +#define VI6_DL_CTRL_DLE BIT(0) #define VI6_DL_HDR_ADDR(n) (0x0104 + (n) * 4) #define VI6_DL_SWAP 0x0114 -#define VI6_DL_SWAP_LWS (1 << 2) -#define VI6_DL_SWAP_WDS (1 << 1) -#define VI6_DL_SWAP_BTS (1 << 0) +#define VI6_DL_SWAP_LWS BIT(2) +#define VI6_DL_SWAP_WDS BIT(1) +#define VI6_DL_SWAP_BTS BIT(0) #define VI6_DL_EXT_CTRL(n) (0x011c + (n) * 36) -#define VI6_DL_EXT_CTRL_NWE (1 << 16) +#define VI6_DL_EXT_CTRL_NWE BIT(16) #define VI6_DL_EXT_CTRL_POLINT_MASK (0x3f << 8) #define VI6_DL_EXT_CTRL_POLINT_SHIFT 8 -#define VI6_DL_EXT_CTRL_DLPRI (1 << 5) -#define VI6_DL_EXT_CTRL_EXPRI (1 << 4) -#define VI6_DL_EXT_CTRL_EXT (1 << 0) +#define VI6_DL_EXT_CTRL_DLPRI BIT(5) +#define VI6_DL_EXT_CTRL_EXPRI BIT(4) +#define VI6_DL_EXT_CTRL_EXT BIT(0) #define VI6_DL_EXT_AUTOFLD_INT BIT(0) #define VI6_DL_BODY_SIZE 0x0120 -#define VI6_DL_BODY_SIZE_UPD (1 << 24) +#define VI6_DL_BODY_SIZE_UPD BIT(24) #define VI6_DL_BODY_SIZE_BS_MASK (0x1ffff << 0) #define VI6_DL_BODY_SIZE_BS_SHIFT 0 @@ -107,10 +107,10 @@ #define VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT 0 #define VI6_RPF_INFMT 0x0308 -#define VI6_RPF_INFMT_VIR (1 << 28) -#define VI6_RPF_INFMT_CIPM (1 << 16) -#define VI6_RPF_INFMT_SPYCS (1 << 15) -#define VI6_RPF_INFMT_SPUVS (1 << 14) +#define VI6_RPF_INFMT_VIR BIT(28) +#define VI6_RPF_INFMT_CIPM BIT(16) +#define VI6_RPF_INFMT_SPYCS BIT(15) +#define VI6_RPF_INFMT_SPUVS BIT(14) #define VI6_RPF_INFMT_CEXT_ZERO (0 << 12) #define VI6_RPF_INFMT_CEXT_EXT (1 << 12) #define VI6_RPF_INFMT_CEXT_ONE (2 << 12) @@ -120,19 +120,19 @@ #define VI6_RPF_INFMT_RDTM_BT709 (2 << 9) #define VI6_RPF_INFMT_RDTM_BT709_EXT (3 << 9) #define VI6_RPF_INFMT_RDTM_MASK (7 << 9) -#define VI6_RPF_INFMT_CSC (1 << 8) +#define VI6_RPF_INFMT_CSC BIT(8) #define VI6_RPF_INFMT_RDFMT_MASK (0x7f << 0) #define VI6_RPF_INFMT_RDFMT_SHIFT 0 #define VI6_RPF_DSWAP 0x030c -#define VI6_RPF_DSWAP_A_LLS (1 << 11) -#define VI6_RPF_DSWAP_A_LWS (1 << 10) -#define VI6_RPF_DSWAP_A_WDS (1 << 9) -#define VI6_RPF_DSWAP_A_BTS (1 << 8) -#define VI6_RPF_DSWAP_P_LLS (1 << 3) -#define VI6_RPF_DSWAP_P_LWS (1 << 2) -#define VI6_RPF_DSWAP_P_WDS (1 << 1) -#define VI6_RPF_DSWAP_P_BTS (1 << 0) +#define VI6_RPF_DSWAP_A_LLS BIT(11) +#define VI6_RPF_DSWAP_A_LWS BIT(10) +#define VI6_RPF_DSWAP_A_WDS BIT(9) +#define VI6_RPF_DSWAP_A_BTS BIT(8) +#define VI6_RPF_DSWAP_P_LLS BIT(3) +#define VI6_RPF_DSWAP_P_LWS BIT(2) +#define VI6_RPF_DSWAP_P_WDS BIT(1) +#define VI6_RPF_DSWAP_P_BTS BIT(0) #define VI6_RPF_LOC 0x0310 #define VI6_RPF_LOC_HCOORD_MASK (0x1fff << 16) @@ -150,7 +150,7 @@ #define VI6_RPF_ALPH_SEL_ASEL_SHIFT 28 #define VI6_RPF_ALPH_SEL_IROP_MASK (0xf << 24) #define VI6_RPF_ALPH_SEL_IROP_SHIFT 24 -#define VI6_RPF_ALPH_SEL_BSEL (1 << 23) +#define VI6_RPF_ALPH_SEL_BSEL BIT(23) #define VI6_RPF_ALPH_SEL_AEXT_ZERO (0 << 18) #define VI6_RPF_ALPH_SEL_AEXT_EXT (1 << 18) #define VI6_RPF_ALPH_SEL_AEXT_ONE (2 << 18) @@ -171,7 +171,7 @@ #define VI6_RPF_VRTCOL_SET_LAYB_SHIFT 0 #define VI6_RPF_MSK_CTRL 0x031c -#define VI6_RPF_MSK_CTRL_MSK_EN (1 << 24) +#define VI6_RPF_MSK_CTRL_MSK_EN BIT(24) #define VI6_RPF_MSK_CTRL_MGR_MASK (0xff << 16) #define VI6_RPF_MSK_CTRL_MGR_SHIFT 16 #define VI6_RPF_MSK_CTRL_MGG_MASK (0xff << 8) @@ -191,9 +191,9 @@ #define VI6_RPF_MSK_SET_MSB_SHIFT 0 #define VI6_RPF_CKEY_CTRL 0x0328 -#define VI6_RPF_CKEY_CTRL_CV (1 << 4) -#define VI6_RPF_CKEY_CTRL_SAPE1 (1 << 1) -#define VI6_RPF_CKEY_CTRL_SAPE0 (1 << 0) +#define VI6_RPF_CKEY_CTRL_CV BIT(4) +#define VI6_RPF_CKEY_CTRL_SAPE1 BIT(1) +#define VI6_RPF_CKEY_CTRL_SAPE0 BIT(0) #define VI6_RPF_CKEY_SET0 0x032c #define VI6_RPF_CKEY_SET1 0x0330 @@ -250,7 +250,7 @@ #define VI6_WPF_HSZCLIP 0x1004 #define VI6_WPF_VSZCLIP 0x1008 -#define VI6_WPF_SZCLIP_EN (1 << 28) +#define VI6_WPF_SZCLIP_EN BIT(28) #define VI6_WPF_SZCLIP_OFST_MASK (0xff << 16) #define VI6_WPF_SZCLIP_OFST_SHIFT 16 #define VI6_WPF_SZCLIP_SIZE_MASK (0xfff << 0) @@ -259,12 +259,12 @@ #define VI6_WPF_OUTFMT 0x100c #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_OUTFMT_PXA BIT(23) +#define VI6_WPF_OUTFMT_ROT BIT(18) +#define VI6_WPF_OUTFMT_HFLP BIT(17) +#define VI6_WPF_OUTFMT_FLP BIT(16) +#define VI6_WPF_OUTFMT_SPYCS BIT(15) +#define VI6_WPF_OUTFMT_SPUVS BIT(14) #define VI6_WPF_OUTFMT_DITH_DIS (0 << 12) #define VI6_WPF_OUTFMT_DITH_EN (3 << 12) #define VI6_WPF_OUTFMT_DITH_MASK (3 << 12) @@ -273,18 +273,18 @@ #define VI6_WPF_OUTFMT_WRTM_BT709 (2 << 9) #define VI6_WPF_OUTFMT_WRTM_BT709_EXT (3 << 9) #define VI6_WPF_OUTFMT_WRTM_MASK (7 << 9) -#define VI6_WPF_OUTFMT_CSC (1 << 8) +#define VI6_WPF_OUTFMT_CSC BIT(8) #define VI6_WPF_OUTFMT_WRFMT_MASK (0x7f << 0) #define VI6_WPF_OUTFMT_WRFMT_SHIFT 0 #define VI6_WPF_DSWAP 0x1010 -#define VI6_WPF_DSWAP_P_LLS (1 << 3) -#define VI6_WPF_DSWAP_P_LWS (1 << 2) -#define VI6_WPF_DSWAP_P_WDS (1 << 1) -#define VI6_WPF_DSWAP_P_BTS (1 << 0) +#define VI6_WPF_DSWAP_P_LLS BIT(3) +#define VI6_WPF_DSWAP_P_LWS BIT(2) +#define VI6_WPF_DSWAP_P_WDS BIT(1) +#define VI6_WPF_DSWAP_P_BTS BIT(0) #define VI6_WPF_RNDCTRL 0x1014 -#define VI6_WPF_RNDCTRL_CBRM (1 << 28) +#define VI6_WPF_RNDCTRL_CBRM BIT(28) #define VI6_WPF_RNDCTRL_ABRM_TRUNC (0 << 24) #define VI6_WPF_RNDCTRL_ABRM_ROUND (1 << 24) #define VI6_WPF_RNDCTRL_ABRM_THRESH (2 << 24) @@ -297,7 +297,7 @@ #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_LN16 BIT(17) #define VI6_WPF_ROT_CTRL_LMEM_WD_MASK (0x1fff << 0) #define VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT 0 @@ -308,7 +308,7 @@ #define VI6_WPF_DSTM_ADDR_C1 0x102c #define VI6_WPF_WRBCK_CTRL(n) (0x1034 + (n) * 0x100) -#define VI6_WPF_WRBCK_CTRL_WBMD (1 << 0) +#define VI6_WPF_WRBCK_CTRL_WBMD BIT(0) /* ----------------------------------------------------------------------------- * UIF Control Registers @@ -317,20 +317,20 @@ #define VI6_UIF_OFFSET 0x100 #define VI6_UIF_DISCOM_DOCMCR 0x1c00 -#define VI6_UIF_DISCOM_DOCMCR_CMPRU (1 << 16) -#define VI6_UIF_DISCOM_DOCMCR_CMPR (1 << 0) +#define VI6_UIF_DISCOM_DOCMCR_CMPRU BIT(16) +#define VI6_UIF_DISCOM_DOCMCR_CMPR BIT(0) #define VI6_UIF_DISCOM_DOCMSTR 0x1c04 -#define VI6_UIF_DISCOM_DOCMSTR_CMPPRE (1 << 1) -#define VI6_UIF_DISCOM_DOCMSTR_CMPST (1 << 0) +#define VI6_UIF_DISCOM_DOCMSTR_CMPPRE BIT(1) +#define VI6_UIF_DISCOM_DOCMSTR_CMPST BIT(0) #define VI6_UIF_DISCOM_DOCMCLSTR 0x1c08 -#define VI6_UIF_DISCOM_DOCMCLSTR_CMPCLPRE (1 << 1) -#define VI6_UIF_DISCOM_DOCMCLSTR_CMPCLST (1 << 0) +#define VI6_UIF_DISCOM_DOCMCLSTR_CMPCLPRE BIT(1) +#define VI6_UIF_DISCOM_DOCMCLSTR_CMPCLST BIT(0) #define VI6_UIF_DISCOM_DOCMIENR 0x1c0c -#define VI6_UIF_DISCOM_DOCMIENR_CMPPREIEN (1 << 1) -#define VI6_UIF_DISCOM_DOCMIENR_CMPIEN (1 << 0) +#define VI6_UIF_DISCOM_DOCMIENR_CMPPREIEN BIT(1) +#define VI6_UIF_DISCOM_DOCMIENR_CMPIEN BIT(0) #define VI6_UIF_DISCOM_DOCMMDR 0x1c10 #define VI6_UIF_DISCOM_DOCMMDR_INTHRH(n) ((n) << 16) @@ -338,7 +338,7 @@ #define VI6_UIF_DISCOM_DOCMPMR 0x1c14 #define VI6_UIF_DISCOM_DOCMPMR_CMPDFF(n) ((n) << 17) #define VI6_UIF_DISCOM_DOCMPMR_CMPDFA(n) ((n) << 8) -#define VI6_UIF_DISCOM_DOCMPMR_CMPDAUF (1 << 7) +#define VI6_UIF_DISCOM_DOCMPMR_CMPDAUF BIT(7) #define VI6_UIF_DISCOM_DOCMPMR_SEL(n) ((n) << 0) #define VI6_UIF_DISCOM_DOCMECRCR 0x1c18 @@ -365,7 +365,7 @@ #define VI6_DPR_HSI_ROUTE 0x2048 #define VI6_DPR_BRU_ROUTE 0x204c #define VI6_DPR_ILV_BRS_ROUTE 0x2050 -#define VI6_DPR_ROUTE_BRSSEL (1 << 28) +#define VI6_DPR_ROUTE_BRSSEL BIT(28) #define VI6_DPR_ROUTE_FXA_MASK (0xff << 16) #define VI6_DPR_ROUTE_FXA_SHIFT 16 #define VI6_DPR_ROUTE_FP_MASK (0x3f << 8) @@ -407,10 +407,10 @@ #define VI6_SRU_CTRL0_PARAM1_MASK (0x1f << 8) #define VI6_SRU_CTRL0_PARAM1_SHIFT 8 #define VI6_SRU_CTRL0_MODE_UPSCALE (4 << 4) -#define VI6_SRU_CTRL0_PARAM2 (1 << 3) -#define VI6_SRU_CTRL0_PARAM3 (1 << 2) -#define VI6_SRU_CTRL0_PARAM4 (1 << 1) -#define VI6_SRU_CTRL0_EN (1 << 0) +#define VI6_SRU_CTRL0_PARAM2 BIT(3) +#define VI6_SRU_CTRL0_PARAM3 BIT(2) +#define VI6_SRU_CTRL0_PARAM4 BIT(1) +#define VI6_SRU_CTRL0_EN BIT(0) #define VI6_SRU_CTRL1 0x2204 #define VI6_SRU_CTRL1_PARAM5 0x7ff @@ -427,18 +427,18 @@ #define VI6_UDS_OFFSET 0x100 #define VI6_UDS_CTRL 0x2300 -#define VI6_UDS_CTRL_AMD (1 << 30) -#define VI6_UDS_CTRL_FMD (1 << 29) -#define VI6_UDS_CTRL_BLADV (1 << 28) -#define VI6_UDS_CTRL_AON (1 << 25) -#define VI6_UDS_CTRL_ATHON (1 << 24) -#define VI6_UDS_CTRL_BC (1 << 20) -#define VI6_UDS_CTRL_NE_A (1 << 19) -#define VI6_UDS_CTRL_NE_RCR (1 << 18) -#define VI6_UDS_CTRL_NE_GY (1 << 17) -#define VI6_UDS_CTRL_NE_BCB (1 << 16) -#define VI6_UDS_CTRL_AMDSLH (1 << 2) -#define VI6_UDS_CTRL_TDIPC (1 << 1) +#define VI6_UDS_CTRL_AMD BIT(30) +#define VI6_UDS_CTRL_FMD BIT(29) +#define VI6_UDS_CTRL_BLADV BIT(28) +#define VI6_UDS_CTRL_AON BIT(25) +#define VI6_UDS_CTRL_ATHON BIT(24) +#define VI6_UDS_CTRL_BC BIT(20) +#define VI6_UDS_CTRL_NE_A BIT(19) +#define VI6_UDS_CTRL_NE_RCR BIT(18) +#define VI6_UDS_CTRL_NE_GY BIT(17) +#define VI6_UDS_CTRL_NE_BCB BIT(16) +#define VI6_UDS_CTRL_AMDSLH BIT(2) +#define VI6_UDS_CTRL_TDIPC BIT(1) #define VI6_UDS_SCALE 0x2304 #define VI6_UDS_SCALE_HMANT_MASK (0xf << 28) @@ -477,12 +477,12 @@ #define VI6_UDS_HPHASE_HEDP_SHIFT 0 #define VI6_UDS_IPC 0x2318 -#define VI6_UDS_IPC_FIELD (1 << 27) +#define VI6_UDS_IPC_FIELD BIT(27) #define VI6_UDS_IPC_VEDP_MASK (0xfff << 0) #define VI6_UDS_IPC_VEDP_SHIFT 0 #define VI6_UDS_HSZCLIP 0x231c -#define VI6_UDS_HSZCLIP_HCEN (1 << 28) +#define VI6_UDS_HSZCLIP_HCEN BIT(28) #define VI6_UDS_HSZCLIP_HCL_OFST_MASK (0xff << 16) #define VI6_UDS_HSZCLIP_HCL_OFST_SHIFT 16 #define VI6_UDS_HSZCLIP_HCL_SIZE_MASK (0x1fff << 0) @@ -507,36 +507,36 @@ */ #define VI6_LUT_CTRL 0x2800 -#define VI6_LUT_CTRL_EN (1 << 0) +#define VI6_LUT_CTRL_EN BIT(0) /* ----------------------------------------------------------------------------- * CLU Control Registers */ #define VI6_CLU_CTRL 0x2900 -#define VI6_CLU_CTRL_AAI (1 << 28) -#define VI6_CLU_CTRL_MVS (1 << 24) +#define VI6_CLU_CTRL_AAI BIT(28) +#define VI6_CLU_CTRL_MVS BIT(24) #define VI6_CLU_CTRL_AX1I_2D (3 << 14) #define VI6_CLU_CTRL_AX2I_2D (1 << 12) #define VI6_CLU_CTRL_OS0_2D (3 << 8) #define VI6_CLU_CTRL_OS1_2D (1 << 6) #define VI6_CLU_CTRL_OS2_2D (3 << 4) -#define VI6_CLU_CTRL_M2D (1 << 1) -#define VI6_CLU_CTRL_EN (1 << 0) +#define VI6_CLU_CTRL_M2D BIT(1) +#define VI6_CLU_CTRL_EN BIT(0) /* ----------------------------------------------------------------------------- * HST Control Registers */ #define VI6_HST_CTRL 0x2a00 -#define VI6_HST_CTRL_EN (1 << 0) +#define VI6_HST_CTRL_EN BIT(0) /* ----------------------------------------------------------------------------- * HSI Control Registers */ #define VI6_HSI_CTRL 0x2b00 -#define VI6_HSI_CTRL_EN (1 << 0) +#define VI6_HSI_CTRL_EN BIT(0) /* ----------------------------------------------------------------------------- * BRS and BRU Control Registers @@ -563,7 +563,7 @@ #define VI6_BRS_BASE 0x3900 #define VI6_BRU_INCTRL 0x0000 -#define VI6_BRU_INCTRL_NRM (1 << 28) +#define VI6_BRU_INCTRL_NRM BIT(28) #define VI6_BRU_INCTRL_DnON (1 << (16 + (n))) #define VI6_BRU_INCTRL_DITHn_OFF (0 << ((n) * 4)) #define VI6_BRU_INCTRL_DITHn_18BPP (1 << ((n) * 4)) @@ -597,7 +597,7 @@ #define VI6_BRU_VIRRPF_COL_BCB_SHIFT 0 #define VI6_BRU_CTRL(n) (0x0010 + (n) * 8 + ((n) <= 3 ? 0 : 4)) -#define VI6_BRU_CTRL_RBC (1 << 31) +#define VI6_BRU_CTRL_RBC BIT(31) #define VI6_BRU_CTRL_DSTSEL_BRUIN(n) (((n) <= 3 ? (n) : (n)+1) << 20) #define VI6_BRU_CTRL_DSTSEL_VRPF (4 << 20) #define VI6_BRU_CTRL_DSTSEL_MASK (7 << 20) @@ -610,7 +610,7 @@ #define VI6_BRU_CTRL_AROP_MASK (0xf << 0) #define VI6_BRU_BLD(n) (0x0014 + (n) * 8 + ((n) <= 3 ? 0 : 4)) -#define VI6_BRU_BLD_CBES (1 << 31) +#define VI6_BRU_BLD_CBES BIT(31) #define VI6_BRU_BLD_CCMDX_DST_A (0 << 28) #define VI6_BRU_BLD_CCMDX_255_DST_A (1 << 28) #define VI6_BRU_BLD_CCMDX_SRC_A (2 << 28) @@ -624,7 +624,7 @@ #define VI6_BRU_BLD_CCMDY_COEFY (4 << 24) #define VI6_BRU_BLD_CCMDY_MASK (7 << 24) #define VI6_BRU_BLD_CCMDY_SHIFT 24 -#define VI6_BRU_BLD_ABES (1 << 23) +#define VI6_BRU_BLD_ABES BIT(23) #define VI6_BRU_BLD_ACMDX_DST_A (0 << 20) #define VI6_BRU_BLD_ACMDX_255_DST_A (1 << 20) #define VI6_BRU_BLD_ACMDX_SRC_A (2 << 20) @@ -662,11 +662,11 @@ #define VI6_HGO_SIZE_HSIZE_SHIFT 16 #define VI6_HGO_SIZE_VSIZE_SHIFT 0 #define VI6_HGO_MODE 0x3008 -#define VI6_HGO_MODE_STEP (1 << 10) -#define VI6_HGO_MODE_MAXRGB (1 << 7) -#define VI6_HGO_MODE_OFSB_R (1 << 6) -#define VI6_HGO_MODE_OFSB_G (1 << 5) -#define VI6_HGO_MODE_OFSB_B (1 << 4) +#define VI6_HGO_MODE_STEP BIT(10) +#define VI6_HGO_MODE_MAXRGB BIT(7) +#define VI6_HGO_MODE_OFSB_R BIT(6) +#define VI6_HGO_MODE_OFSB_G BIT(5) +#define VI6_HGO_MODE_OFSB_B BIT(4) #define VI6_HGO_MODE_HRATIO_SHIFT 2 #define VI6_HGO_MODE_VRATIO_SHIFT 0 #define VI6_HGO_LB_TH 0x300c @@ -687,7 +687,7 @@ #define VI6_HGO_EXT_HIST_ADDR 0x335c #define VI6_HGO_EXT_HIST_DATA 0x3360 #define VI6_HGO_REGRST 0x33fc -#define VI6_HGO_REGRST_RCLEA (1 << 0) +#define VI6_HGO_REGRST_RCLEA BIT(0) /* ----------------------------------------------------------------------------- * HGT Control Registers @@ -713,7 +713,7 @@ #define VI6_HGT_SUM 0x3754 #define VI6_HGT_LB_DET 0x3758 #define VI6_HGT_REGRST 0x37fc -#define VI6_HGT_REGRST_RCLEA (1 << 0) +#define VI6_HGT_REGRST_RCLEA BIT(0) /* ----------------------------------------------------------------------------- * LIF Control Registers @@ -724,9 +724,9 @@ #define VI6_LIF_CTRL 0x3b00 #define VI6_LIF_CTRL_OBTH_MASK (0x7ff << 16) #define VI6_LIF_CTRL_OBTH_SHIFT 16 -#define VI6_LIF_CTRL_CFMT (1 << 4) -#define VI6_LIF_CTRL_REQSEL (1 << 1) -#define VI6_LIF_CTRL_LIF_EN (1 << 0) +#define VI6_LIF_CTRL_CFMT BIT(4) +#define VI6_LIF_CTRL_REQSEL BIT(1) +#define VI6_LIF_CTRL_LIF_EN BIT(0) #define VI6_LIF_CSBTH 0x3b04 #define VI6_LIF_CSBTH_HBTH_MASK (0x7ff << 16) @@ -735,7 +735,7 @@ #define VI6_LIF_CSBTH_LBTH_SHIFT 0 #define VI6_LIF_LBA 0x3b0c -#define VI6_LIF_LBA_LBA0 (1 << 31) +#define VI6_LIF_LBA_LBA0 BIT(31) #define VI6_LIF_LBA_LBA1_MASK (0xfff << 16) #define VI6_LIF_LBA_LBA1_SHIFT 16 diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index fd98e483b2f4..5e59ed2c3614 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -956,12 +956,6 @@ vsp1_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) | V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE - | V4L2_CAP_STREAMING; - else - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE - | V4L2_CAP_STREAMING; strscpy(cap->driver, "vsp1", sizeof(cap->driver)); strscpy(cap->card, video->video.name, sizeof(cap->card)); @@ -1268,11 +1262,15 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1, video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; video->pad.flags = MEDIA_PAD_FL_SOURCE; video->video.vfl_dir = VFL_DIR_TX; + video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_STREAMING; } else { direction = "output"; video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; video->pad.flags = MEDIA_PAD_FL_SINK; video->video.vfl_dir = VFL_DIR_RX; + video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_STREAMING; } mutex_init(&video->lock); diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index c9d5fdb2d407..b211380a11f2 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -491,15 +491,8 @@ xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap) struct v4l2_fh *vfh = file->private_data; struct xvip_dma *dma = to_xvip_dma(vfh->vdev); - cap->device_caps = V4L2_CAP_STREAMING; - - if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - else - cap->device_caps |= V4L2_CAP_VIDEO_OUTPUT; - - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS - | dma->xdev->v4l2_caps; + cap->capabilities = dma->xdev->v4l2_caps | V4L2_CAP_STREAMING | + V4L2_CAP_DEVICE_CAPS; strscpy(cap->driver, "xilinx-vipp", sizeof(cap->driver)); strscpy(cap->card, dma->video.name, sizeof(cap->card)); @@ -524,8 +517,6 @@ xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) return -EINVAL; f->pixelformat = dma->format.pixelformat; - strscpy(f->description, dma->fmtinfo->description, - sizeof(f->description)); return 0; } @@ -700,6 +691,11 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, dma->video.release = video_device_release_empty; dma->video.ioctl_ops = &xvip_dma_ioctl_ops; dma->video.lock = &dma->lock; + dma->video.device_caps = V4L2_CAP_STREAMING; + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + dma->video.device_caps |= V4L2_CAP_VIDEO_CAPTURE; + else + dma->video.device_caps |= V4L2_CAP_VIDEO_OUTPUT; video_set_drvdata(&dma->video, dma); diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c index 08a825c3a3f6..6ad61b08a31a 100644 --- a/drivers/media/platform/xilinx/xilinx-vip.c +++ b/drivers/media/platform/xilinx/xilinx-vip.c @@ -25,21 +25,21 @@ static const struct xvip_video_format xvip_video_formats[] = { { XVIP_VF_YUV_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16, - 2, V4L2_PIX_FMT_YUYV, "4:2:2, packed, YUYV" }, + 2, V4L2_PIX_FMT_YUYV }, { XVIP_VF_YUV_444, 8, NULL, MEDIA_BUS_FMT_VUY8_1X24, - 3, V4L2_PIX_FMT_YUV444, "4:4:4, packed, YUYV" }, + 3, V4L2_PIX_FMT_YUV444 }, { XVIP_VF_RBG, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24, - 3, 0, NULL }, + 3, 0 }, { XVIP_VF_MONO_SENSOR, 8, "mono", MEDIA_BUS_FMT_Y8_1X8, - 1, V4L2_PIX_FMT_GREY, "Greyscale 8-bit" }, + 1, V4L2_PIX_FMT_GREY }, { XVIP_VF_MONO_SENSOR, 8, "rggb", MEDIA_BUS_FMT_SRGGB8_1X8, - 1, V4L2_PIX_FMT_SRGGB8, "Bayer 8-bit RGGB" }, + 1, V4L2_PIX_FMT_SRGGB8 }, { XVIP_VF_MONO_SENSOR, 8, "grbg", MEDIA_BUS_FMT_SGRBG8_1X8, - 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit GRBG" }, + 1, V4L2_PIX_FMT_SGRBG8 }, { XVIP_VF_MONO_SENSOR, 8, "gbrg", MEDIA_BUS_FMT_SGBRG8_1X8, - 1, V4L2_PIX_FMT_SGBRG8, "Bayer 8-bit GBRG" }, + 1, V4L2_PIX_FMT_SGBRG8 }, { XVIP_VF_MONO_SENSOR, 8, "bggr", MEDIA_BUS_FMT_SBGGR8_1X8, - 1, V4L2_PIX_FMT_SBGGR8, "Bayer 8-bit BGGR" }, + 1, V4L2_PIX_FMT_SBGGR8 }, }; /** diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h index ba939dd52818..f71e2b650453 100644 --- a/drivers/media/platform/xilinx/xilinx-vip.h +++ b/drivers/media/platform/xilinx/xilinx-vip.h @@ -12,6 +12,7 @@ #ifndef __XILINX_VIP_H__ #define __XILINX_VIP_H__ +#include <linux/bitops.h> #include <linux/io.h> #include <media/v4l2-subdev.h> @@ -35,23 +36,23 @@ struct clk; /* Xilinx Video IP Control Registers */ #define XVIP_CTRL_CONTROL 0x0000 -#define XVIP_CTRL_CONTROL_SW_ENABLE (1 << 0) -#define XVIP_CTRL_CONTROL_REG_UPDATE (1 << 1) -#define XVIP_CTRL_CONTROL_BYPASS (1 << 4) -#define XVIP_CTRL_CONTROL_TEST_PATTERN (1 << 5) -#define XVIP_CTRL_CONTROL_FRAME_SYNC_RESET (1 << 30) -#define XVIP_CTRL_CONTROL_SW_RESET (1 << 31) +#define XVIP_CTRL_CONTROL_SW_ENABLE BIT(0) +#define XVIP_CTRL_CONTROL_REG_UPDATE BIT(1) +#define XVIP_CTRL_CONTROL_BYPASS BIT(4) +#define XVIP_CTRL_CONTROL_TEST_PATTERN BIT(5) +#define XVIP_CTRL_CONTROL_FRAME_SYNC_RESET BIT(30) +#define XVIP_CTRL_CONTROL_SW_RESET BIT(31) #define XVIP_CTRL_STATUS 0x0004 -#define XVIP_CTRL_STATUS_PROC_STARTED (1 << 0) -#define XVIP_CTRL_STATUS_EOF (1 << 1) +#define XVIP_CTRL_STATUS_PROC_STARTED BIT(0) +#define XVIP_CTRL_STATUS_EOF BIT(1) #define XVIP_CTRL_ERROR 0x0008 -#define XVIP_CTRL_ERROR_SLAVE_EOL_EARLY (1 << 0) -#define XVIP_CTRL_ERROR_SLAVE_EOL_LATE (1 << 1) -#define XVIP_CTRL_ERROR_SLAVE_SOF_EARLY (1 << 2) -#define XVIP_CTRL_ERROR_SLAVE_SOF_LATE (1 << 3) +#define XVIP_CTRL_ERROR_SLAVE_EOL_EARLY BIT(0) +#define XVIP_CTRL_ERROR_SLAVE_EOL_LATE BIT(1) +#define XVIP_CTRL_ERROR_SLAVE_SOF_EARLY BIT(2) +#define XVIP_CTRL_ERROR_SLAVE_SOF_LATE BIT(3) #define XVIP_CTRL_IRQ_ENABLE 0x000c -#define XVIP_CTRL_IRQ_ENABLE_PROC_STARTED (1 << 0) -#define XVIP_CTRL_IRQ_EOF (1 << 1) +#define XVIP_CTRL_IRQ_ENABLE_PROC_STARTED BIT(0) +#define XVIP_CTRL_IRQ_EOF BIT(1) #define XVIP_CTRL_VERSION 0x0010 #define XVIP_CTRL_VERSION_MAJOR_MASK (0xff << 24) #define XVIP_CTRL_VERSION_MAJOR_SHIFT 24 @@ -108,7 +109,6 @@ struct xvip_device { * @code: media bus format code * @bpp: bytes per pixel (when stored in memory) * @fourcc: V4L2 pixel format FCC identifier - * @description: format description, suitable for userspace */ struct xvip_video_format { unsigned int vf_code; @@ -117,7 +117,6 @@ struct xvip_video_format { unsigned int code; unsigned int bpp; u32 fourcc; - const char *description; }; const struct xvip_video_format *xvip_get_format_by_code(unsigned int code); diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index edce0402155d..cc2856efea59 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -385,9 +385,9 @@ static int xvip_graph_parse_one(struct xvip_composite_device *xdev, asd = v4l2_async_notifier_add_fwnode_subdev( &xdev->notifier, remote, sizeof(struct xvip_graph_entity)); + fwnode_handle_put(remote); if (IS_ERR(asd)) { ret = PTR_ERR(asd); - fwnode_handle_put(remote); goto err_notifier_cleanup; } } diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 06400112aebb..a532f63aa9d9 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -125,7 +125,7 @@ struct gemtek { #define BU2614_FMUN_SHIFT (BU2614_VOID2_BITS + BU2614_VOID2_SHIFT) #define BU2614_TEST_SHIFT (BU2614_FMUN_BITS + BU2614_FMUN_SHIFT) -#define MKMASK(field) (((1<<BU2614_##field##_BITS) - 1) << \ +#define MKMASK(field) (((1UL<<BU2614_##field##_BITS) - 1) << \ BU2614_##field##_SHIFT) #define BU2614_PORT_MASK MKMASK(PORT) #define BU2614_FREQ_MASK MKMASK(FREQ) diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index 2fc009509c7c..dfb8b62f0e2b 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -16,7 +16,6 @@ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org> */ -#include <stdarg.h> #include <linux/module.h> #include <linux/init.h> #include <linux/ioport.h> diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 7d53422b3b56..7541698a0be1 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -330,8 +330,7 @@ end: /* * si470x_i2c_probe - probe for the device */ -static int si470x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int si470x_i2c_probe(struct i2c_client *client) { struct si470x_device *radio; int retval = 0; @@ -544,7 +543,7 @@ static struct i2c_driver si470x_i2c_driver = { .pm = &si470x_i2c_pm, #endif }, - .probe = si470x_i2c_probe, + .probe_new = si470x_i2c_probe, .remove = si470x_i2c_remove, .id_table = si470x_i2c_id, }; diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 49073747b1e7..fedff68d8c49 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -734,7 +734,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, /* start radio */ retval = si470x_start_usb(radio); if (retval < 0) - goto err_all; + goto err_buf; /* set initial frequency */ si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ @@ -749,6 +749,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, return 0; err_all: + usb_kill_urb(radio->int_in_urb); +err_buf: kfree(radio->buffer); err_ctrl: v4l2_ctrl_handler_free(&radio->hdl); @@ -822,6 +824,7 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf) mutex_lock(&radio->lock); v4l2_device_disconnect(&radio->v4l2_dev); video_unregister_device(&radio->videodev); + usb_kill_urb(radio->int_in_urb); usb_set_intfdata(intf, NULL); mutex_unlock(&radio->lock); v4l2_device_put(&radio->v4l2_dev); diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c index 7d97de2fa56c..7f3aee495ed3 100644 --- a/drivers/media/radio/si4713/si4713.c +++ b/drivers/media/radio/si4713/si4713.c @@ -1427,8 +1427,7 @@ static const struct v4l2_ctrl_config si4713_alt_freqs_ctrl = { * I2C driver interface */ /* si4713_probe - probe for the device */ -static int si4713_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int si4713_probe(struct i2c_client *client) { struct si4713_device *sdev; struct v4l2_ctrl_handler *hdl; @@ -1660,7 +1659,7 @@ static struct i2c_driver si4713_i2c_driver = { .name = "si4713", .of_match_table = of_match_ptr(si4713_of_match), }, - .probe = si4713_probe, + .probe_new = si4713_probe, .remove = si4713_remove, .id_table = si4713_id, }; diff --git a/drivers/media/radio/wl128x/fmdrv_common.h b/drivers/media/radio/wl128x/fmdrv_common.h index 7d7a2b17aa76..6a287eadae75 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.h +++ b/drivers/media/radio/wl128x/fmdrv_common.h @@ -159,18 +159,18 @@ struct fm_event_msg_hdr { #define FM_DISABLE 0 /* FLAG_GET register bits */ -#define FM_FR_EVENT (1 << 0) -#define FM_BL_EVENT (1 << 1) -#define FM_RDS_EVENT (1 << 2) -#define FM_BBLK_EVENT (1 << 3) -#define FM_LSYNC_EVENT (1 << 4) -#define FM_LEV_EVENT (1 << 5) -#define FM_IFFR_EVENT (1 << 6) -#define FM_PI_EVENT (1 << 7) -#define FM_PD_EVENT (1 << 8) -#define FM_STIC_EVENT (1 << 9) -#define FM_MAL_EVENT (1 << 10) -#define FM_POW_ENB_EVENT (1 << 11) +#define FM_FR_EVENT BIT(0) +#define FM_BL_EVENT BIT(1) +#define FM_RDS_EVENT BIT(2) +#define FM_BBLK_EVENT BIT(3) +#define FM_LSYNC_EVENT BIT(4) +#define FM_LEV_EVENT BIT(5) +#define FM_IFFR_EVENT BIT(6) +#define FM_PI_EVENT BIT(7) +#define FM_PD_EVENT BIT(8) +#define FM_STIC_EVENT BIT(9) +#define FM_MAL_EVENT BIT(10) +#define FM_POW_ENB_EVENT BIT(11) /* * Firmware files of FM. ASIC ID and ASIC version will be appened to this, @@ -268,38 +268,38 @@ struct fm_event_msg_hdr { * Represents an RDS group type & version. * There are 15 groups, each group has 2 versions: A and B. */ -#define FM_RDS_GROUP_TYPE_MASK_0A ((unsigned long)1<<0) -#define FM_RDS_GROUP_TYPE_MASK_0B ((unsigned long)1<<1) -#define FM_RDS_GROUP_TYPE_MASK_1A ((unsigned long)1<<2) -#define FM_RDS_GROUP_TYPE_MASK_1B ((unsigned long)1<<3) -#define FM_RDS_GROUP_TYPE_MASK_2A ((unsigned long)1<<4) -#define FM_RDS_GROUP_TYPE_MASK_2B ((unsigned long)1<<5) -#define FM_RDS_GROUP_TYPE_MASK_3A ((unsigned long)1<<6) -#define FM_RDS_GROUP_TYPE_MASK_3B ((unsigned long)1<<7) -#define FM_RDS_GROUP_TYPE_MASK_4A ((unsigned long)1<<8) -#define FM_RDS_GROUP_TYPE_MASK_4B ((unsigned long)1<<9) -#define FM_RDS_GROUP_TYPE_MASK_5A ((unsigned long)1<<10) -#define FM_RDS_GROUP_TYPE_MASK_5B ((unsigned long)1<<11) -#define FM_RDS_GROUP_TYPE_MASK_6A ((unsigned long)1<<12) -#define FM_RDS_GROUP_TYPE_MASK_6B ((unsigned long)1<<13) -#define FM_RDS_GROUP_TYPE_MASK_7A ((unsigned long)1<<14) -#define FM_RDS_GROUP_TYPE_MASK_7B ((unsigned long)1<<15) -#define FM_RDS_GROUP_TYPE_MASK_8A ((unsigned long)1<<16) -#define FM_RDS_GROUP_TYPE_MASK_8B ((unsigned long)1<<17) -#define FM_RDS_GROUP_TYPE_MASK_9A ((unsigned long)1<<18) -#define FM_RDS_GROUP_TYPE_MASK_9B ((unsigned long)1<<19) -#define FM_RDS_GROUP_TYPE_MASK_10A ((unsigned long)1<<20) -#define FM_RDS_GROUP_TYPE_MASK_10B ((unsigned long)1<<21) -#define FM_RDS_GROUP_TYPE_MASK_11A ((unsigned long)1<<22) -#define FM_RDS_GROUP_TYPE_MASK_11B ((unsigned long)1<<23) -#define FM_RDS_GROUP_TYPE_MASK_12A ((unsigned long)1<<24) -#define FM_RDS_GROUP_TYPE_MASK_12B ((unsigned long)1<<25) -#define FM_RDS_GROUP_TYPE_MASK_13A ((unsigned long)1<<26) -#define FM_RDS_GROUP_TYPE_MASK_13B ((unsigned long)1<<27) -#define FM_RDS_GROUP_TYPE_MASK_14A ((unsigned long)1<<28) -#define FM_RDS_GROUP_TYPE_MASK_14B ((unsigned long)1<<29) -#define FM_RDS_GROUP_TYPE_MASK_15A ((unsigned long)1<<30) -#define FM_RDS_GROUP_TYPE_MASK_15B ((unsigned long)1<<31) +#define FM_RDS_GROUP_TYPE_MASK_0A BIT(0) +#define FM_RDS_GROUP_TYPE_MASK_0B BIT(1) +#define FM_RDS_GROUP_TYPE_MASK_1A BIT(2) +#define FM_RDS_GROUP_TYPE_MASK_1B BIT(3) +#define FM_RDS_GROUP_TYPE_MASK_2A BIT(4) +#define FM_RDS_GROUP_TYPE_MASK_2B BIT(5) +#define FM_RDS_GROUP_TYPE_MASK_3A BIT(6) +#define FM_RDS_GROUP_TYPE_MASK_3B BIT(7) +#define FM_RDS_GROUP_TYPE_MASK_4A BIT(8) +#define FM_RDS_GROUP_TYPE_MASK_4B BIT(9) +#define FM_RDS_GROUP_TYPE_MASK_5A BIT(10) +#define FM_RDS_GROUP_TYPE_MASK_5B BIT(11) +#define FM_RDS_GROUP_TYPE_MASK_6A BIT(12) +#define FM_RDS_GROUP_TYPE_MASK_6B BIT(13) +#define FM_RDS_GROUP_TYPE_MASK_7A BIT(14) +#define FM_RDS_GROUP_TYPE_MASK_7B BIT(15) +#define FM_RDS_GROUP_TYPE_MASK_8A BIT(16) +#define FM_RDS_GROUP_TYPE_MASK_8B BIT(17) +#define FM_RDS_GROUP_TYPE_MASK_9A BIT(18) +#define FM_RDS_GROUP_TYPE_MASK_9B BIT(19) +#define FM_RDS_GROUP_TYPE_MASK_10A BIT(20) +#define FM_RDS_GROUP_TYPE_MASK_10B BIT(21) +#define FM_RDS_GROUP_TYPE_MASK_11A BIT(22) +#define FM_RDS_GROUP_TYPE_MASK_11B BIT(23) +#define FM_RDS_GROUP_TYPE_MASK_12A BIT(24) +#define FM_RDS_GROUP_TYPE_MASK_12B BIT(25) +#define FM_RDS_GROUP_TYPE_MASK_13A BIT(26) +#define FM_RDS_GROUP_TYPE_MASK_13B BIT(27) +#define FM_RDS_GROUP_TYPE_MASK_14A BIT(28) +#define FM_RDS_GROUP_TYPE_MASK_14B BIT(29) +#define FM_RDS_GROUP_TYPE_MASK_15A BIT(30) +#define FM_RDS_GROUP_TYPE_MASK_15B BIT(31) /* RX Alternate Frequency info */ #define FM_RDS_MIN_AF 1 diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index ea05e125016a..872d6441e512 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -413,6 +413,10 @@ static int iguanair_probe(struct usb_interface *intf, int ret, pipein, pipeout; struct usb_host_interface *idesc; + idesc = intf->altsetting; + if (idesc->desc.bNumEndpoints < 2) + return -ENODEV; + ir = kzalloc(sizeof(*ir), GFP_KERNEL); rc = rc_allocate_device(RC_DRIVER_IR_RAW); if (!ir || !rc) { @@ -427,18 +431,13 @@ static int iguanair_probe(struct usb_interface *intf, ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); ir->urb_out = usb_alloc_urb(0, GFP_KERNEL); - if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out) { + if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out || + !usb_endpoint_is_int_in(&idesc->endpoint[0].desc) || + !usb_endpoint_is_int_out(&idesc->endpoint[1].desc)) { ret = -ENOMEM; goto out; } - idesc = intf->altsetting; - - if (idesc->desc.bNumEndpoints < 2) { - ret = -ENODEV; - goto out; - } - ir->rc = rc; ir->dev = &intf->dev; ir->udev = udev; diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c index 7e457f26a595..094aa6a06315 100644 --- a/drivers/media/rc/img-ir/img-ir-core.c +++ b/drivers/media/rc/img-ir/img-ir-core.c @@ -81,10 +81,8 @@ static int img_ir_probe(struct platform_device *pdev) /* Get resources from platform device */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "cannot find IRQ resource\n"); + if (irq < 0) return irq; - } /* Private driver data */ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 7bee72108b0e..37a850421fbb 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1826,12 +1826,17 @@ static void imon_get_ffdc_type(struct imon_context *ictx) break; /* iMON VFD, MCE IR */ case 0x46: - case 0x7e: case 0x9e: dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; allowed_protos = RC_PROTO_BIT_RC6_MCE; break; + /* iMON VFD, iMON or MCE IR */ + case 0x7e: + dev_info(ictx->dev, "0xffdc iMON VFD, iMON or MCE IR"); + detected_display_type = IMON_DISPLAY_TYPE_VFD; + allowed_protos |= RC_PROTO_BIT_RC6_MCE; + break; /* iMON LCD, MCE IR */ case 0x9f: dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); diff --git a/drivers/media/rc/imon_raw.c b/drivers/media/rc/imon_raw.c index 25e56c5b13c0..d4aedcf76418 100644 --- a/drivers/media/rc/imon_raw.c +++ b/drivers/media/rc/imon_raw.c @@ -14,7 +14,7 @@ struct imon { struct device *dev; struct urb *ir_urb; struct rc_dev *rcdev; - u8 ir_buf[8] __aligned(__alignof__(u64)); + __be64 ir_buf; char phys[64]; }; @@ -29,14 +29,35 @@ struct imon { static void imon_ir_data(struct imon *imon) { struct ir_raw_event rawir = {}; - u64 d = be64_to_cpup((__be64 *)imon->ir_buf) >> 24; + u64 data = be64_to_cpu(imon->ir_buf); + u8 packet_no = data & 0xff; int offset = 40; int bit; - dev_dbg(imon->dev, "data: %*ph", 8, imon->ir_buf); + if (packet_no == 0xff) + return; + + dev_dbg(imon->dev, "data: %*ph", 8, &imon->ir_buf); + + /* + * Only the first 5 bytes contain IR data. Right shift so we move + * the IR bits to the lower 40 bits. + */ + data >>= 24; do { - bit = fls64(d & (BIT_ULL(offset) - 1)); + /* + * Find highest set bit which is less or equal to offset + * + * offset is the bit above (base 0) where we start looking. + * + * data & (BIT_ULL(offset) - 1) masks off any unwanted bits, + * so we have just bits less than offset. + * + * fls will tell us the highest bit set plus 1 (or 0 if no + * bits are set). + */ + bit = fls64(data & (BIT_ULL(offset) - 1)); if (bit < offset) { dev_dbg(imon->dev, "pulse: %d bits", offset - bit); rawir.pulse = true; @@ -49,7 +70,12 @@ static void imon_ir_data(struct imon *imon) offset = bit; } - bit = fls64(~d & (BIT_ULL(offset) - 1)); + /* + * Find highest clear bit which is less than offset. + * + * Just invert the data and use same trick as above. + */ + bit = fls64(~data & (BIT_ULL(offset) - 1)); dev_dbg(imon->dev, "space: %d bits", offset - bit); rawir.pulse = false; @@ -59,7 +85,7 @@ static void imon_ir_data(struct imon *imon) offset = bit; } while (offset > 0); - if (imon->ir_buf[7] == 0x0a) { + if (packet_no == 0x0a && !imon->rcdev->idle) { ir_raw_event_set_idle(imon->rcdev, true); ir_raw_event_handle(imon->rcdev); } @@ -72,8 +98,7 @@ static void imon_ir_rx(struct urb *urb) switch (urb->status) { case 0: - if (imon->ir_buf[7] != 0xff) - imon_ir_data(imon); + imon_ir_data(imon); break; case -ECONNRESET: case -ENOENT: @@ -129,7 +154,7 @@ static int imon_probe(struct usb_interface *intf, imon->dev = &intf->dev; usb_fill_int_urb(imon->ir_urb, udev, usb_rcvintpipe(udev, ir_ep->bEndpointAddress), - imon->ir_buf, sizeof(imon->ir_buf), + &imon->ir_buf, sizeof(imon->ir_buf), imon_ir_rx, imon, ir_ep->bInterval); rcdev = devm_rc_allocate_device(&intf->dev, RC_DRIVER_IR_RAW); diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index 85561f6555a2..32ccefeff57d 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -232,10 +232,8 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) return PTR_ERR(priv->base); priv->irq = platform_get_irq(pdev, 0); - if (priv->irq < 0) { - dev_err(dev, "irq can not get\n"); + if (priv->irq < 0) return priv->irq; - } rdev = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rdev) diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 5b1399af6b3a..a56fc634d2d6 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-it913x-v1.o \ rc-it913x-v2.o \ rc-kaiomy.o \ + rc-khadas.o \ rc-kworld-315u.o \ rc-kworld-pc150u.o \ rc-kworld-plus-tv-analog.o \ @@ -75,6 +76,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-nec-terratec-cinergy-xs.o \ rc-norwood.o \ rc-npgtech.o \ + rc-odroid.o \ rc-pctv-sedna.o \ rc-pinnacle-color.o \ rc-pinnacle-grey.o \ @@ -94,6 +96,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-snapstream-firefly.o \ rc-streamzap.o \ rc-tango.o \ + rc-tanix-tx3mini.o \ + rc-tanix-tx5max.o \ rc-tbs-nec.o \ rc-technisat-ts35.o \ rc-technisat-usb2.o \ @@ -113,8 +117,11 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-videomate-m1f.o \ rc-videomate-s350.o \ rc-videomate-tv-pvr.o \ + rc-wetek-hub.o \ + rc-wetek-play2.o \ rc-winfast.o \ rc-winfast-usbii-deluxe.o \ rc-su3000.o \ rc-xbox-dvd.o \ + rc-x96max.o \ rc-zx-irdec.o diff --git a/drivers/media/rc/keymaps/rc-imon-rsc.c b/drivers/media/rc/keymaps/rc-imon-rsc.c index 6f7ee4859682..38787dd0e4a0 100644 --- a/drivers/media/rc/keymaps/rc-imon-rsc.c +++ b/drivers/media/rc/keymaps/rc-imon-rsc.c @@ -7,7 +7,8 @@ // // Note that this remote has a stick which its own IR protocol, -// with 16 directions. This is not supported yet. +// with 16 directions. This is supported by the imon_rsc BPF decoder +// in v4l-utils. // static struct rc_map_table imon_rsc[] = { { 0x801010, KEY_EXIT }, @@ -25,7 +26,7 @@ static struct rc_map_table imon_rsc[] = { { 0x80105c, KEY_NUMERIC_9 }, { 0x801081, KEY_SCREEN }, /* Desktop */ { 0x80105d, KEY_NUMERIC_0 }, - { 0x801082, KEY_MAX }, + { 0x801082, KEY_ZOOM }, /* Maximise */ { 0x801048, KEY_ESC }, { 0x80104b, KEY_MEDIA }, /* Windows key */ { 0x801083, KEY_MENU }, @@ -52,7 +53,7 @@ static struct rc_map_table imon_rsc[] = { { 0x80104e, KEY_STOP }, { 0x801052, KEY_REWIND }, { 0x801053, KEY_FASTFORWARD }, - { 0x801089, KEY_ZOOM } /* full screen */ + { 0x801089, KEY_FULL_SCREEN } /* full screen */ }; static struct rc_map_list imon_rsc_map = { diff --git a/drivers/media/rc/keymaps/rc-khadas.c b/drivers/media/rc/keymaps/rc-khadas.c new file mode 100644 index 000000000000..ce4938444d90 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-khadas.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2019 Christian Hewitt <christianshewitt@gmail.com> + +/* + * Keytable for the Khadas VIM/EDGE SBC remote control + */ + +#include <media/rc-map.h> +#include <linux/module.h> + +static struct rc_map_table khadas[] = { + { 0x14, KEY_POWER }, + + { 0x03, KEY_UP }, + { 0x02, KEY_DOWN }, + { 0x0e, KEY_LEFT }, + { 0x1a, KEY_RIGHT }, + { 0x07, KEY_OK }, + + { 0x01, KEY_BACK }, + { 0x5b, KEY_MUTE }, // mouse + { 0x13, KEY_MENU }, + + { 0x58, KEY_VOLUMEDOWN }, + { 0x0b, KEY_VOLUMEUP }, + + { 0x48, KEY_HOME }, +}; + +static struct rc_map_list khadas_map = { + .map = { + .scan = khadas, + .size = ARRAY_SIZE(khadas), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_KHADAS, + } +}; + +static int __init init_rc_map_khadas(void) +{ + return rc_map_register(&khadas_map); +} + +static void __exit exit_rc_map_khadas(void) +{ + rc_map_unregister(&khadas_map); +} + +module_init(init_rc_map_khadas) +module_exit(exit_rc_map_khadas) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com>"); diff --git a/drivers/media/rc/keymaps/rc-odroid.c b/drivers/media/rc/keymaps/rc-odroid.c new file mode 100644 index 000000000000..c6fbb64b5c41 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-odroid.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2019 Christian Hewitt <christianshewitt@gmail.com> + +#include <media/rc-map.h> +#include <linux/module.h> + +// +// Keytable for the HardKernel ODROID remote control +// + +static struct rc_map_table odroid[] = { + { 0xb2dc, KEY_POWER }, + + { 0xb288, KEY_MUTE }, + { 0xb282, KEY_HOME }, + + { 0xb2ca, KEY_UP }, + { 0xb299, KEY_LEFT }, + { 0xb2ce, KEY_OK }, + { 0xb2c1, KEY_RIGHT }, + { 0xb2d2, KEY_DOWN }, + + { 0xb2c5, KEY_MENU }, + { 0xb29a, KEY_BACK }, + + { 0xb281, KEY_VOLUMEDOWN }, + { 0xb280, KEY_VOLUMEUP }, +}; + +static struct rc_map_list odroid_map = { + .map = { + .scan = odroid, + .size = ARRAY_SIZE(odroid), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_ODROID, + } +}; + +static int __init init_rc_map_odroid(void) +{ + return rc_map_register(&odroid_map); +} + +static void __exit exit_rc_map_odroid(void) +{ + rc_map_unregister(&odroid_map); +} + +module_init(init_rc_map_odroid) +module_exit(exit_rc_map_odroid) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); diff --git a/drivers/media/rc/keymaps/rc-tanix-tx3mini.c b/drivers/media/rc/keymaps/rc-tanix-tx3mini.c new file mode 100644 index 000000000000..d486cd69afb2 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-tanix-tx3mini.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2018 Christian Hewitt + +#include <media/rc-map.h> +#include <linux/module.h> + +/* + * Keymap for the Tanix TX3 mini STB remote control + */ + +static struct rc_map_table tanix_tx3mini[] = { + { 0x8051, KEY_POWER }, + { 0x804d, KEY_MUTE }, + + { 0x8009, KEY_RED }, + { 0x8011, KEY_GREEN }, + { 0x8054, KEY_YELLOW }, + { 0x804f, KEY_BLUE }, + + { 0x8056, KEY_VOLUMEDOWN }, + { 0x80bd, KEY_PREVIOUS }, + { 0x80bb, KEY_NEXT }, + { 0x804e, KEY_VOLUMEUP }, + + { 0x8053, KEY_HOME }, + { 0x801b, KEY_BACK }, + + { 0x8026, KEY_UP }, + { 0x8028, KEY_DOWN }, + { 0x8025, KEY_LEFT }, + { 0x8027, KEY_RIGHT }, + { 0x800d, KEY_OK }, + + { 0x8049, KEY_MENU }, + { 0x8052, KEY_EPG }, // mouse + + { 0x8031, KEY_1 }, + { 0x8032, KEY_2 }, + { 0x8033, KEY_3 }, + + { 0x8034, KEY_4 }, + { 0x8035, KEY_5 }, + { 0x8036, KEY_6 }, + + { 0x8037, KEY_7 }, + { 0x8038, KEY_8 }, + { 0x8039, KEY_9 }, + + { 0x8058, KEY_SUBTITLE }, // 1/a + { 0x8030, KEY_0 }, + { 0x8044, KEY_DELETE }, +}; + +static struct rc_map_list tanix_tx3mini_map = { + .map = { + .scan = tanix_tx3mini, + .size = ARRAY_SIZE(tanix_tx3mini), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_TANIX_TX3MINI, + } +}; + +static int __init init_rc_map_tanix_tx3mini(void) +{ + return rc_map_register(&tanix_tx3mini_map); +} + +static void __exit exit_rc_map_tanix_tx3mini(void) +{ + rc_map_unregister(&tanix_tx3mini_map); +} + +module_init(init_rc_map_tanix_tx3mini) +module_exit(exit_rc_map_tanix_tx3mini) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com>"); diff --git a/drivers/media/rc/keymaps/rc-tanix-tx5max.c b/drivers/media/rc/keymaps/rc-tanix-tx5max.c new file mode 100644 index 000000000000..59aaabed80dd --- /dev/null +++ b/drivers/media/rc/keymaps/rc-tanix-tx5max.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2018 Christian Hewitt + +#include <media/rc-map.h> +#include <linux/module.h> + +/* + * Keymap for the Tanix TX5 max STB remote control + */ + +static struct rc_map_table tanix_tx5max[] = { + { 0x40404d, KEY_POWER }, + { 0x404043, KEY_MUTE }, + + { 0x404017, KEY_VOLUMEDOWN }, + { 0x404018, KEY_VOLUMEUP }, + + { 0x40400b, KEY_UP }, + { 0x404010, KEY_LEFT }, + { 0x404011, KEY_RIGHT }, + { 0x40400e, KEY_DOWN }, + { 0x40400d, KEY_OK }, + + { 0x40401a, KEY_HOME }, + { 0x404045, KEY_MENU }, + { 0x404042, KEY_BACK }, + + { 0x404001, KEY_1 }, + { 0x404002, KEY_2 }, + { 0x404003, KEY_3 }, + + { 0x404004, KEY_4 }, + { 0x404005, KEY_5 }, + { 0x404006, KEY_6 }, + + { 0x404007, KEY_7 }, + { 0x404008, KEY_8 }, + { 0x404009, KEY_9 }, + + { 0x404047, KEY_SUBTITLE }, // mouse + { 0x404000, KEY_0 }, + { 0x40400c, KEY_DELETE }, +}; + +static struct rc_map_list tanix_tx5max_map = { + .map = { + .scan = tanix_tx5max, + .size = ARRAY_SIZE(tanix_tx5max), + .rc_proto = RC_PROTO_NECX, + .name = RC_MAP_TANIX_TX5MAX, + } +}; + +static int __init init_rc_map_tanix_tx5max(void) +{ + return rc_map_register(&tanix_tx5max_map); +} + +static void __exit exit_rc_map_tanix_tx5max(void) +{ + rc_map_unregister(&tanix_tx5max_map); +} + +module_init(init_rc_map_tanix_tx5max) +module_exit(exit_rc_map_tanix_tx5max) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com>"); diff --git a/drivers/media/rc/keymaps/rc-wetek-hub.c b/drivers/media/rc/keymaps/rc-wetek-hub.c new file mode 100644 index 000000000000..b5a21aff45f5 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-wetek-hub.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2018 Christian Hewitt + +#include <media/rc-map.h> +#include <linux/module.h> + +/* + * This keymap is used with the WeTek Hub STB. + */ + +static struct rc_map_table wetek_hub[] = { + { 0x77f1, KEY_POWER }, + + { 0x77f2, KEY_HOME }, + { 0x77f3, KEY_MUTE }, // mouse + + { 0x77f4, KEY_UP }, + { 0x77f5, KEY_DOWN }, + { 0x77f6, KEY_LEFT }, + { 0x77f7, KEY_RIGHT }, + { 0x77f8, KEY_OK }, + + { 0x77f9, KEY_BACK }, + { 0x77fa, KEY_MENU }, + + { 0x77fb, KEY_VOLUMEUP }, + { 0x77fc, KEY_VOLUMEDOWN }, +}; + +static struct rc_map_list wetek_hub_map = { + .map = { + .scan = wetek_hub, + .size = ARRAY_SIZE(wetek_hub), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_WETEK_HUB, + } +}; + +static int __init init_rc_map_wetek_hub(void) +{ + return rc_map_register(&wetek_hub_map); +} + +static void __exit exit_rc_map_wetek_hub(void) +{ + rc_map_unregister(&wetek_hub_map); +} + +module_init(init_rc_map_wetek_hub) +module_exit(exit_rc_map_wetek_hub) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com>"); diff --git a/drivers/media/rc/keymaps/rc-wetek-play2.c b/drivers/media/rc/keymaps/rc-wetek-play2.c new file mode 100644 index 000000000000..bbbb11fa3c11 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-wetek-play2.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2019 Christian Hewitt <christianshewitt@gmail.com> + +#include <media/rc-map.h> +#include <linux/module.h> + +// +// Keytable for the WeTek Play 2 STB remote control +// + +static struct rc_map_table wetek_play2[] = { + { 0x5e5f02, KEY_POWER }, + { 0x5e5f46, KEY_SLEEP }, // tv + { 0x5e5f10, KEY_MUTE }, + + { 0x5e5f22, KEY_1 }, + { 0x5e5f23, KEY_2 }, + { 0x5e5f24, KEY_3 }, + + { 0x5e5f25, KEY_4 }, + { 0x5e5f26, KEY_5 }, + { 0x5e5f27, KEY_6 }, + + { 0x5e5f28, KEY_7 }, + { 0x5e5f29, KEY_8 }, + { 0x5e5f30, KEY_9 }, + + { 0x5e5f71, KEY_BACK }, + { 0x5e5f21, KEY_0 }, + { 0x5e5f72, KEY_CAPSLOCK }, + + // outer ring clockwide from top + { 0x5e5f03, KEY_HOME }, + { 0x5e5f61, KEY_BACK }, + { 0x5e5f77, KEY_CONFIG }, // mouse + { 0x5e5f83, KEY_EPG }, + { 0x5e5f84, KEY_SCREEN }, // square + { 0x5e5f48, KEY_MENU }, + + // inner ring + { 0x5e5f50, KEY_UP }, + { 0x5e5f4b, KEY_DOWN }, + { 0x5e5f4c, KEY_LEFT }, + { 0x5e5f4d, KEY_RIGHT }, + { 0x5e5f47, KEY_OK }, + + { 0x5e5f44, KEY_VOLUMEUP }, + { 0x5e5f43, KEY_VOLUMEDOWN }, + { 0x5e5f4f, KEY_FAVORITES }, + { 0x5e5f82, KEY_SUBTITLE }, // txt + { 0x5e5f41, KEY_PAGEUP }, + { 0x5e5f42, KEY_PAGEDOWN }, + + { 0x5e5f73, KEY_RED }, + { 0x5e5f74, KEY_GREEN }, + { 0x5e5f75, KEY_YELLOW }, + { 0x5e5f76, KEY_BLUE }, + + { 0x5e5f67, KEY_PREVIOUSSONG }, + { 0x5e5f79, KEY_REWIND }, + { 0x5e5f80, KEY_FASTFORWARD }, + { 0x5e5f81, KEY_NEXTSONG }, + + { 0x5e5f04, KEY_RECORD }, + { 0x5e5f2c, KEY_PLAYPAUSE }, + { 0x5e5f2b, KEY_STOP }, +}; + +static struct rc_map_list wetek_play2_map = { + .map = { + .scan = wetek_play2, + .size = ARRAY_SIZE(wetek_play2), + .rc_proto = RC_PROTO_NECX, + .name = RC_MAP_WETEK_PLAY2, + } +}; + +static int __init init_rc_map_wetek_play2(void) +{ + return rc_map_register(&wetek_play2_map); +} + +static void __exit exit_rc_map_wetek_play2(void) +{ + rc_map_unregister(&wetek_play2_map); +} + +module_init(init_rc_map_wetek_play2) +module_exit(exit_rc_map_wetek_play2) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); diff --git a/drivers/media/rc/keymaps/rc-x96max.c b/drivers/media/rc/keymaps/rc-x96max.c new file mode 100644 index 000000000000..0998ec3320e4 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-x96max.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2019 Christian Hewitt <christianshewitt@gmail.com> + +#include <media/rc-map.h> +#include <linux/module.h> + +// +// Keytable for the X96-max STB remote control +// + +static struct rc_map_table x96max[] = { + { 0x140, KEY_POWER }, + + // ** TV CONTROL ** + // SET + // AV/TV + // POWER + // VOLUME UP + // VOLUME DOWN + + { 0x118, KEY_VOLUMEUP }, + { 0x110, KEY_VOLUMEDOWN }, + + { 0x143, KEY_MUTE }, // config + + { 0x100, KEY_EPG }, // mouse + { 0x119, KEY_BACK }, + + { 0x116, KEY_UP }, + { 0x151, KEY_LEFT }, + { 0x150, KEY_RIGHT }, + { 0x11a, KEY_DOWN }, + { 0x113, KEY_OK }, + + { 0x111, KEY_HOME }, + { 0x14c, KEY_CONTEXT_MENU }, + + { 0x159, KEY_PREVIOUS }, + { 0x15a, KEY_PLAYPAUSE }, + { 0x158, KEY_NEXT }, + + { 0x147, KEY_MENU }, // @ key + { 0x101, KEY_NUMERIC_0 }, + { 0x142, KEY_BACKSPACE }, + + { 0x14e, KEY_NUMERIC_1 }, + { 0x10d, KEY_NUMERIC_2 }, + { 0x10c, KEY_NUMERIC_3 }, + + { 0x14a, KEY_NUMERIC_4 }, + { 0x109, KEY_NUMERIC_5 }, + { 0x108, KEY_NUMERIC_6 }, + + { 0x146, KEY_NUMERIC_7 }, + { 0x105, KEY_NUMERIC_8 }, + { 0x104, KEY_NUMERIC_9 }, +}; + +static struct rc_map_list x96max_map = { + .map = { + .scan = x96max, + .size = ARRAY_SIZE(x96max), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_X96MAX, + } +}; + +static int __init init_rc_map_x96max(void) +{ + return rc_map_register(&x96max_map); +} + +static void __exit exit_rc_map_x96max(void) +{ + rc_map_unregister(&x96max_map); +} + +module_init(init_rc_map_x96max) +module_exit(exit_rc_map_x96max) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 4d5351ebb940..3fc9829a9233 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -31,21 +31,22 @@ #include <linux/pm_wakeup.h> #include <media/rc-core.h> -#define DRIVER_VERSION "1.94" +#define DRIVER_VERSION "1.95" #define DRIVER_AUTHOR "Jarod Wilson <jarod@redhat.com>" #define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \ "device driver" #define DRIVER_NAME "mceusb" +#define USB_TX_TIMEOUT 1000 /* in milliseconds */ #define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */ #define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */ /* MCE constants */ -#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */ +#define MCE_IRBUF_SIZE 128 /* TX IR buffer length */ #define MCE_TIME_UNIT 50 /* Approx 50us resolution */ -#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */ -#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */ -#define MCE_IRDATA_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */ +#define MCE_PACKET_SIZE 31 /* Max length of packet (with header) */ +#define MCE_IRDATA_HEADER (0x80 + MCE_PACKET_SIZE - 1) + /* Actual format is 0x80 + num_bytes */ #define MCE_IRDATA_TRAILER 0x80 /* End of IR data */ #define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */ #define MCE_DEFAULT_TX_MASK 0x03 /* Vals: TX1=0x01, TX2=0x02, ALL=0x03 */ @@ -461,6 +462,7 @@ struct mceusb_dev { /* usb */ struct usb_device *usbdev; + struct usb_interface *usbintf; struct urb *urb_in; unsigned int pipe_in; struct usb_endpoint_descriptor *usb_ep_out; @@ -517,6 +519,7 @@ struct mceusb_dev { unsigned long kevent_flags; # define EVENT_TX_HALT 0 # define EVENT_RX_HALT 1 +# define EVENT_RST_PEND 31 }; /* MCE Device Command Strings, generally a port and command pair */ @@ -607,9 +610,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len, if (len <= skip) return; - dev_dbg(dev, "%cx data: %*ph (length=%d)", - (out ? 't' : 'r'), - min(len, buf_len - offset), buf + offset, len); + dev_dbg(dev, "%cx data[%d]: %*ph (len=%d sz=%d)", + (out ? 't' : 'r'), offset, + min(len, buf_len - offset), buf + offset, len, buf_len); inout = out ? "Request" : "Got"; @@ -731,6 +734,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len, case MCE_RSP_CMD_ILLEGAL: dev_dbg(dev, "Illegal PORT_IR command"); break; + case MCE_RSP_TX_TIMEOUT: + dev_dbg(dev, "IR TX timeout (TX buffer underrun)"); + break; default: dev_dbg(dev, "Unknown command 0x%02x 0x%02x", cmd, subcmd); @@ -745,42 +751,107 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len, dev_dbg(dev, "End of raw IR data"); else if ((cmd != MCE_CMD_PORT_IR) && ((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA)) - dev_dbg(dev, "Raw IR data, %d pulse/space samples", ir->rem); + dev_dbg(dev, "Raw IR data, %d pulse/space samples", + cmd & MCE_PACKET_LENGTH_MASK); #endif } /* * Schedule work that can't be done in interrupt handlers - * (mceusb_dev_recv() and mce_async_callback()) nor tasklets. + * (mceusb_dev_recv() and mce_write_callback()) nor tasklets. * Invokes mceusb_deferred_kevent() for recovering from * error events specified by the kevent bit field. */ static void mceusb_defer_kevent(struct mceusb_dev *ir, int kevent) { set_bit(kevent, &ir->kevent_flags); + + if (test_bit(EVENT_RST_PEND, &ir->kevent_flags)) { + dev_dbg(ir->dev, "kevent %d dropped pending USB Reset Device", + kevent); + return; + } + if (!schedule_work(&ir->kevent)) - dev_err(ir->dev, "kevent %d may have been dropped", kevent); + dev_dbg(ir->dev, "kevent %d already scheduled", kevent); else dev_dbg(ir->dev, "kevent %d scheduled", kevent); } -static void mce_async_callback(struct urb *urb) +static void mce_write_callback(struct urb *urb) { - struct mceusb_dev *ir; - int len; - if (!urb) return; - ir = urb->context; + complete(urb->context); +} + +/* + * Write (TX/send) data to MCE device USB endpoint out. + * Used for IR blaster TX and MCE device commands. + * + * Return: The number of bytes written (> 0) or errno (< 0). + */ +static int mce_write(struct mceusb_dev *ir, u8 *data, int size) +{ + int ret; + struct urb *urb; + struct device *dev = ir->dev; + unsigned char *buf_out; + struct completion tx_done; + unsigned long expire; + unsigned long ret_wait; + + mceusb_dev_printdata(ir, data, size, 0, size, true); + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (unlikely(!urb)) { + dev_err(dev, "Error: mce write couldn't allocate urb"); + return -ENOMEM; + } + + buf_out = kmalloc(size, GFP_KERNEL); + if (!buf_out) { + usb_free_urb(urb); + return -ENOMEM; + } + + init_completion(&tx_done); + + /* outbound data */ + if (usb_endpoint_xfer_int(ir->usb_ep_out)) + usb_fill_int_urb(urb, ir->usbdev, ir->pipe_out, + buf_out, size, mce_write_callback, &tx_done, + ir->usb_ep_out->bInterval); + else + usb_fill_bulk_urb(urb, ir->usbdev, ir->pipe_out, + buf_out, size, mce_write_callback, &tx_done); + memcpy(buf_out, data, size); + + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret) { + dev_err(dev, "Error: mce write submit urb error = %d", ret); + kfree(buf_out); + usb_free_urb(urb); + return ret; + } + + expire = msecs_to_jiffies(USB_TX_TIMEOUT); + ret_wait = wait_for_completion_timeout(&tx_done, expire); + if (!ret_wait) { + dev_err(dev, "Error: mce write timed out (expire = %lu (%dms))", + expire, USB_TX_TIMEOUT); + usb_kill_urb(urb); + ret = (urb->status == -ENOENT ? -ETIMEDOUT : urb->status); + } else { + ret = urb->status; + } + if (ret >= 0) + ret = urb->actual_length; /* bytes written */ switch (urb->status) { /* success */ case 0: - len = urb->actual_length; - - mceusb_dev_printdata(ir, urb->transfer_buffer, len, - 0, len, true); break; case -ECONNRESET: @@ -790,140 +861,135 @@ static void mce_async_callback(struct urb *urb) break; case -EPIPE: - dev_err(ir->dev, "Error: request urb status = %d (TX HALT)", + dev_err(ir->dev, "Error: mce write urb status = %d (TX HALT)", urb->status); mceusb_defer_kevent(ir, EVENT_TX_HALT); break; default: - dev_err(ir->dev, "Error: request urb status = %d", urb->status); + dev_err(ir->dev, "Error: mce write urb status = %d", + urb->status); break; } - /* the transfer buffer and urb were allocated in mce_request_packet */ - kfree(urb->transfer_buffer); - usb_free_urb(urb); -} - -/* request outgoing (send) usb packet - used to initialize remote */ -static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data, - int size) -{ - int res; - struct urb *async_urb; - struct device *dev = ir->dev; - unsigned char *async_buf; - - async_urb = usb_alloc_urb(0, GFP_KERNEL); - if (unlikely(!async_urb)) { - dev_err(dev, "Error, couldn't allocate urb!"); - return; - } - - async_buf = kmalloc(size, GFP_KERNEL); - if (!async_buf) { - usb_free_urb(async_urb); - return; - } + dev_dbg(dev, "tx done status = %d (wait = %lu, expire = %lu (%dms), urb->actual_length = %d, urb->status = %d)", + ret, ret_wait, expire, USB_TX_TIMEOUT, + urb->actual_length, urb->status); - /* outbound data */ - if (usb_endpoint_xfer_int(ir->usb_ep_out)) - usb_fill_int_urb(async_urb, ir->usbdev, ir->pipe_out, - async_buf, size, mce_async_callback, ir, - ir->usb_ep_out->bInterval); - else - usb_fill_bulk_urb(async_urb, ir->usbdev, ir->pipe_out, - async_buf, size, mce_async_callback, ir); - - memcpy(async_buf, data, size); - - dev_dbg(dev, "send request called (size=%#x)", size); + kfree(buf_out); + usb_free_urb(urb); - res = usb_submit_urb(async_urb, GFP_ATOMIC); - if (res) { - dev_err(dev, "send request FAILED! (res=%d)", res); - kfree(async_buf); - usb_free_urb(async_urb); - return; - } - dev_dbg(dev, "send request complete (res=%d)", res); + return ret; } -static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) +static void mce_command_out(struct mceusb_dev *ir, u8 *data, int size) { int rsize = sizeof(DEVICE_RESUME); if (ir->need_reset) { ir->need_reset = false; - mce_request_packet(ir, DEVICE_RESUME, rsize); + mce_write(ir, DEVICE_RESUME, rsize); msleep(10); } - mce_request_packet(ir, data, size); + mce_write(ir, data, size); msleep(10); } -/* Send data out the IR blaster port(s) */ +/* + * Transmit IR out the MCE device IR blaster port(s). + * + * Convert IR pulse/space sequence from LIRC to MCE format. + * Break up a long IR sequence into multiple parts (MCE IR data packets). + * + * u32 txbuf[] consists of IR pulse, space, ..., and pulse times in usec. + * Pulses and spaces are implicit by their position. + * The first IR sample, txbuf[0], is always a pulse. + * + * u8 irbuf[] consists of multiple IR data packets for the MCE device. + * A packet is 1 u8 MCE_IRDATA_HEADER and up to 30 u8 IR samples. + * An IR sample is 1-bit pulse/space flag with 7-bit time + * in MCE time units (50usec). + * + * Return: The number of IR samples sent (> 0) or errno (< 0). + */ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) { struct mceusb_dev *ir = dev->priv; - int i, length, ret = 0; - int cmdcount = 0; - unsigned char cmdbuf[MCE_CMDBUF_SIZE]; - - /* MCE tx init header */ - cmdbuf[cmdcount++] = MCE_CMD_PORT_IR; - cmdbuf[cmdcount++] = MCE_CMD_SETIRTXPORTS; - cmdbuf[cmdcount++] = ir->tx_mask; + u8 cmdbuf[3] = { MCE_CMD_PORT_IR, MCE_CMD_SETIRTXPORTS, 0x00 }; + u8 irbuf[MCE_IRBUF_SIZE]; + int ircount = 0; + unsigned int irsample; + int i, length, ret; /* Send the set TX ports command */ - mce_async_out(ir, cmdbuf, cmdcount); - cmdcount = 0; - - /* Generate mce packet data */ - for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { - txbuf[i] = txbuf[i] / MCE_TIME_UNIT; - - do { /* loop to support long pulses/spaces > 127*50us=6.35ms */ - - /* Insert mce packet header every 4th entry */ - if ((cmdcount < MCE_CMDBUF_SIZE) && - (cmdcount % MCE_CODE_LENGTH) == 0) - cmdbuf[cmdcount++] = MCE_IRDATA_HEADER; - - /* Insert mce packet data */ - if (cmdcount < MCE_CMDBUF_SIZE) - cmdbuf[cmdcount++] = - (txbuf[i] < MCE_PULSE_BIT ? - txbuf[i] : MCE_MAX_PULSE_LENGTH) | - (i & 1 ? 0x00 : MCE_PULSE_BIT); - else { - ret = -EINVAL; - goto out; + cmdbuf[2] = ir->tx_mask; + mce_command_out(ir, cmdbuf, sizeof(cmdbuf)); + + /* Generate mce IR data packet */ + for (i = 0; i < count; i++) { + irsample = txbuf[i] / MCE_TIME_UNIT; + + /* loop to support long pulses/spaces > 6350us (127*50us) */ + while (irsample > 0) { + /* Insert IR header every 30th entry */ + if (ircount % MCE_PACKET_SIZE == 0) { + /* Room for IR header and one IR sample? */ + if (ircount >= MCE_IRBUF_SIZE - 1) { + /* Send near full buffer */ + ret = mce_write(ir, irbuf, ircount); + if (ret < 0) + return ret; + ircount = 0; + } + irbuf[ircount++] = MCE_IRDATA_HEADER; } - } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) && - (txbuf[i] -= MCE_MAX_PULSE_LENGTH)); - } - - /* Check if we have room for the empty packet at the end */ - if (cmdcount >= MCE_CMDBUF_SIZE) { - ret = -EINVAL; - goto out; - } + /* Insert IR sample */ + if (irsample <= MCE_MAX_PULSE_LENGTH) { + irbuf[ircount] = irsample; + irsample = 0; + } else { + irbuf[ircount] = MCE_MAX_PULSE_LENGTH; + irsample -= MCE_MAX_PULSE_LENGTH; + } + /* + * Even i = IR pulse + * Odd i = IR space + */ + irbuf[ircount] |= (i & 1 ? 0 : MCE_PULSE_BIT); + ircount++; + + /* IR buffer full? */ + if (ircount >= MCE_IRBUF_SIZE) { + /* Fix packet length in last header */ + length = ircount % MCE_PACKET_SIZE; + if (length > 0) + irbuf[ircount - length] -= + MCE_PACKET_SIZE - length; + /* Send full buffer */ + ret = mce_write(ir, irbuf, ircount); + if (ret < 0) + return ret; + ircount = 0; + } + } + } /* after for loop, 0 <= ircount < MCE_IRBUF_SIZE */ /* Fix packet length in last header */ - length = cmdcount % MCE_CODE_LENGTH; - cmdbuf[cmdcount - length] -= MCE_CODE_LENGTH - length; + length = ircount % MCE_PACKET_SIZE; + if (length > 0) + irbuf[ircount - length] -= MCE_PACKET_SIZE - length; - /* All mce commands end with an empty packet (0x80) */ - cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER; + /* Append IR trailer (0x80) to final partial (or empty) IR buffer */ + irbuf[ircount++] = MCE_IRDATA_TRAILER; - /* Transmit the command to the mce device */ - mce_async_out(ir, cmdbuf, cmdcount); + /* Send final buffer */ + ret = mce_write(ir, irbuf, ircount); + if (ret < 0) + return ret; -out: - return ret ? ret : count; + return count; } /* Sets active IR outputs -- mce devices typically have two */ @@ -963,7 +1029,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) cmdbuf[2] = MCE_CMD_SIG_END; cmdbuf[3] = MCE_IRDATA_TRAILER; dev_dbg(ir->dev, "disabling carrier modulation"); - mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + mce_command_out(ir, cmdbuf, sizeof(cmdbuf)); return 0; } @@ -977,7 +1043,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) carrier); /* Transmit new carrier to mce device */ - mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + mce_command_out(ir, cmdbuf, sizeof(cmdbuf)); return 0; } } @@ -1000,10 +1066,10 @@ static int mceusb_set_timeout(struct rc_dev *dev, unsigned int timeout) cmdbuf[2] = units >> 8; cmdbuf[3] = units; - mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + mce_command_out(ir, cmdbuf, sizeof(cmdbuf)); /* get receiver timeout value */ - mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); + mce_command_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); return 0; } @@ -1028,7 +1094,7 @@ static int mceusb_set_rx_wideband(struct rc_dev *dev, int enable) ir->wideband_rx_enabled = false; cmdbuf[2] = 1; /* port 1 is long range receiver */ } - mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + mce_command_out(ir, cmdbuf, sizeof(cmdbuf)); /* response from device sets ir->learning_active */ return 0; @@ -1051,7 +1117,7 @@ static int mceusb_set_rx_carrier_report(struct rc_dev *dev, int enable) ir->carrier_report_enabled = true; if (!ir->learning_active) { cmdbuf[2] = 2; /* port 2 is short range receiver */ - mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + mce_command_out(ir, cmdbuf, sizeof(cmdbuf)); } } else { ir->carrier_report_enabled = false; @@ -1062,7 +1128,7 @@ static int mceusb_set_rx_carrier_report(struct rc_dev *dev, int enable) */ if (ir->learning_active && !ir->wideband_rx_enabled) { cmdbuf[2] = 1; /* port 1 is long range receiver */ - mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + mce_command_out(ir, cmdbuf, sizeof(cmdbuf)); } } @@ -1141,6 +1207,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) } break; case MCE_RSP_CMD_ILLEGAL: + case MCE_RSP_TX_TIMEOUT: ir->need_reset = true; break; default: @@ -1279,7 +1346,7 @@ static void mceusb_get_emulator_version(struct mceusb_dev *ir) { /* If we get no reply or an illegal command reply, its ver 1, says MS */ ir->emver = 1; - mce_async_out(ir, GET_EMVER, sizeof(GET_EMVER)); + mce_command_out(ir, GET_EMVER, sizeof(GET_EMVER)); } static void mceusb_gen1_init(struct mceusb_dev *ir) @@ -1325,10 +1392,10 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) dev_dbg(dev, "set handshake - retC = %d", ret); /* device resume */ - mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME)); + mce_command_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME)); /* get hw/sw revision? */ - mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); + mce_command_out(ir, GET_REVISION, sizeof(GET_REVISION)); kfree(data); } @@ -1336,13 +1403,13 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) static void mceusb_gen2_init(struct mceusb_dev *ir) { /* device resume */ - mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME)); + mce_command_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME)); /* get wake version (protocol, key, address) */ - mce_async_out(ir, GET_WAKEVERSION, sizeof(GET_WAKEVERSION)); + mce_command_out(ir, GET_WAKEVERSION, sizeof(GET_WAKEVERSION)); /* unknown what this one actually returns... */ - mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2)); + mce_command_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2)); } static void mceusb_get_parameters(struct mceusb_dev *ir) @@ -1356,24 +1423,24 @@ static void mceusb_get_parameters(struct mceusb_dev *ir) ir->num_rxports = 2; /* get number of tx and rx ports */ - mce_async_out(ir, GET_NUM_PORTS, sizeof(GET_NUM_PORTS)); + mce_command_out(ir, GET_NUM_PORTS, sizeof(GET_NUM_PORTS)); /* get the carrier and frequency */ - mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); + mce_command_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); if (ir->num_txports && !ir->flags.no_tx) /* get the transmitter bitmask */ - mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); + mce_command_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); /* get receiver timeout value */ - mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); + mce_command_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); /* get receiver sensor setting */ - mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); + mce_command_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); for (i = 0; i < ir->num_txports; i++) { cmdbuf[2] = i; - mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + mce_command_out(ir, cmdbuf, sizeof(cmdbuf)); } } @@ -1382,7 +1449,7 @@ static void mceusb_flash_led(struct mceusb_dev *ir) if (ir->emver < 2) return; - mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED)); + mce_command_out(ir, FLASH_LED, sizeof(FLASH_LED)); } /* @@ -1398,28 +1465,59 @@ static void mceusb_deferred_kevent(struct work_struct *work) container_of(work, struct mceusb_dev, kevent); int status; + dev_err(ir->dev, "kevent handler called (flags 0x%lx)", + ir->kevent_flags); + + if (test_bit(EVENT_RST_PEND, &ir->kevent_flags)) { + dev_err(ir->dev, "kevent handler canceled pending USB Reset Device"); + return; + } + if (test_bit(EVENT_RX_HALT, &ir->kevent_flags)) { usb_unlink_urb(ir->urb_in); status = usb_clear_halt(ir->usbdev, ir->pipe_in); + dev_err(ir->dev, "rx clear halt status = %d", status); if (status < 0) { - dev_err(ir->dev, "rx clear halt error %d", - status); + /* + * Unable to clear RX halt/stall. + * Will need to call usb_reset_device(). + */ + dev_err(ir->dev, + "stuck RX HALT state requires USB Reset Device to clear"); + usb_queue_reset_device(ir->usbintf); + set_bit(EVENT_RST_PEND, &ir->kevent_flags); + clear_bit(EVENT_RX_HALT, &ir->kevent_flags); + + /* Cancel all other error events and handlers */ + clear_bit(EVENT_TX_HALT, &ir->kevent_flags); + return; } clear_bit(EVENT_RX_HALT, &ir->kevent_flags); - if (status == 0) { - status = usb_submit_urb(ir->urb_in, GFP_KERNEL); - if (status < 0) { - dev_err(ir->dev, - "rx unhalt submit urb error %d", - status); - } + status = usb_submit_urb(ir->urb_in, GFP_KERNEL); + if (status < 0) { + dev_err(ir->dev, "rx unhalt submit urb error = %d", + status); } } if (test_bit(EVENT_TX_HALT, &ir->kevent_flags)) { status = usb_clear_halt(ir->usbdev, ir->pipe_out); - if (status < 0) - dev_err(ir->dev, "tx clear halt error %d", status); + dev_err(ir->dev, "tx clear halt status = %d", status); + if (status < 0) { + /* + * Unable to clear TX halt/stall. + * Will need to call usb_reset_device(). + */ + dev_err(ir->dev, + "stuck TX HALT state requires USB Reset Device to clear"); + usb_queue_reset_device(ir->usbintf); + set_bit(EVENT_RST_PEND, &ir->kevent_flags); + clear_bit(EVENT_TX_HALT, &ir->kevent_flags); + + /* Cancel all other error events and handlers */ + clear_bit(EVENT_RX_HALT, &ir->kevent_flags); + return; + } clear_bit(EVENT_TX_HALT, &ir->kevent_flags); } } @@ -1581,6 +1679,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, if (!ir->urb_in) goto urb_in_alloc_fail; + ir->usbintf = intf; ir->usbdev = usb_get_dev(dev); ir->dev = &intf->dev; ir->len_in = maxp; @@ -1688,6 +1787,8 @@ static void mceusb_dev_disconnect(struct usb_interface *intf) struct usb_device *dev = interface_to_usbdev(intf); struct mceusb_dev *ir = usb_get_intfdata(intf); + dev_dbg(&intf->dev, "%s called", __func__); + usb_set_intfdata(intf, NULL); if (!ir) diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 72a7bbbf6b1f..51c6dd3406a0 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -117,10 +117,8 @@ static int meson_ir_probe(struct platform_device *pdev) return PTR_ERR(ir->reg); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "no irq resource\n"); + if (irq < 0) return irq; - } ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); if (!ir->rc) { diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c index 50fb0aebb8d4..a0c94ab322c7 100644 --- a/drivers/media/rc/mtk-cir.c +++ b/drivers/media/rc/mtk-cir.c @@ -35,6 +35,11 @@ /* Fields containing pulse width data */ #define MTK_WIDTH_MASK (GENMASK(7, 0)) +/* IR threshold */ +#define MTK_IRTHD 0x14 +#define MTK_DG_CNT_MASK (GENMASK(12, 8)) +#define MTK_DG_CNT(x) ((x) << 8) + /* Bit to enable interrupt */ #define MTK_IRINT_EN BIT(0) @@ -340,7 +345,7 @@ static int mtk_ir_probe(struct platform_device *pdev) ir->rc->map_name = map_name ?: RC_MAP_EMPTY; ir->rc->dev.parent = dev; ir->rc->driver_name = MTK_IR_DEV; - ir->rc->allowed_protocols = RC_PROTO_BIT_ALL; + ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; ir->rc->rx_resolution = MTK_IR_SAMPLE; ir->rc->timeout = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1); @@ -353,10 +358,8 @@ static int mtk_ir_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ir); ir->irq = platform_get_irq(pdev, 0); - if (ir->irq < 0) { - dev_err(dev, "no irq resource\n"); + if (ir->irq < 0) return -ENODEV; - } if (clk_prepare_enable(ir->clk)) { dev_err(dev, "try to enable ir_clk failed\n"); @@ -398,6 +401,9 @@ static int mtk_ir_probe(struct platform_device *pdev) mtk_w32_mask(ir, val, ir->data->fields[MTK_HW_PERIOD].mask, ir->data->fields[MTK_HW_PERIOD].reg); + /* Set de-glitch counter */ + mtk_w32_mask(ir, MTK_DG_CNT(1), MTK_DG_CNT_MASK, MTK_IRTHD); + /* Enable IR and PWM */ val = mtk_r32(ir, MTK_CONFIG_HIGH_REG); val |= MTK_OK_COUNT(ir->data->ok_count) | MTK_PWM_EN | MTK_IR_EN; diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index aa719d0ae6b0..e222b4c98be4 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -39,11 +39,11 @@ /* Rx Interrupt Enable */ #define SUNXI_IR_RXINT_REG 0x2C -/* Rx FIFO Overflow */ +/* Rx FIFO Overflow Interrupt Enable */ #define REG_RXINT_ROI_EN BIT(0) -/* Rx Packet End */ +/* Rx Packet End Interrupt Enable */ #define REG_RXINT_RPEI_EN BIT(1) -/* Rx FIFO Data Available */ +/* Rx FIFO Data Available Interrupt Enable */ #define REG_RXINT_RAI_EN BIT(4) /* Rx FIFO available byte level */ @@ -51,6 +51,12 @@ /* Rx Interrupt Status */ #define SUNXI_IR_RXSTA_REG 0x30 +/* Rx FIFO Overflow */ +#define REG_RXSTA_ROI REG_RXINT_ROI_EN +/* Rx Packet End */ +#define REG_RXSTA_RPE REG_RXINT_RPEI_EN +/* Rx FIFO Data Available */ +#define REG_RXSTA_RA REG_RXINT_RAI_EN /* RX FIFO Get Available Counter */ #define REG_RXSTA_GET_AC(val) (((val) >> 8) & (ir->fifo_size * 2 - 1)) /* Clear all interrupt status value */ @@ -72,6 +78,17 @@ /* Time after which device stops sending data in ms */ #define SUNXI_IR_TIMEOUT 120 +/** + * struct sunxi_ir_quirks - Differences between SoC variants. + * + * @has_reset: SoC needs reset deasserted. + * @fifo_size: size of the fifo. + */ +struct sunxi_ir_quirks { + bool has_reset; + int fifo_size; +}; + struct sunxi_ir { spinlock_t ir_lock; struct rc_dev *rc; @@ -99,7 +116,7 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id) /* clean all pending statuses */ writel(status | REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG); - if (status & (REG_RXINT_RAI_EN | REG_RXINT_RPEI_EN)) { + if (status & (REG_RXSTA_RA | REG_RXSTA_RPE)) { /* How many messages in fifo */ rc = REG_RXSTA_GET_AC(status); /* Sanity check */ @@ -115,9 +132,9 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id) } } - if (status & REG_RXINT_ROI_EN) { + if (status & REG_RXSTA_ROI) { ir_raw_event_reset(ir->rc); - } else if (status & REG_RXINT_RPEI_EN) { + } else if (status & REG_RXSTA_RPE) { ir_raw_event_set_idle(ir->rc, true); ir_raw_event_handle(ir->rc); } @@ -134,6 +151,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *dn = dev->of_node; + const struct sunxi_ir_quirks *quirks; struct resource *res; struct sunxi_ir *ir; u32 b_clk_freq = SUNXI_IR_BASE_CLK; @@ -142,12 +160,15 @@ static int sunxi_ir_probe(struct platform_device *pdev) if (!ir) return -ENOMEM; + quirks = of_device_get_match_data(&pdev->dev); + if (!quirks) { + dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); + return -ENODEV; + } + spin_lock_init(&ir->ir_lock); - if (of_device_is_compatible(dn, "allwinner,sun5i-a13-ir")) - ir->fifo_size = 64; - else - ir->fifo_size = 16; + ir->fifo_size = quirks->fifo_size; /* Clock */ ir->apb_clk = devm_clk_get(dev, "apb"); @@ -164,13 +185,15 @@ static int sunxi_ir_probe(struct platform_device *pdev) /* Base clock frequency (optional) */ of_property_read_u32(dn, "clock-frequency", &b_clk_freq); - /* Reset (optional) */ - ir->rst = devm_reset_control_get_optional_exclusive(dev, NULL); - if (IS_ERR(ir->rst)) - return PTR_ERR(ir->rst); - ret = reset_control_deassert(ir->rst); - if (ret) - return ret; + /* Reset */ + if (quirks->has_reset) { + ir->rst = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(ir->rst)) + return PTR_ERR(ir->rst); + ret = reset_control_deassert(ir->rst); + if (ret) + return ret; + } ret = clk_set_rate(ir->clk, b_clk_freq); if (ret) { @@ -233,7 +256,6 @@ static int sunxi_ir_probe(struct platform_device *pdev) /* IRQ */ ir->irq = platform_get_irq(pdev, 0); if (ir->irq < 0) { - dev_err(dev, "no irq resource\n"); ret = ir->irq; goto exit_free_dev; } @@ -306,10 +328,35 @@ static int sunxi_ir_remove(struct platform_device *pdev) return 0; } +static const struct sunxi_ir_quirks sun4i_a10_ir_quirks = { + .has_reset = false, + .fifo_size = 16, +}; + +static const struct sunxi_ir_quirks sun5i_a13_ir_quirks = { + .has_reset = false, + .fifo_size = 64, +}; + +static const struct sunxi_ir_quirks sun6i_a31_ir_quirks = { + .has_reset = true, + .fifo_size = 64, +}; + static const struct of_device_id sunxi_ir_match[] = { - { .compatible = "allwinner,sun4i-a10-ir", }, - { .compatible = "allwinner,sun5i-a13-ir", }, - {}, + { + .compatible = "allwinner,sun4i-a10-ir", + .data = &sun4i_a10_ir_quirks, + }, + { + .compatible = "allwinner,sun5i-a13-ir", + .data = &sun5i_a13_ir_quirks, + }, + { + .compatible = "allwinner,sun6i-a31-ir", + .data = &sun6i_a31_ir_quirks, + }, + {} }; MODULE_DEVICE_TABLE(of, sunxi_ir_match); diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig index 08386abb9bbc..bcc49cb47de6 100644 --- a/drivers/media/spi/Kconfig +++ b/drivers/media/spi/Kconfig @@ -1,8 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only if VIDEO_V4L2 +comment "SPI drivers hidden by 'Autoselect ancillary drivers'" + depends on MEDIA_HIDE_ANCILLARY_SUBDRV + menu "SPI helper chips" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT + visible if !MEDIA_HIDE_ANCILLARY_SUBDRV config VIDEO_GS1662 tristate "Gennum Serializers video" diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index a7108e575e9b..e104bb7766e1 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -15,8 +15,12 @@ config MEDIA_TUNER select MEDIA_TUNER_TDA9887 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MC44S803 if MEDIA_SUBDRV_AUTOSELECT +comment "Tuner drivers hidden by 'Autoselect ancillary drivers'" + depends on MEDIA_HIDE_ANCILLARY_SUBDRV + depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT + menu "Customize TV tuners" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT + visible if !MEDIA_HIDE_ANCILLARY_SUBDRV depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT config MEDIA_TUNER_SIMPLE diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index aa6861dcd3fd..574c3bb135d7 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c @@ -381,7 +381,7 @@ static int load_all_firmwares(struct dvb_frontend *fe, goto corrupt; } - priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); + priv->firm[n].ptr = kmemdup(p, size, GFP_KERNEL); if (priv->firm[n].ptr == NULL) { tuner_err("Not enough memory to load firmware file.\n"); rc = -ENOMEM; @@ -394,7 +394,6 @@ static int load_all_firmwares(struct dvb_frontend *fe, type, (unsigned long long)id, size); } - memcpy(priv->firm[n].ptr, p, size); priv->firm[n].type = type; priv->firm[n].id = id; priv->firm[n].size = size; diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c index 43925e219d81..d9606738ce43 100644 --- a/drivers/media/tuners/xc4000.c +++ b/drivers/media/tuners/xc4000.c @@ -812,7 +812,7 @@ static int xc4000_fwupload(struct dvb_frontend *fe) goto corrupt; } - priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); + priv->firm[n].ptr = kmemdup(p, size, GFP_KERNEL); if (priv->firm[n].ptr == NULL) { printk(KERN_ERR "Not enough memory to load firmware file.\n"); rc = -ENOMEM; @@ -826,7 +826,6 @@ static int xc4000_fwupload(struct dvb_frontend *fe) type, (unsigned long long)id, size); } - memcpy(priv->firm[n].ptr, p, size); priv->firm[n].type = type; priv->firm[n].id = id; priv->firm[n].size = size; diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index b35231ffe503..751703db06f5 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -71,7 +71,6 @@ static const struct v4l2_frequency_band bands_rf[] = { /* stream formats */ struct airspy_format { - char *name; u32 pixelformat; u32 buffersize; }; @@ -79,7 +78,6 @@ struct airspy_format { /* format descriptions for capture and preview */ static struct airspy_format formats[] = { { - .name = "Real U12LE", .pixelformat = V4L2_SDR_FMT_RU12LE, .buffersize = BULK_BUFFER_SIZE, }, @@ -622,7 +620,6 @@ static int airspy_enum_fmt_sdr_cap(struct file *file, void *priv, if (f->index >= NUM_FORMATS) return -EINVAL; - strscpy(f->description, formats[f->index].name, sizeof(f->description)); f->pixelformat = formats[f->index].pixelformat; return 0; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 5e00019bce8a..d1895334cbbf 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1153,7 +1153,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, format->fmt.pix.sizeimage = width * height * 2; format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; format->fmt.pix.field = V4L2_FIELD_INTERLACED; - format->fmt.pix.priv = 0; if (cmd == VIDIOC_TRY_FMT) return 0; @@ -1207,10 +1206,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, dprintk(1, "%s called\n", __func__); - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strscpy(f->description, "Packed YUV2", sizeof(f->description)); - - f->flags = 0; f->pixelformat = V4L2_PIX_FMT_UYVY; return 0; @@ -1231,7 +1226,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.sizeimage = dev->frame_size; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */ f->fmt.pix.field = V4L2_FIELD_INTERLACED; - f->fmt.pix.priv = 0; return 0; } diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index 17468f7d78ed..3ab80a7b4498 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -676,6 +676,10 @@ static int submit_urbs(struct camera_data *cam) if (!urb) { for (j = 0; j < i; j++) usb_free_urb(cam->sbuf[j].urb); + for (j = 0; j < NUM_SBUF; j++) { + kfree(cam->sbuf[j].data); + cam->sbuf[j].data = NULL; + } return -ENOMEM; } diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c index 0feae825cebb..626264a56517 100644 --- a/drivers/media/usb/cpia2/cpia2_v4l.c +++ b/drivers/media/usb/cpia2/cpia2_v4l.c @@ -292,28 +292,13 @@ static int cpia2_s_input(struct file *file, void *fh, unsigned int i) static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - int index = f->index; - - if (index < 0 || index > 1) - return -EINVAL; + if (f->index > 1) + return -EINVAL; - memset(f, 0, sizeof(*f)); - f->index = index; - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->flags = V4L2_FMT_FLAG_COMPRESSED; - switch(index) { - case 0: - strscpy(f->description, "MJPEG", sizeof(f->description)); + if (f->index == 0) f->pixelformat = V4L2_PIX_FMT_MJPEG; - break; - case 1: - strscpy(f->description, "JPEG", sizeof(f->description)); + else f->pixelformat = V4L2_PIX_FMT_JPEG; - break; - default: - return -EINVAL; - } - return 0; } @@ -338,7 +323,6 @@ static int cpia2_try_fmt_vid_cap(struct file *file, void *fh, f->fmt.pix.bytesperline = 0; f->fmt.pix.sizeimage = cam->frame_size; f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - f->fmt.pix.priv = 0; switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) { case VIDEOSIZE_VGA: @@ -449,7 +433,6 @@ static int cpia2_g_fmt_vid_cap(struct file *file, void *fh, f->fmt.pix.bytesperline = 0; f->fmt.pix.sizeimage = cam->frame_size; f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - f->fmt.pix.priv = 0; return 0; } diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 2475f69a2f1c..6d218a036966 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1051,6 +1051,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev) p_current_fw = p_fw; vfree(p_current_fw); p_current_fw = NULL; + vfree(p_buffer); uninitGPIO(dev); release_firmware(firmware); dprintk(1, "Firmware upload successful.\n"); @@ -1592,7 +1593,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, "MPEG", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; return 0; diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index e0d98ba8fdbf..e123e74c549e 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -1351,7 +1351,7 @@ static void cx231xx_unregister_media_device(struct cx231xx *dev) /* * cx231xx_realease_resources() * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload + * called when the device gets disconnected or at module unload */ void cx231xx_release_resources(struct cx231xx *dev) { @@ -1924,7 +1924,7 @@ err_if: /* * cx231xx_usb_disconnect() - * called when the device gets diconencted + * called when the device gets disconnected * video device will be unregistered on v4l2_close in case it is still open */ static void cx231xx_usb_disconnect(struct usb_interface *interface) diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index a749baadc1f1..982cb56e97e9 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -53,7 +53,7 @@ static DEFINE_MUTEX(cx231xx_devlist_mutex); /* * cx231xx_realease_resources() * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload + * called when the device gets disconnected or at module unload */ void cx231xx_remove_from_devlist(struct cx231xx *dev) { diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index b651ac7713ea..9b51f07a729e 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -80,7 +80,6 @@ MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); /* supported video standards */ static struct cx231xx_fmt format[] = { { - .name = "16bpp YUY2, 4:2:2, packed", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .reg = 0, @@ -1578,7 +1577,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (unlikely(f->index >= ARRAY_SIZE(format))) return -EINVAL; - strscpy(f->description, format[f->index].name, sizeof(f->description)); f->pixelformat = format[f->index].fourcc; return 0; @@ -1839,7 +1837,7 @@ static int cx231xx_v4l2_open(struct file *filp) /* * cx231xx_realease_resources() * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload + * called when the device gets disconnected or at module unload */ void cx231xx_release_analog_resources(struct cx231xx *dev) { diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 3efa8ff93c1c..b007611abc37 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -121,7 +121,6 @@ #define CX23417_RESET 9 struct cx23417_fmt { - char *name; u32 fourcc; /* v4l2 format id */ int depth; int flags; diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index 8610487f2d72..617a306f6815 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -540,6 +540,8 @@ static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap) si2168_config.i2c_adapter = &i2c_adapter; si2168_config.fe = &adap->fe[0]; si2168_config.ts_mode = SI2168_TS_PARALLEL; + if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2) + si2168_config.ts_mode |= SI2168_TS_CLK_MANUAL; si2168_config.ts_clock_inv = 1; state->i2c_client_demod = dvb_module_probe("si2168", NULL, @@ -550,11 +552,19 @@ static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap) /* attach tuner */ si2157_config.fe = adap->fe[0]; - si2157_config.if_port = 0; - - state->i2c_client_tuner = dvb_module_probe("si2157", "si2141", - i2c_adapter, - 0x60, &si2157_config); + if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230) { + si2157_config.if_port = 1; + state->i2c_client_tuner = dvb_module_probe("si2157", NULL, + i2c_adapter, + 0x60, + &si2157_config); + } else { + si2157_config.if_port = 0; + state->i2c_client_tuner = dvb_module_probe("si2157", "si2141", + i2c_adapter, + 0x60, + &si2157_config); + } if (!state->i2c_client_tuner) { dvb_module_release(state->i2c_client_demod); return -ENODEV; @@ -776,9 +786,15 @@ static const struct usb_device_id dvbsky_id_table[] = { { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R4, &dvbsky_s960_props, "Terratec Cinergy S2 Rev.4", RC_MAP_DVBSKY) }, + { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230, + &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230", + RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C, &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C", RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, + { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2, + &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C v2", + RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, { } }; MODULE_DEVICE_TABLE(usb, dvbsky_id_table); diff --git a/drivers/media/usb/dvb-usb-v2/ec168.c b/drivers/media/usb/dvb-usb-v2/ec168.c index 0c1fef118be4..e30305876840 100644 --- a/drivers/media/usb/dvb-usb-v2/ec168.c +++ b/drivers/media/usb/dvb-usb-v2/ec168.c @@ -309,7 +309,7 @@ static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff) /* DVB USB Driver stuff */ /* bInterfaceNumber 0 is HID * bInterfaceNumber 1 is DVB-T */ -static struct dvb_usb_device_properties ec168_props = { +static const struct dvb_usb_device_properties ec168_props = { .driver_name = KBUILD_MODNAME, .owner = THIS_MODULE, .adapter_nr = adapter_nr, diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c index b784d9da1a82..c7197e534c02 100644 --- a/drivers/media/usb/dvb-usb-v2/gl861.c +++ b/drivers/media/usb/dvb-usb-v2/gl861.c @@ -353,7 +353,7 @@ static int friio_ext_ctl(struct dvb_usb_device *d, ret += i2c_transfer(&d->i2c_adap, &msg, 1); /* send 32bit(satur, R, G, B) data in serial */ - mask = 1 << 31; + mask = 1UL << 31; for (i = 0; i < 32; i++) { buf[1] = power | FRIIO_CTL_STROBE; if (sat_color & mask) diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index bac0778f7def..f02fa0a67aa4 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -78,7 +78,6 @@ enum cxusb_table_index { DVICO_BLUEBIRD_DUAL_4_REV_2, CONEXANT_D680_DMB, MYGICA_D689, - MYGICA_T230, NR__cxusb_table_index }; @@ -456,26 +455,6 @@ static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return 0; } -static int cxusb_read_status(struct dvb_frontend *fe, - enum fe_status *status) -{ - struct dvb_usb_adapter *adap = (struct dvb_usb_adapter *)fe->dvb->priv; - struct cxusb_state *state = (struct cxusb_state *)adap->dev->priv; - int ret; - - ret = state->fe_read_status(fe, status); - - /* it need resync slave fifo when signal change from unlock to lock.*/ - if ((*status & FE_HAS_LOCK) && (!state->last_lock)) { - mutex_lock(&state->stream_mutex); - cxusb_streaming_ctrl(adap, 1); - mutex_unlock(&state->stream_mutex); - } - - state->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0; - return ret; -} - static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) { int ep = d->props.generic_bulk_ctrl_endpoint; @@ -1374,86 +1353,6 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) return 0; } -static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap->dev; - struct cxusb_state *st = d->priv; - struct i2c_adapter *adapter; - struct i2c_client *client_demod; - struct i2c_client *client_tuner; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - - /* Select required USB configuration */ - if (usb_set_interface(d->udev, 0, 0) < 0) - err("set interface failed"); - - /* Unblock all USB pipes */ - usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, - d->props.adapter[0].fe[0].stream.endpoint)); - - /* attach frontend */ - si2168_config.i2c_adapter = &adapter; - si2168_config.fe = &adap->fe_adap[0].fe; - si2168_config.ts_mode = SI2168_TS_PARALLEL; - si2168_config.ts_clock_inv = 1; - memset(&info, 0, sizeof(struct i2c_board_info)); - strscpy(info.type, "si2168", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2168_config; - request_module(info.type); - client_demod = i2c_new_device(&d->i2c_adap, &info); - if (!client_demod || !client_demod->dev.driver) - return -ENODEV; - - if (!try_module_get(client_demod->dev.driver->owner)) { - i2c_unregister_device(client_demod); - return -ENODEV; - } - - st->i2c_client_demod = client_demod; - - /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = adap->fe_adap[0].fe; - si2157_config.if_port = 1; - memset(&info, 0, sizeof(struct i2c_board_info)); - strscpy(info.type, "si2157", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module(info.type); - client_tuner = i2c_new_device(adapter, &info); - if (!client_tuner || !client_tuner->dev.driver) { - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); - return -ENODEV; - } - if (!try_module_get(client_tuner->dev.driver->owner)) { - i2c_unregister_device(client_tuner); - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); - return -ENODEV; - } - - st->i2c_client_tuner = client_tuner; - - /* hook fe: need to resync the slave fifo when signal locks. */ - mutex_init(&st->stream_mutex); - st->last_lock = 0; - st->fe_read_status = adap->fe_adap[0].fe->ops.read_status; - adap->fe_adap[0].fe->ops.read_status = cxusb_read_status; - - return 0; -} - /* * DViCO has shipped two devices with the same USB ID, but only one of them * needs a firmware download. Check the device class details to see if they @@ -1633,7 +1532,6 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope static struct dvb_usb_device_properties cxusb_aver_a868r_properties; static struct dvb_usb_device_properties cxusb_d680_dmb_properties; static struct dvb_usb_device_properties cxusb_mygica_d689_properties; -static struct dvb_usb_device_properties cxusb_mygica_t230_properties; static int cxusb_medion_priv_init(struct dvb_usb_device *dvbdev) { @@ -1759,8 +1657,6 @@ static int cxusb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) || !dvb_usb_device_init(intf, &cxusb_mygica_d689_properties, THIS_MODULE, NULL, adapter_nr) || - !dvb_usb_device_init(intf, &cxusb_mygica_t230_properties, - THIS_MODULE, NULL, adapter_nr) || 0) return 0; @@ -1862,9 +1758,6 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { [MYGICA_D689] = { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) }, - [MYGICA_T230] = { - USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230) - }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, cxusb_table); @@ -2535,60 +2428,6 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { } }; -static struct dvb_usb_device_properties cxusb_mygica_t230_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_mygica_t230_frontend_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - } }, - }, - }, - - .power_ctrl = cxusb_d680_dmb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.core = { - .rc_interval = 100, - .rc_codes = RC_MAP_D680_DMB, - .module_name = KBUILD_MODNAME, - .rc_query = cxusb_d680_dmb_rc_query, - .allowed_protos = RC_PROTO_BIT_UNKNOWN, - }, - - .num_device_descs = 1, - .devices = { - { - "Mygica T230 DVB-T/T2/C", - { NULL }, - { &cxusb_table[MYGICA_T230], NULL }, - }, - } -}; - static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 66d685065e06..ab7a100ec84f 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -2439,9 +2439,13 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) 8, 0x0486, }; + if (!IS_ENABLED(CONFIG_DVB_DIB9000)) + return -ENODEV; if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &dib9090_dib0090_config) == NULL) return -ENODEV; i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + if (!i2c) + return -ENODEV; if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) return -ENODEV; dib0700_set_i2c_speed(adap->dev, 1500); @@ -2517,10 +2521,14 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) 0, 0x00ef, 8, 0x0406, }; + if (!IS_ENABLED(CONFIG_DVB_DIB9000)) + return -ENODEV; i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe); if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &nim9090md_dib0090_config[0]) == NULL) return -ENODEV; i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + if (!i2c) + return -ENODEV; if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) return -ENODEV; diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c index d6b36e4f33d2..441d878fc22c 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -909,14 +909,6 @@ static int pctv452e_frontend_attach(struct dvb_usb_adapter *a) &a->dev->i2c_adap); if (!a->fe_adap[0].fe) return -ENODEV; - - /* - * dvb_frontend will call dvb_detach for both stb0899_detach - * and stb0899_release but we only do dvb_attach(stb0899_attach). - * Increment the module refcount instead. - */ - symbol_get(stb0899_attach); - if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe, &a->dev->i2c_adap)) == NULL) err("Cannot attach lnbp22\n"); diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index c659e18b358b..676d233d46d5 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -608,10 +608,9 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) static int technisat_usb2_get_ir(struct dvb_usb_device *d) { struct technisat_usb2_state *state = d->priv; - u8 *buf = state->buf; - u8 *b; - int ret; struct ir_raw_event ev; + u8 *buf = state->buf; + int i, ret; buf[0] = GET_IR_DATA_VENDOR_REQUEST; buf[1] = 0x08; @@ -647,26 +646,25 @@ unlock: return 0; /* no key pressed */ /* decoding */ - b = buf+1; #if 0 deb_rc("RC: %d ", ret); - debug_dump(b, ret, deb_rc); + debug_dump(buf + 1, ret, deb_rc); #endif ev.pulse = 0; - while (1) { - ev.pulse = !ev.pulse; - ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000; - ir_raw_event_store(d->rc_dev, &ev); - - b++; - if (*b == 0xff) { + for (i = 1; i < ARRAY_SIZE(state->buf); i++) { + if (buf[i] == 0xff) { ev.pulse = 0; ev.duration = 888888*2; ir_raw_event_store(d->rc_dev, &ev); break; } + + ev.pulse = !ev.pulse; + ev.duration = (buf[i] * FIRMWARE_CLOCK_DIVISOR * + FIRMWARE_CLOCK_TICK) / 1000; + ir_raw_event_store(d->rc_dev, &ev); } ir_raw_event_handle(d->rc_dev); diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 1283c7ca9ad5..5983e72a0622 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3566,13 +3566,12 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, static int em28xx_duplicate_dev(struct em28xx *dev) { int nr; - struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL); + struct em28xx *sec_dev = kmemdup(dev, sizeof(*sec_dev), GFP_KERNEL); if (!sec_dev) { dev->dev_next = NULL; return -ENOMEM; } - memcpy(sec_dev, dev, sizeof(*sec_dev)); /* Check to see next free device and mark as used */ do { nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); @@ -4020,7 +4019,6 @@ static void em28xx_usb_disconnect(struct usb_interface *intf) dev->dev_next->disconnected = 1; dev_info(&dev->intf->dev, "Disconnecting %s\n", dev->dev_next->name); - flush_request_modules(dev->dev_next); } dev->disconnected = 1; diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 2b8c84a5c9a8..e6088b5d1b80 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -931,7 +931,7 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, usb_bufs->buf = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!usb_bufs->buf) { - kfree(usb_bufs->buf); + kfree(usb_bufs->urb); return -ENOMEM; } diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 0512e1959394..b0f7390e4b4f 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -102,37 +102,30 @@ MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); /* supported video standards */ static struct em28xx_fmt format[] = { { - .name = "16 bpp YUY2, 4:2:2, packed", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .reg = EM28XX_OUTFMT_YUV422_Y0UY1V, }, { - .name = "16 bpp RGB 565, LE", .fourcc = V4L2_PIX_FMT_RGB565, .depth = 16, .reg = EM28XX_OUTFMT_RGB_16_656, }, { - .name = "8 bpp Bayer RGRG..GBGB", .fourcc = V4L2_PIX_FMT_SRGGB8, .depth = 8, .reg = EM28XX_OUTFMT_RGB_8_RGRG, }, { - .name = "8 bpp Bayer BGBG..GRGR", .fourcc = V4L2_PIX_FMT_SBGGR8, .depth = 8, .reg = EM28XX_OUTFMT_RGB_8_BGBG, }, { - .name = "8 bpp Bayer GRGR..BGBG", .fourcc = V4L2_PIX_FMT_SGRBG8, .depth = 8, .reg = EM28XX_OUTFMT_RGB_8_GRGR, }, { - .name = "8 bpp Bayer GBGB..RGRG", .fourcc = V4L2_PIX_FMT_SGBRG8, .depth = 8, .reg = EM28XX_OUTFMT_RGB_8_GBGB, }, { - .name = "12 bpp YUV411", .fourcc = V4L2_PIX_FMT_YUV411P, .depth = 12, .reg = EM28XX_OUTFMT_YUV411, @@ -1517,7 +1510,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, else f->fmt.pix.field = v4l2->interlaced_fieldmode ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; - f->fmt.pix.priv = 0; return 0; } @@ -2011,7 +2003,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (unlikely(f->index >= ARRAY_SIZE(format))) return -EINVAL; - strscpy(f->description, format[f->index].name, sizeof(f->description)); f->pixelformat = format[f->index].fourcc; return 0; @@ -2208,7 +2199,7 @@ static int em28xx_v4l2_open(struct file *filp) /* * em28xx_v4l2_fini() * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload + * called when the device gets disconnected or at module unload */ static int em28xx_v4l2_fini(struct em28xx *dev) { diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index a551072e62ed..c8bc59059a19 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -251,13 +251,11 @@ struct em28xx_usb_ctl { /** * struct em28xx_fmt - Struct to enumberate video formats * - * @name: Name for the video standard * @fourcc: v4l2 format id * @depth: mean number of bits to represent a pixel * @reg: em28xx register value to set it */ struct em28xx_fmt { - char *name; u32 fourcc; int depth; int reg; @@ -657,7 +655,7 @@ struct em28xx { enum em28xx_chip_id chip_id; unsigned int is_em25xx:1; // em25xx/em276x/7x/8x family bridge - unsigned int disconnected:1; // device has been diconnected + unsigned int disconnected:1; // device has been disconnected unsigned int has_video:1; unsigned int is_audio_only:1; unsigned int is_webcam:1; diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index 88edfef80b40..0b3d185f3cb0 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -285,33 +285,22 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *fmt) { - char *desc = NULL; - switch (fmt->index) { case 0: fmt->pixelformat = V4L2_PIX_FMT_MJPEG; - desc = "Motion JPEG"; break; case 1: fmt->pixelformat = V4L2_PIX_FMT_MPEG1; - desc = "MPEG-1 ES"; break; case 2: fmt->pixelformat = V4L2_PIX_FMT_MPEG2; - desc = "MPEG-2 ES"; break; case 3: fmt->pixelformat = V4L2_PIX_FMT_MPEG4; - desc = "MPEG-4 ES"; break; default: return -EINVAL; } - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt->flags = V4L2_FMT_FLAG_COMPRESSED; - - strscpy(fmt->description, desc, sizeof(fmt->description)); - return 0; } diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c index 179d4d642dae..49e75a1a1f3f 100644 --- a/drivers/media/usb/go7007/s2250-board.c +++ b/drivers/media/usb/go7007/s2250-board.c @@ -505,9 +505,9 @@ static int s2250_probe(struct i2c_client *client, struct go7007 *go = i2c_get_adapdata(adapter); struct go7007_usb *usb = go->hpi_context; - audio = i2c_new_dummy(adapter, TLV320_ADDRESS >> 1); - if (audio == NULL) - return -ENOMEM; + audio = i2c_new_dummy_device(adapter, TLV320_ADDRESS >> 1); + if (IS_ERR(audio)) + return PTR_ERR(audio); state = kzalloc(sizeof(struct s2250), GFP_KERNEL); if (state == NULL) { diff --git a/drivers/media/usb/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c index 4a449c62fc32..b05fa227ffb2 100644 --- a/drivers/media/usb/go7007/snd-go7007.c +++ b/drivers/media/usb/go7007/snd-go7007.c @@ -253,7 +253,7 @@ int go7007_snd_init(struct go7007 *go) return ret; } strscpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver)); - strscpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver)); + strscpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->shortname)); strscpy(gosnd->card->longname, gosnd->card->shortname, sizeof(gosnd->card->longname)); diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index be11f7830bca..4add2b12d330 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1024,27 +1024,18 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; /* no more format */ fmtdesc->pixelformat = fmt_tb[index]; - if (gspca_dev->cam.cam_mode[i].sizeimage < - gspca_dev->cam.cam_mode[i].width * - gspca_dev->cam.cam_mode[i].height) - fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED; - fmtdesc->description[0] = fmtdesc->pixelformat & 0xff; - fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff; - fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff; - fmtdesc->description[3] = fmtdesc->pixelformat >> 24; - fmtdesc->description[4] = '\0'; return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) +static int vidioc_g_fmt_vid_cap(struct file *file, void *_priv, + struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); + u32 priv = fmt->fmt.pix.priv; fmt->fmt.pix = gspca_dev->pixfmt; - /* some drivers use priv internally, zero it before giving it back to - the core */ - fmt->fmt.pix.priv = 0; + /* some drivers use priv internally, so keep the original value */ + fmt->fmt.pix.priv = priv; return 0; } @@ -1079,27 +1070,27 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, fmt->fmt.pix.height = h; gspca_dev->sd_desc->try_fmt(gspca_dev, fmt); } - /* some drivers use priv internally, zero it before giving it back to - the core */ - fmt->fmt.pix.priv = 0; return mode; /* used when s_fmt */ } -static int vidioc_try_fmt_vid_cap(struct file *file, - void *priv, - struct v4l2_format *fmt) +static int vidioc_try_fmt_vid_cap(struct file *file, void *_priv, + struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); + u32 priv = fmt->fmt.pix.priv; if (try_fmt_vid_cap(gspca_dev, fmt) < 0) return -EINVAL; + /* some drivers use priv internally, so keep the original value */ + fmt->fmt.pix.priv = priv; return 0; } -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) +static int vidioc_s_fmt_vid_cap(struct file *file, void *_priv, + struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); + u32 priv = fmt->fmt.pix.priv; int mode; if (vb2_is_busy(&gspca_dev->queue)) @@ -1115,6 +1106,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, gspca_dev->pixfmt = fmt->fmt.pix; else gspca_dev->pixfmt = gspca_dev->cam.cam_mode[mode]; + /* some drivers use priv internally, so keep the original value */ + fmt->fmt.pix.priv = priv; return 0; } diff --git a/drivers/media/usb/gspca/konica.c b/drivers/media/usb/gspca/konica.c index d8e40137a204..53db9a2895ea 100644 --- a/drivers/media/usb/gspca/konica.c +++ b/drivers/media/usb/gspca/konica.c @@ -114,6 +114,11 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index) if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, 2); } } diff --git a/drivers/media/usb/gspca/nw80x.c b/drivers/media/usb/gspca/nw80x.c index 59649704beba..880f569bda30 100644 --- a/drivers/media/usb/gspca/nw80x.c +++ b/drivers/media/usb/gspca/nw80x.c @@ -1572,6 +1572,11 @@ static void reg_r(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); return; } if (len == 1) diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c index cfb1f53bc17e..f417dfc0b872 100644 --- a/drivers/media/usb/gspca/ov519.c +++ b/drivers/media/usb/gspca/ov519.c @@ -2073,6 +2073,11 @@ static int reg_r(struct sd *sd, u16 index) } else { gspca_err(gspca_dev, "reg_r %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; + /* + * Make sure the result is zeroed to avoid uninitialized + * values. + */ + gspca_dev->usb_buf[0] = 0; } return ret; @@ -2101,6 +2106,11 @@ static int reg_r8(struct sd *sd, } else { gspca_err(gspca_dev, "reg_r8 %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, 8); } return ret; diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 56521c991db4..185c1f10fb30 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -693,6 +693,11 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) if (ret < 0) { pr_err("read failed %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the result is zeroed to avoid uninitialized + * values. + */ + gspca_dev->usb_buf[0] = 0; } return gspca_dev->usb_buf[0]; } diff --git a/drivers/media/usb/gspca/ov534_9.c b/drivers/media/usb/gspca/ov534_9.c index 867f860a9650..91efc650cf76 100644 --- a/drivers/media/usb/gspca/ov534_9.c +++ b/drivers/media/usb/gspca/ov534_9.c @@ -1145,6 +1145,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg) if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + return 0; } return gspca_dev->usb_buf[0]; } diff --git a/drivers/media/usb/gspca/se401.c b/drivers/media/usb/gspca/se401.c index 061deee138c3..e087cfb5980b 100644 --- a/drivers/media/usb/gspca/se401.c +++ b/drivers/media/usb/gspca/se401.c @@ -101,6 +101,11 @@ static void se401_read_req(struct gspca_dev *gspca_dev, u16 req, int silent) pr_err("read req failed req %#04x error %d\n", req, err); gspca_dev->usb_err = err; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, READ_REQ_SIZE); } } diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c index b43f89fee6c1..2a6d0a1265a7 100644 --- a/drivers/media/usb/gspca/sn9c20x.c +++ b/drivers/media/usb/gspca/sn9c20x.c @@ -124,6 +124,13 @@ static const struct dmi_system_id flip_dmi_table[] = { } }, { + .ident = "MSI MS-1039", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-1039"), + } + }, + { .ident = "MSI MS-1632", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), @@ -909,6 +916,11 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length) if (unlikely(result < 0 || result != length)) { pr_err("Read register %02x failed %d\n", reg, result); gspca_dev->usb_err = result; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c index 046fc2c2a135..4d655e2da9cb 100644 --- a/drivers/media/usb/gspca/sonixb.c +++ b/drivers/media/usb/gspca/sonixb.c @@ -453,6 +453,11 @@ static void reg_r(struct gspca_dev *gspca_dev, dev_err(gspca_dev->v4l2_dev.dev, "Error reading register %02x: %d\n", value, res); gspca_dev->usb_err = res; + /* + * Make sure the result is zeroed to avoid uninitialized + * values. + */ + gspca_dev->usb_buf[0] = 0; } } diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c index 50a6c8425827..2e1bd2df8304 100644 --- a/drivers/media/usb/gspca/sonixj.c +++ b/drivers/media/usb/gspca/sonixj.c @@ -1162,6 +1162,11 @@ static void reg_r(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } diff --git a/drivers/media/usb/gspca/spca1528.c b/drivers/media/usb/gspca/spca1528.c index 2ae03b60163f..ccc477944ef8 100644 --- a/drivers/media/usb/gspca/spca1528.c +++ b/drivers/media/usb/gspca/spca1528.c @@ -71,6 +71,11 @@ static void reg_r(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } diff --git a/drivers/media/usb/gspca/sq930x.c b/drivers/media/usb/gspca/sq930x.c index d1ba0888d798..c3610247a90e 100644 --- a/drivers/media/usb/gspca/sq930x.c +++ b/drivers/media/usb/gspca/sq930x.c @@ -425,6 +425,11 @@ static void reg_r(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r %04x failed %d\n", value, ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } diff --git a/drivers/media/usb/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c index d0ddfa957ca9..f4a4222f0d2e 100644 --- a/drivers/media/usb/gspca/sunplus.c +++ b/drivers/media/usb/gspca/sunplus.c @@ -255,6 +255,11 @@ static void reg_r(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } diff --git a/drivers/media/usb/gspca/vc032x.c b/drivers/media/usb/gspca/vc032x.c index 588a847ea483..4cb7c92ea132 100644 --- a/drivers/media/usb/gspca/vc032x.c +++ b/drivers/media/usb/gspca/vc032x.c @@ -2906,6 +2906,11 @@ static void reg_r_i(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } static void reg_r(struct gspca_dev *gspca_dev, diff --git a/drivers/media/usb/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c index 16b679c2de21..a8350ee9712f 100644 --- a/drivers/media/usb/gspca/w996Xcf.c +++ b/drivers/media/usb/gspca/w996Xcf.c @@ -133,6 +133,11 @@ static int w9968cf_read_sb(struct sd *sd) } else { pr_err("Read SB reg [01] failed\n"); sd->gspca_dev.usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(sd->gspca_dev.usb_buf, 0, 2); } udelay(W9968CF_I2C_BUS_DELAY); diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 9b9d894d29bc..b75c18a012a7 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -137,6 +137,7 @@ static int device_authorization(struct hdpvr_device *dev) dev->fw_ver = dev->usbc_buf[1]; + dev->usbc_buf[46] = '\0'; v4l2_info(&dev->v4l2_dev, "firmware version 0x%x dated %s\n", dev->fw_ver, &dev->usbc_buf[2]); @@ -271,6 +272,7 @@ static int hdpvr_probe(struct usb_interface *interface, #endif size_t buffer_size; int i; + int dev_num; int retval = -ENOMEM; /* allocate memory for our device state and initialize it */ @@ -368,8 +370,17 @@ static int hdpvr_probe(struct usb_interface *interface, } #endif + dev_num = atomic_inc_return(&dev_nr); + if (dev_num >= HDPVR_MAX) { + v4l2_err(&dev->v4l2_dev, + "max device number reached, device register failed\n"); + atomic_dec(&dev_nr); + retval = -ENODEV; + goto reg_fail; + } + retval = hdpvr_register_videodev(dev, &interface->dev, - video_nr[atomic_inc_return(&dev_nr)]); + video_nr[dev_num]); if (retval < 0) { v4l2_err(&dev->v4l2_dev, "registering videodev failed\n"); goto reg_fail; diff --git a/drivers/media/usb/hdpvr/hdpvr-i2c.c b/drivers/media/usb/hdpvr/hdpvr-i2c.c index bc5975b17c0c..785c8508a46e 100644 --- a/drivers/media/usb/hdpvr/hdpvr-i2c.c +++ b/drivers/media/usb/hdpvr/hdpvr-i2c.c @@ -193,8 +193,6 @@ static int hdpvr_activate_ir(struct hdpvr_device *dev) int hdpvr_register_i2c_adapter(struct hdpvr_device *dev) { - int retval = -ENOMEM; - hdpvr_activate_ir(dev); dev->i2c_adapter = hdpvr_i2c_adapter_template; @@ -202,9 +200,7 @@ int hdpvr_register_i2c_adapter(struct hdpvr_device *dev) i2c_set_adapdata(&dev->i2c_adapter, dev); - retval = i2c_add_adapter(&dev->i2c_adapter); - - return retval; + return i2c_add_adapter(&dev->i2c_adapter); } #endif diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 5b3e67b80627..bad71d863d39 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -987,9 +987,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, if (f->index != 0) return -EINVAL; - f->flags = V4L2_FMT_FLAG_COMPRESSED; - strscpy(f->description, "MPEG2-TS with AVC/AAC streams", - sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; return 0; diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 4c9b2a12acfb..65be6f140fe8 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -66,7 +66,6 @@ static const struct v4l2_frequency_band bands[] = { /* stream formats */ struct msi2500_format { - char *name; u32 pixelformat; u32 buffersize; }; @@ -74,27 +73,21 @@ struct msi2500_format { /* format descriptions for capture and preview */ static struct msi2500_format formats[] = { { - .name = "Complex S8", .pixelformat = V4L2_SDR_FMT_CS8, .buffersize = 3 * 1008, #if 0 }, { - .name = "10+2-bit signed", .pixelformat = MSI2500_PIX_FMT_SDR_MSI2500_384, }, { - .name = "12-bit signed", .pixelformat = MSI2500_PIX_FMT_SDR_S12, #endif }, { - .name = "Complex S14LE", .pixelformat = V4L2_SDR_FMT_CS14LE, .buffersize = 3 * 1008, }, { - .name = "Complex U8 (emulated)", .pixelformat = V4L2_SDR_FMT_CU8, .buffersize = 3 * 1008, }, { - .name = "Complex U16LE (emulated)", .pixelformat = V4L2_SDR_FMT_CU16LE, .buffersize = 3 * 1008, }, @@ -904,7 +897,6 @@ static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv, if (f->index >= dev->num_formats) return -EINVAL; - strscpy(f->description, formats[f->index].name, sizeof(f->description)); f->pixelformat = formats[f->index].pixelformat; return 0; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c index 79f0e0c6df37..8e81af537901 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c @@ -39,7 +39,7 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw) int ret; int mode16 = 0; unsigned pcnt,tcnt; - eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL); + eeprom = kzalloc(EEPROM_SIZE, GFP_KERNEL); if (!eeprom) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Failed to allocate memory required to read eeprom"); @@ -74,7 +74,6 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw) (1) we're only fetching part of the eeprom, and (2) if we were getting the whole thing our I2C driver can't grab it in one pass - which is what tveeprom is otherwise going to attempt */ - memset(eeprom,0,EEPROM_SIZE); for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) { pcnt = 16; if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 6fe8b9af858a..1cfb7cf64131 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -660,7 +660,7 @@ static int ctrl_check_input(struct pvr2_ctrl *cptr,int v) { if (v < 0 || v > PVR2_CVAL_INPUT_MAX) return 0; - return ((1 << v) & cptr->hdw->input_allowed_mask) != 0; + return ((1UL << v) & cptr->hdw->input_allowed_mask) != 0; } static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v) @@ -784,7 +784,7 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr) { - struct v4l2_queryctrl qctrl; + struct v4l2_queryctrl qctrl = {}; struct pvr2_ctl_info *info; qctrl.id = cptr->info->v4l_id; cx2341x_ctrl_query(&cptr->hdw->enc_ctl_state,&qctrl); @@ -2445,7 +2445,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, /* Ensure that default input choice is a valid one. */ m = hdw->input_avail_mask; if (m) for (idx = 0; idx < (sizeof(m) << 3); idx++) { - if (!((1 << idx) & m)) continue; + if (!((1UL << idx) & m)) continue; hdw->input_val = idx; break; } @@ -2501,11 +2501,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, // Initialize control data regarding video standard masks valid_std_mask = pvr2_std_get_usable(); for (idx = 0; idx < 32; idx++) { - if (!(valid_std_mask & (1 << idx))) continue; + if (!(valid_std_mask & (1UL << idx))) continue; cnt1 = pvr2_std_id_to_str( hdw->std_mask_names[idx], sizeof(hdw->std_mask_names[idx])-1, - 1 << idx); + 1UL << idx); hdw->std_mask_names[idx][cnt1] = 0; } cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDAVAIL); @@ -3329,7 +3329,7 @@ static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw) int ret; int mode16 = 0; unsigned pcnt,tcnt; - eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL); + eeprom = kzalloc(EEPROM_SIZE, GFP_KERNEL); if (!eeprom) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Failed to allocate memory required to read eeprom"); @@ -3364,7 +3364,6 @@ static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw) (1) we're only fetching part of the eeprom, and (2) if we were getting the whole thing our I2C driver can't grab it in one pass - which is what tveeprom is otherwise going to attempt */ - memset(eeprom,0,EEPROM_SIZE); for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) { pcnt = 16; if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt; @@ -4673,7 +4672,7 @@ static unsigned int print_input_mask(unsigned int msk, unsigned int idx,ccnt; unsigned int tcnt = 0; for (idx = 0; idx < ARRAY_SIZE(control_values_input); idx++) { - if (!((1 << idx) & msk)) continue; + if (!((1UL << idx) & msk)) continue; ccnt = scnprintf(buf+tcnt, acnt-tcnt, "%s%s", @@ -5100,7 +5099,7 @@ int pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw, break; } hdw->input_allowed_mask = nv; - if ((1 << hdw->input_val) & hdw->input_allowed_mask) { + if ((1UL << hdw->input_val) & hdw->input_allowed_mask) { /* Current mode is still in the allowed mask, so we're done. */ break; @@ -5113,7 +5112,7 @@ int pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw, } m = hdw->input_allowed_mask; for (idx = 0; idx < (sizeof(m) << 3); idx++) { - if (!((1 << idx) & m)) continue; + if (!((1UL << idx) & m)) continue; pvr2_hdw_set_input(hdw,idx); break; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 0aff2f396392..a34717eba409 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -1003,7 +1003,7 @@ static int pvr2_v4l2_open(struct file *file) input_mask &= pvr2_hdw_get_input_available(hdw); input_cnt = 0; for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) { - if (input_mask & (1 << idx)) input_cnt++; + if (input_mask & (1UL << idx)) input_cnt++; } fhp->input_cnt = input_cnt; fhp->input_map = kzalloc(input_cnt,GFP_KERNEL); @@ -1018,7 +1018,7 @@ static int pvr2_v4l2_open(struct file *file) } input_cnt = 0; for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) { - if (!(input_mask & (1 << idx))) continue; + if (!(input_mask & (1UL << idx))) continue; fhp->input_map[input_cnt++] = idx; } diff --git a/drivers/media/usb/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c index 76c498cccc49..2f135d533af6 100644 --- a/drivers/media/usb/pwc/pwc-v4l.c +++ b/drivers/media/usb/pwc/pwc-v4l.c @@ -873,14 +873,9 @@ static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc case 0: /* RAW format */ f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2; - f->flags = V4L2_FMT_FLAG_COMPRESSED; - strscpy(f->description, "Raw Philips Webcam", - sizeof(f->description)); break; case 1: f->pixelformat = V4L2_PIX_FMT_YUV420; - strscpy(f->description, "4:2:0, planar, Y-Cb-Cr", - sizeof(f->description)); break; default: return -EINVAL; diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index aa90558479f7..329ec8089592 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -273,7 +273,6 @@ static inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev) } struct s2255_fmt { - char *name; u32 fourcc; int depth; }; @@ -385,29 +384,23 @@ MODULE_DEVICE_TABLE(usb, s2255_table); /* JPEG formats must be defined last to support jpeg_enable parameter */ static const struct s2255_fmt formats[] = { { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16 }, { - .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16 }, { - .name = "4:2:2, planar, YUV422P", .fourcc = V4L2_PIX_FMT_YUV422P, .depth = 16 }, { - .name = "8bpp GREY", .fourcc = V4L2_PIX_FMT_GREY, .depth = 8 }, { - .name = "JPG", .fourcc = V4L2_PIX_FMT_JPEG, .depth = 24 }, { - .name = "MJPG", .fourcc = V4L2_PIX_FMT_MJPEG, .depth = 24 } @@ -737,7 +730,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) return -EINVAL; - strscpy(f->description, formats[index].name, sizeof(f->description)); f->pixelformat = formats[index].fourcc; return 0; } @@ -759,7 +751,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.bytesperline = f->fmt.pix.width * (vc->fmt->depth >> 3); f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.priv = 0; return 0; } @@ -811,7 +802,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.priv = 0; dprintk(vc->dev, 50, "%s: set width %d height %d field %d\n", __func__, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); return 0; diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index b71a0f4b40b5..bcd14c66e8df 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -46,7 +46,6 @@ struct stk1160_decimate_ctrl { /* supported video standards */ static struct stk1160_fmt format[] = { { - .name = "16 bpp YUY2, 4:2:2, packed", .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16, } @@ -346,7 +345,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, format[f->index].name, sizeof(f->description)); f->pixelformat = format[f->index].fourcc; return 0; } diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index 099ce2a2f021..a31ea1c80f25 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -102,7 +102,6 @@ struct stk1160_isoc_ctl { }; struct stk1160_fmt { - char *name; u32 fourcc; /* v4l2 format id */ int depth; }; diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index be8041e3e6b8..cfca3c70599b 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -857,23 +857,18 @@ static int stk_vidioc_enum_fmt_vid_cap(struct file *filp, switch (fmtd->index) { case 0: fmtd->pixelformat = V4L2_PIX_FMT_RGB565; - strscpy(fmtd->description, "r5g6b5", sizeof(fmtd->description)); break; case 1: fmtd->pixelformat = V4L2_PIX_FMT_RGB565X; - strscpy(fmtd->description, "r5g6b5BE", sizeof(fmtd->description)); break; case 2: fmtd->pixelformat = V4L2_PIX_FMT_UYVY; - strscpy(fmtd->description, "yuv4:2:2", sizeof(fmtd->description)); break; case 3: fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8; - strscpy(fmtd->description, "Raw bayer", sizeof(fmtd->description)); break; case 4: fmtd->pixelformat = V4L2_PIX_FMT_YUYV; - strscpy(fmtd->description, "yuv4:2:2", sizeof(fmtd->description)); break; default: return -EINVAL; diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c index 23df50aa0a4a..5358cd8c4603 100644 --- a/drivers/media/usb/tm6000/tm6000-cards.c +++ b/drivers/media/usb/tm6000/tm6000-cards.c @@ -1328,7 +1328,7 @@ put_device: /* * tm6000_usb_disconnect() - * called when the device gets diconencted + * called when the device gets disconnected * video device will be unregistered on v4l2_close in case it is still open */ static void tm6000_usb_disconnect(struct usb_interface *interface) diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c index e4d2dcd5cc0f..19c90fa9e443 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/media/usb/tm6000/tm6000-dvb.c @@ -97,6 +97,7 @@ static void tm6000_urb_received(struct urb *urb) printk(KERN_ERR "tm6000: error %s\n", __func__); kfree(urb->transfer_buffer); usb_free_urb(urb); + dev->dvb->bulk_urb = NULL; } } } @@ -127,6 +128,7 @@ static int tm6000_start_stream(struct tm6000_core *dev) dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); if (!dvb->bulk_urb->transfer_buffer) { usb_free_urb(dvb->bulk_urb); + dvb->bulk_urb = NULL; return -ENOMEM; } @@ -153,6 +155,7 @@ static int tm6000_start_stream(struct tm6000_core *dev) kfree(dvb->bulk_urb->transfer_buffer); usb_free_urb(dvb->bulk_urb); + dvb->bulk_urb = NULL; return ret; } diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 85fcddfb0202..c07a81a6cbe2 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -52,15 +52,12 @@ EXPORT_SYMBOL_GPL(tm6000_debug); static struct tm6000_fmt format[] = { { - .name = "4:2:2, packed, YVY2", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, }, { - .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16, }, { - .name = "A/V + VBI mux packet", .fourcc = V4L2_PIX_FMT_TM6000, .depth = 16, } @@ -875,7 +872,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index >= ARRAY_SIZE(format)) return -EINVAL; - strscpy(f->description, format[f->index].name, sizeof(f->description)); f->pixelformat = format[f->index].fourcc; return 0; } diff --git a/drivers/media/usb/tm6000/tm6000.h b/drivers/media/usb/tm6000/tm6000.h index 0864ed7314eb..bf396544da9a 100644 --- a/drivers/media/usb/tm6000/tm6000.h +++ b/drivers/media/usb/tm6000/tm6000.h @@ -64,7 +64,6 @@ struct tm6000_input { */ struct tm6000_fmt { - char *name; u32 fourcc; /* v4l2 format id */ int depth; }; diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 1d0afa340f47..3198f9624b7c 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -319,7 +319,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, dprintk("%s\n", __func__); - b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); + b = kzalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); if (!b) return -ENOMEM; diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 51f784479e91..3d9284a09ee5 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -633,8 +633,6 @@ static int usbtv_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index > 0) return -EINVAL; - strscpy(f->description, "16 bpp YUY2, 4:2:2, packed", - sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_YUYV; return 0; } diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 93750af82d98..cdc66adda755 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -87,14 +87,14 @@ static int usbvision_nr; static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { - { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" }, - { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" }, - { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" }, - { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" }, - { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" }, - { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" }, - { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, /* 1.5 ! */ - { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } + { 1, 1, 8, V4L2_PIX_FMT_GREY }, + { 1, 2, 16, V4L2_PIX_FMT_RGB565 }, + { 1, 3, 24, V4L2_PIX_FMT_RGB24 }, + { 1, 4, 32, V4L2_PIX_FMT_RGB32 }, + { 1, 2, 16, V4L2_PIX_FMT_RGB555 }, + { 1, 2, 16, V4L2_PIX_FMT_YUYV }, + { 1, 2, 12, V4L2_PIX_FMT_YVU420 }, /* 1.5 ! */ + { 1, 2, 16, V4L2_PIX_FMT_YUV422P } }; /* Function prototypes */ @@ -796,8 +796,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, { if (vfd->index >= USBVISION_SUPPORTED_PALETTES - 1) return -EINVAL; - strscpy(vfd->description, usbvision_v4l2_format[vfd->index].desc, - sizeof(vfd->description)); vfd->pixelformat = usbvision_v4l2_format[vfd->index].format; return 0; } @@ -967,7 +965,6 @@ static ssize_t usbvision_read(struct file *file, char __user *buf, __func__, (unsigned long)count, frame->bytes_read); -#if 1 /* * FIXME: * For now, forget the frame if it has not been read in one shot. @@ -976,15 +973,6 @@ static ssize_t usbvision_read(struct file *file, char __user *buf, /* Mark it as available to be used again. */ frame->grabstate = frame_state_unused; -#else - if (frame->bytes_read >= frame->scanlength) { - /* All data has been read */ - frame->bytes_read = 0; - - /* Mark it as available to be used again. */ - frame->grabstate = frame_state_unused; - } -#endif return count; } diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h index 4198f972a47b..11539578e8d2 100644 --- a/drivers/media/usb/usbvision/usbvision.h +++ b/drivers/media/usb/usbvision/usbvision.h @@ -264,7 +264,6 @@ struct usbvision_v4l2_format_st { int bytes_per_pixel; int depth; int format; - char *desc; }; #define USBVISION_SUPPORTED_PALETTES ARRAY_SIZE(usbvision_v4l2_format) diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 203329cadbc4..0335e69b70ab 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -253,7 +253,6 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(format, frame); fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize; fmt->fmt.pix.colorspace = format->colorspace; - fmt->fmt.pix.priv = 0; if (uvc_format != NULL) *uvc_format = format; @@ -290,7 +289,6 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream, fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(format, frame); fmt->fmt.pix.sizeimage = stream->ctrl.dwMaxVideoFrameSize; fmt->fmt.pix.colorspace = format->colorspace; - fmt->fmt.pix.priv = 0; done: mutex_unlock(&stream->mutex); diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index a9bcba4fa9c6..637962825d7a 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -141,7 +141,6 @@ struct zr364xx_pipeinfo { }; struct zr364xx_fmt { - char *name; u32 fourcc; int depth; }; @@ -149,7 +148,6 @@ struct zr364xx_fmt { /* image formats. */ static const struct zr364xx_fmt formats[] = { { - .name = "JPG", .fourcc = V4L2_PIX_FMT_JPEG, .depth = 24 } @@ -199,12 +197,10 @@ static int send_control_msg(struct usb_device *udev, u8 request, u16 value, { int status; - unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL); + unsigned char *transfer_buffer = kmemdup(cp, size, GFP_KERNEL); if (!transfer_buffer) return -ENOMEM; - memcpy(transfer_buffer, cp, size); - status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, @@ -376,8 +372,7 @@ static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, vb); int rc; - DBG("%s, field=%d, fmt name = %s\n", __func__, field, - cam->fmt ? cam->fmt->name : ""); + DBG("%s, field=%d\n", __func__, field); if (!cam->fmt) return -EINVAL; @@ -751,8 +746,6 @@ static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file, { if (f->index > 0) return -EINVAL; - f->flags = V4L2_FMT_FLAG_COMPRESSED; - strscpy(f->description, formats[0].name, sizeof(f->description)); f->pixelformat = formats[0].fourcc; return 0; } diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 7c5f62f196e5..39e3fb30ba0b 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -11,6 +11,11 @@ config VIDEO_V4L2 select VIDEOBUF2_V4L2 if VIDEOBUF2_CORE default (I2C || I2C=n) && VIDEO_DEV +config VIDEO_V4L2_I2C + bool + depends on I2C && VIDEO_V4L2 + default y + config VIDEO_ADV_DEBUG bool "Enable advanced debug functionality on V4L2 drivers" help diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index 9ee57e1efefe..786bd1ec4d1b 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -7,18 +7,15 @@ tuner-objs := tuner-core.o videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ v4l2-event.o v4l2-ctrls.o v4l2-subdev.o v4l2-clk.o \ - v4l2-async.o -ifeq ($(CONFIG_COMPAT),y) - videodev-objs += v4l2-compat-ioctl32.o -endif -obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o -ifeq ($(CONFIG_TRACEPOINTS),y) - videodev-objs += v4l2-trace.o -endif + v4l2-async.o v4l2-common.o +videodev-$(CONFIG_COMPAT) += v4l2-compat-ioctl32.o +videodev-$(CONFIG_TRACEPOINTS) += v4l2-trace.o videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o +videodev-$(CONFIG_SPI) += v4l2-spi.o +videodev-$(CONFIG_VIDEO_V4L2_I2C) += v4l2-i2c.o +obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o obj-$(CONFIG_VIDEO_V4L2) += videodev.o -obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o obj-$(CONFIG_VIDEO_V4L2) += v4l2-dv-timings.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 8d307b538f52..8bde33c21ce4 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -534,7 +534,7 @@ static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier) { struct v4l2_async_subdev *asd, *tmp; - if (!notifier) + if (!notifier || !notifier->asd_list.next) return; list_for_each_entry_safe(asd, tmp, ¬ifier->asd_list, asd_list) { @@ -593,10 +593,11 @@ v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, return ERR_PTR(-ENOMEM); asd->match_type = V4L2_ASYNC_MATCH_FWNODE; - asd->match.fwnode = fwnode; + asd->match.fwnode = fwnode_handle_get(fwnode); ret = v4l2_async_notifier_add_subdev(notifier, asd); if (ret) { + fwnode_handle_put(fwnode); kfree(asd); return ERR_PTR(ret); } @@ -605,6 +606,29 @@ v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, } EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_subdev); +int +v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif, + struct fwnode_handle *endpoint, + struct v4l2_async_subdev *asd) +{ + struct fwnode_handle *remote; + int ret; + + remote = fwnode_graph_get_remote_port_parent(endpoint); + if (!remote) + return -ENOTCONN; + + asd->match_type = V4L2_ASYNC_MATCH_FWNODE; + asd->match.fwnode = remote; + + ret = v4l2_async_notifier_add_subdev(notif, asd); + if (ret) + fwnode_handle_put(remote); + + return ret; +} +EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_remote_subdev); + struct v4l2_async_subdev * v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier, int adapter_id, unsigned short address, diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index f8ad1c580a3e..62f7aa92ac29 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -40,10 +40,6 @@ #include <linux/mm.h> #include <linux/string.h> #include <linux/errno.h> -#include <linux/i2c.h> -#if defined(CONFIG_SPI) -#include <linux/spi/spi.h> -#endif #include <linux/uaccess.h> #include <asm/pgtable.h> #include <asm/io.h> @@ -54,10 +50,6 @@ #include <linux/videodev2.h> -MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr"); -MODULE_DESCRIPTION("misc helper functions for v4l2 device drivers"); -MODULE_LICENSE("GPL"); - /* * * V 4 L 2 D R I V E R H E L P E R A P I @@ -95,212 +87,6 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 _min, s32 _max, s32 _ } EXPORT_SYMBOL(v4l2_ctrl_query_fill); -/* I2C Helper functions */ - -#if IS_ENABLED(CONFIG_I2C) - -void v4l2_i2c_subdev_set_name(struct v4l2_subdev *sd, struct i2c_client *client, - const char *devname, const char *postfix) -{ - if (!devname) - devname = client->dev.driver->name; - if (!postfix) - postfix = ""; - - snprintf(sd->name, sizeof(sd->name), "%s%s %d-%04x", devname, postfix, - i2c_adapter_id(client->adapter), client->addr); -} -EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_set_name); - -void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, - const struct v4l2_subdev_ops *ops) -{ - v4l2_subdev_init(sd, ops); - sd->flags |= V4L2_SUBDEV_FL_IS_I2C; - /* the owner is the same as the i2c_client's driver owner */ - sd->owner = client->dev.driver->owner; - sd->dev = &client->dev; - /* i2c_client and v4l2_subdev point to one another */ - v4l2_set_subdevdata(sd, client); - i2c_set_clientdata(client, sd); - v4l2_i2c_subdev_set_name(sd, client, NULL, NULL); -} -EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init); - -/* Load an i2c sub-device. */ -struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, struct i2c_board_info *info, - const unsigned short *probe_addrs) -{ - struct v4l2_subdev *sd = NULL; - struct i2c_client *client; - - BUG_ON(!v4l2_dev); - - request_module(I2C_MODULE_PREFIX "%s", info->type); - - /* Create the i2c client */ - if (info->addr == 0 && probe_addrs) - client = i2c_new_probed_device(adapter, info, probe_addrs, - NULL); - else - client = i2c_new_device(adapter, info); - - /* Note: by loading the module first we are certain that c->driver - will be set if the driver was found. If the module was not loaded - first, then the i2c core tries to delay-load the module for us, - and then c->driver is still NULL until the module is finally - loaded. This delay-load mechanism doesn't work if other drivers - want to use the i2c device, so explicitly loading the module - is the best alternative. */ - if (client == NULL || client->dev.driver == NULL) - goto error; - - /* Lock the module so we can safely get the v4l2_subdev pointer */ - if (!try_module_get(client->dev.driver->owner)) - goto error; - sd = i2c_get_clientdata(client); - - /* Register with the v4l2_device which increases the module's - use count as well. */ - if (v4l2_device_register_subdev(v4l2_dev, sd)) - sd = NULL; - /* Decrease the module use count to match the first try_module_get. */ - module_put(client->dev.driver->owner); - -error: - /* If we have a client but no subdev, then something went wrong and - we must unregister the client. */ - if (client && sd == NULL) - i2c_unregister_device(client); - return sd; -} -EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board); - -struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, const char *client_type, - u8 addr, const unsigned short *probe_addrs) -{ - struct i2c_board_info info; - - /* Setup the i2c board info with the device type and - the device address. */ - memset(&info, 0, sizeof(info)); - strscpy(info.type, client_type, sizeof(info.type)); - info.addr = addr; - - return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs); -} -EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev); - -/* Return i2c client address of v4l2_subdev. */ -unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return client ? client->addr : I2C_CLIENT_END; -} -EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr); - -/* Return a list of I2C tuner addresses to probe. Use only if the tuner - addresses are unknown. */ -const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) -{ - static const unsigned short radio_addrs[] = { -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5761) - 0x10, -#endif - 0x60, - I2C_CLIENT_END - }; - static const unsigned short demod_addrs[] = { - 0x42, 0x43, 0x4a, 0x4b, - I2C_CLIENT_END - }; - static const unsigned short tv_addrs[] = { - 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ - 0x60, 0x61, 0x62, 0x63, 0x64, - I2C_CLIENT_END - }; - - switch (type) { - case ADDRS_RADIO: - return radio_addrs; - case ADDRS_DEMOD: - return demod_addrs; - case ADDRS_TV: - return tv_addrs; - case ADDRS_TV_WITH_DEMOD: - return tv_addrs + 4; - } - return NULL; -} -EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs); - -#endif /* defined(CONFIG_I2C) */ - -#if defined(CONFIG_SPI) - -/* Load an spi sub-device. */ - -void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi, - const struct v4l2_subdev_ops *ops) -{ - v4l2_subdev_init(sd, ops); - sd->flags |= V4L2_SUBDEV_FL_IS_SPI; - /* the owner is the same as the spi_device's driver owner */ - sd->owner = spi->dev.driver->owner; - sd->dev = &spi->dev; - /* spi_device and v4l2_subdev point to one another */ - v4l2_set_subdevdata(sd, spi); - spi_set_drvdata(spi, sd); - /* initialize name */ - snprintf(sd->name, sizeof(sd->name), "%s %s", - spi->dev.driver->name, dev_name(&spi->dev)); -} -EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init); - -struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, - struct spi_master *master, struct spi_board_info *info) -{ - struct v4l2_subdev *sd = NULL; - struct spi_device *spi = NULL; - - BUG_ON(!v4l2_dev); - - if (info->modalias[0]) - request_module(info->modalias); - - spi = spi_new_device(master, info); - - if (spi == NULL || spi->dev.driver == NULL) - goto error; - - if (!try_module_get(spi->dev.driver->owner)) - goto error; - - sd = spi_get_drvdata(spi); - - /* Register with the v4l2_device which increases the module's - use count as well. */ - if (v4l2_device_register_subdev(v4l2_dev, sd)) - sd = NULL; - - /* Decrease the module use count to match the first try_module_get. */ - module_put(spi->dev.driver->owner); - -error: - /* If we have a client but no subdev, then something went wrong and - we must unregister the client. */ - if (!sd) - spi_unregister_device(spi); - - return sd; -} -EXPORT_SYMBOL_GPL(v4l2_spi_new_subdev); - -#endif /* defined(CONFIG_SPI) */ - /* Clamp x to be between min and max, aligned to a multiple of 2^align. min * and max don't have to be aligned, but there must be at least one valid * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples @@ -455,11 +241,15 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) { .format = V4L2_PIX_FMT_HSV24, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_BGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_XBGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGRX32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_RGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_XRGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGBX32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_HSV32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_ARGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGBA32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_ABGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGRA32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_GREY, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, /* YUV packed formats */ diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 371537dd8cd3..1d8f38824631 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -6,6 +6,8 @@ */ +#define pr_fmt(fmt) "v4l2-ctrls: " fmt + #include <linux/ctype.h> #include <linux/mm.h> #include <linux/slab.h> @@ -16,6 +18,12 @@ #include <media/v4l2-event.h> #include <media/v4l2-dev.h> +#define dprintk(vdev, fmt, arg...) do { \ + if (!WARN_ON(!(vdev)) && ((vdev)->dev_debug & V4L2_DEV_DEBUG_CTRL)) \ + printk(KERN_DEBUG pr_fmt("%s: %s: " fmt), \ + __func__, video_device_node_name(vdev), ##arg); \ +} while (0) + #define has_op(master, op) \ (master->ops && master->ops->op) #define call_op(master, op) \ @@ -394,6 +402,16 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Explicit", NULL, }; + static const char * const h264_decode_mode[] = { + "Slice-Based", + "Frame-Based", + NULL, + }; + static const char * const h264_start_code[] = { + "No Start Code", + "Annex B Start Code", + NULL, + }; static const char * const mpeg_mpeg2_level[] = { "Low", "Main", @@ -625,6 +643,10 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return h264_fp_arrangement_type; case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: return h264_fmo_map_type; + case V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE: + return h264_decode_mode; + case V4L2_CID_MPEG_VIDEO_H264_START_CODE: + return h264_start_code; case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return mpeg_mpeg2_level; case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: @@ -844,6 +866,8 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX: return "H264 Scaling Matrix"; case V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS: return "H264 Slice Parameters"; case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: return "H264 Decode Parameters"; + case V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE: return "H264 Decode Mode"; + case V4L2_CID_MPEG_VIDEO_H264_START_CODE: return "H264 Start Code"; case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level"; case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; @@ -885,6 +909,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: return "VPX P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: return "VP8 Profile"; case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: return "VP9 Profile"; + case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: return "VP8 Frame Header"; /* HEVC controls */ case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value"; @@ -1211,6 +1236,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: + case V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE: + case V4L2_CID_MPEG_VIDEO_H264_START_CODE: case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: @@ -1345,6 +1372,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS; break; + case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: + *type = V4L2_CTRL_TYPE_VP8_FRAME_HEADER; + break; default: *type = V4L2_CTRL_TYPE_INTEGER; break; @@ -1629,10 +1659,105 @@ static void std_log(const struct v4l2_ctrl *ctrl) }) /* Validate a new control */ + +#define zero_padding(s) \ + memset(&(s).padding, 0, sizeof((s).padding)) + +/* + * Compound controls validation requires setting unused fields/flags to zero + * in order to properly detect unchanged controls with std_equal's memcmp. + */ +static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr) +{ + struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; + void *p = ptr.p + idx * ctrl->elem_size; + + switch ((u32)ctrl->type) { + case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: + p_mpeg2_slice_params = p; + + switch (p_mpeg2_slice_params->sequence.chroma_format) { + case 1: /* 4:2:0 */ + case 2: /* 4:2:2 */ + case 3: /* 4:4:4 */ + break; + default: + return -EINVAL; + } + + switch (p_mpeg2_slice_params->picture.intra_dc_precision) { + case 0: /* 8 bits */ + case 1: /* 9 bits */ + case 2: /* 10 bits */ + case 3: /* 11 bits */ + break; + default: + return -EINVAL; + } + + switch (p_mpeg2_slice_params->picture.picture_structure) { + case 1: /* interlaced top field */ + case 2: /* interlaced bottom field */ + case 3: /* progressive */ + break; + default: + return -EINVAL; + } + + switch (p_mpeg2_slice_params->picture.picture_coding_type) { + case V4L2_MPEG2_PICTURE_CODING_TYPE_I: + case V4L2_MPEG2_PICTURE_CODING_TYPE_P: + case V4L2_MPEG2_PICTURE_CODING_TYPE_B: + break; + default: + return -EINVAL; + } + + break; + + case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION: + break; + + case V4L2_CTRL_TYPE_FWHT_PARAMS: + break; + + case V4L2_CTRL_TYPE_H264_SPS: + case V4L2_CTRL_TYPE_H264_PPS: + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + break; + + case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: + p_vp8_frame_header = p; + + switch (p_vp8_frame_header->num_dct_parts) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + zero_padding(p_vp8_frame_header->segment_header); + zero_padding(p_vp8_frame_header->lf_header); + zero_padding(p_vp8_frame_header->quant_header); + zero_padding(p_vp8_frame_header->entropy_header); + zero_padding(p_vp8_frame_header->coder_state); + break; + default: + return -EINVAL; + } + + return 0; +} + static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr) { - struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; size_t len; u64 offset; s64 val; @@ -1695,63 +1820,8 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, return -ERANGE; return 0; - case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: - p_mpeg2_slice_params = ptr.p; - - switch (p_mpeg2_slice_params->sequence.chroma_format) { - case 1: /* 4:2:0 */ - case 2: /* 4:2:2 */ - case 3: /* 4:4:4 */ - break; - default: - return -EINVAL; - } - - switch (p_mpeg2_slice_params->picture.intra_dc_precision) { - case 0: /* 8 bits */ - case 1: /* 9 bits */ - case 2: /* 10 bits */ - case 3: /* 11 bits */ - break; - default: - return -EINVAL; - } - - switch (p_mpeg2_slice_params->picture.picture_structure) { - case 1: /* interlaced top field */ - case 2: /* interlaced bottom field */ - case 3: /* progressive */ - break; - default: - return -EINVAL; - } - - switch (p_mpeg2_slice_params->picture.picture_coding_type) { - case V4L2_MPEG2_PICTURE_CODING_TYPE_I: - case V4L2_MPEG2_PICTURE_CODING_TYPE_P: - case V4L2_MPEG2_PICTURE_CODING_TYPE_B: - break; - default: - return -EINVAL; - } - - return 0; - - case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION: - return 0; - - case V4L2_CTRL_TYPE_FWHT_PARAMS: - return 0; - - case V4L2_CTRL_TYPE_H264_SPS: - case V4L2_CTRL_TYPE_H264_PPS: - case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: - case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: - case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: - return 0; - default: - return -EINVAL; + return std_validate_compound(ctrl, idx, ptr); } } @@ -2348,6 +2418,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: elem_size = sizeof(struct v4l2_ctrl_h264_decode_params); break; + case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: + elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header); + break; default: if (type < V4L2_CTRL_COMPOUND_TYPES) elem_size = sizeof(s32); @@ -3217,6 +3290,7 @@ static int v4l2_ctrl_request_bind(struct media_request *req, static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs, struct v4l2_ctrl_helper *helpers, + struct video_device *vdev, bool get) { struct v4l2_ctrl_helper *h; @@ -3234,20 +3308,31 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, if (cs->which && cs->which != V4L2_CTRL_WHICH_DEF_VAL && cs->which != V4L2_CTRL_WHICH_REQUEST_VAL && - V4L2_CTRL_ID2WHICH(id) != cs->which) + V4L2_CTRL_ID2WHICH(id) != cs->which) { + dprintk(vdev, + "invalid which 0x%x or control id 0x%x\n", + cs->which, id); return -EINVAL; + } /* Old-style private controls are not allowed for extended controls */ - if (id >= V4L2_CID_PRIVATE_BASE) + if (id >= V4L2_CID_PRIVATE_BASE) { + dprintk(vdev, + "old-style private controls not allowed\n"); return -EINVAL; + } ref = find_ref_lock(hdl, id); - if (ref == NULL) + if (ref == NULL) { + dprintk(vdev, "cannot find control id 0x%x\n", id); return -EINVAL; + } h->ref = ref; ctrl = ref->ctrl; - if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) + if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) { + dprintk(vdev, "control id 0x%x is disabled\n", id); return -EINVAL; + } if (ctrl->cluster[0]->ncontrols > 1) have_clusters = true; @@ -3257,10 +3342,17 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, unsigned tot_size = ctrl->elems * ctrl->elem_size; if (c->size < tot_size) { + /* + * In the get case the application first + * queries to obtain the size of the control. + */ if (get) { c->size = tot_size; return -ENOSPC; } + dprintk(vdev, + "pointer control id 0x%x size too small, %d bytes but %d bytes needed\n", + id, c->size, tot_size); return -EFAULT; } c->size = tot_size; @@ -3321,7 +3413,8 @@ static int class_check(struct v4l2_ctrl_handler *hdl, u32 which) /* Get extended controls. Allocates the helpers array if needed. */ static int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, - struct v4l2_ext_controls *cs) + struct v4l2_ext_controls *cs, + struct video_device *vdev) { struct v4l2_ctrl_helper helper[4]; struct v4l2_ctrl_helper *helpers = helper; @@ -3347,7 +3440,7 @@ static int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, return -ENOMEM; } - ret = prepare_ext_ctrls(hdl, cs, helpers, true); + ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, true); cs->error_idx = cs->count; for (i = 0; !ret && i < cs->count; i++) @@ -3440,8 +3533,8 @@ v4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl, return obj; } -int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct media_device *mdev, - struct v4l2_ext_controls *cs) +int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev, + struct media_device *mdev, struct v4l2_ext_controls *cs) { struct media_request_object *obj = NULL; struct media_request *req = NULL; @@ -3477,7 +3570,7 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct media_device *mdev, req_obj); } - ret = v4l2_g_ext_ctrls_common(hdl, cs); + ret = v4l2_g_ext_ctrls_common(hdl, cs, vdev); if (obj) { media_request_unlock_for_access(req); @@ -3620,7 +3713,9 @@ static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master, /* Validate controls. */ static int validate_ctrls(struct v4l2_ext_controls *cs, - struct v4l2_ctrl_helper *helpers, bool set) + struct v4l2_ctrl_helper *helpers, + struct video_device *vdev, + bool set) { unsigned i; int ret = 0; @@ -3632,16 +3727,24 @@ static int validate_ctrls(struct v4l2_ext_controls *cs, cs->error_idx = i; - if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) + if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) { + dprintk(vdev, + "control id 0x%x is read-only\n", + ctrl->id); return -EACCES; + } /* This test is also done in try_set_control_cluster() which is called in atomic context, so that has the final say, but it makes sense to do an up-front check as well. Once an error occurs in try_set_control_cluster() some other controls may have been set already and we want to do a best-effort to avoid that. */ - if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) + if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) { + dprintk(vdev, + "control id 0x%x is grabbed, cannot set\n", + ctrl->id); return -EBUSY; + } /* * Skip validation for now if the payload needs to be copied * from userspace into kernelspace. We'll validate those later. @@ -3676,7 +3779,8 @@ static void update_from_auto_cluster(struct v4l2_ctrl *master) /* Try or try-and-set controls */ static int try_set_ext_ctrls_common(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, - struct v4l2_ext_controls *cs, bool set) + struct v4l2_ext_controls *cs, + struct video_device *vdev, bool set) { struct v4l2_ctrl_helper helper[4]; struct v4l2_ctrl_helper *helpers = helper; @@ -3686,13 +3790,19 @@ static int try_set_ext_ctrls_common(struct v4l2_fh *fh, cs->error_idx = cs->count; /* Default value cannot be changed */ - if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) + if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) { + dprintk(vdev, "%s: cannot change default value\n", + video_device_node_name(vdev)); return -EINVAL; + } cs->which = V4L2_CTRL_ID2WHICH(cs->which); - if (hdl == NULL) + if (hdl == NULL) { + dprintk(vdev, "%s: invalid null control handler\n", + video_device_node_name(vdev)); return -EINVAL; + } if (cs->count == 0) return class_check(hdl, cs->which); @@ -3703,9 +3813,9 @@ static int try_set_ext_ctrls_common(struct v4l2_fh *fh, if (!helpers) return -ENOMEM; } - ret = prepare_ext_ctrls(hdl, cs, helpers, false); + ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, false); if (!ret) - ret = validate_ctrls(cs, helpers, set); + ret = validate_ctrls(cs, helpers, vdev, set); if (ret && set) cs->error_idx = cs->count; for (i = 0; !ret && i < cs->count; i++) { @@ -3790,7 +3900,9 @@ static int try_set_ext_ctrls_common(struct v4l2_fh *fh, } static int try_set_ext_ctrls(struct v4l2_fh *fh, - struct v4l2_ctrl_handler *hdl, struct media_device *mdev, + struct v4l2_ctrl_handler *hdl, + struct video_device *vdev, + struct media_device *mdev, struct v4l2_ext_controls *cs, bool set) { struct media_request_object *obj = NULL; @@ -3798,21 +3910,39 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, int ret; if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL) { - if (!mdev || cs->request_fd < 0) + if (!mdev) { + dprintk(vdev, "%s: missing media device\n", + video_device_node_name(vdev)); return -EINVAL; + } + + if (cs->request_fd < 0) { + dprintk(vdev, "%s: invalid request fd %d\n", + video_device_node_name(vdev), cs->request_fd); + return -EINVAL; + } req = media_request_get_by_fd(mdev, cs->request_fd); - if (IS_ERR(req)) + if (IS_ERR(req)) { + dprintk(vdev, "%s: cannot find request fd %d\n", + video_device_node_name(vdev), cs->request_fd); return PTR_ERR(req); + } ret = media_request_lock_for_update(req); if (ret) { + dprintk(vdev, "%s: cannot lock request fd %d\n", + video_device_node_name(vdev), cs->request_fd); media_request_put(req); return ret; } obj = v4l2_ctrls_find_req_obj(hdl, req, set); if (IS_ERR(obj)) { + dprintk(vdev, + "%s: cannot find request object for request fd %d\n", + video_device_node_name(vdev), + cs->request_fd); media_request_unlock_for_update(req); media_request_put(req); return PTR_ERR(obj); @@ -3821,7 +3951,11 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, req_obj); } - ret = try_set_ext_ctrls_common(fh, hdl, cs, set); + ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set); + if (ret) + dprintk(vdev, + "%s: try_set_ext_ctrls_common failed (%d)\n", + video_device_node_name(vdev), ret); if (obj) { media_request_unlock_for_update(req); @@ -3832,17 +3966,22 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, return ret; } -int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct media_device *mdev, +int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, + struct video_device *vdev, + struct media_device *mdev, struct v4l2_ext_controls *cs) { - return try_set_ext_ctrls(NULL, hdl, mdev, cs, false); + return try_set_ext_ctrls(NULL, hdl, vdev, mdev, cs, false); } EXPORT_SYMBOL(v4l2_try_ext_ctrls); -int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, - struct media_device *mdev, struct v4l2_ext_controls *cs) +int v4l2_s_ext_ctrls(struct v4l2_fh *fh, + struct v4l2_ctrl_handler *hdl, + struct video_device *vdev, + struct media_device *mdev, + struct v4l2_ext_controls *cs) { - return try_set_ext_ctrls(fh, hdl, mdev, cs, true); + return try_set_ext_ctrls(fh, hdl, vdev, mdev, cs, true); } EXPORT_SYMBOL(v4l2_s_ext_ctrls); diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index cbb74f748555..4037689a945a 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -859,6 +859,9 @@ int __video_register_device(struct video_device *vdev, /* the v4l2_dev pointer MUST be present */ if (WARN_ON(!vdev->v4l2_dev)) return -EINVAL; + /* the device_caps field MUST be set for all but subdevs */ + if (WARN_ON(type != VFL_TYPE_SUBDEV && !vdev->device_caps)) + return -EINVAL; /* v4l2_fh support */ spin_lock_init(&vdev->fh_lock); @@ -1089,7 +1092,7 @@ static void __exit videodev_exit(void) subsys_initcall(videodev_init); module_exit(videodev_exit) -MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@kernel.org>"); -MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); +MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@kernel.org>, Bill Dirks, Justin Schoeman, Gerd Knorr"); +MODULE_DESCRIPTION("Video4Linux2 core driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR); diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index aa277f5bc862..63d6b147b21e 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -9,11 +9,7 @@ #include <linux/types.h> #include <linux/ioctl.h> #include <linux/module.h> -#include <linux/i2c.h> #include <linux/slab.h> -#if defined(CONFIG_SPI) -#include <linux/spi/spi.h> -#endif #include <linux/videodev2.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> @@ -102,37 +98,10 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) /* Unregister subdevs */ list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) { v4l2_device_unregister_subdev(sd); -#if IS_ENABLED(CONFIG_I2C) - if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* - * We need to unregister the i2c client - * explicitly. We cannot rely on - * i2c_del_adapter to always unregister - * clients for us, since if the i2c bus is a - * platform bus, then it is never deleted. - * - * Device tree or ACPI based devices must not - * be unregistered as they have not been - * registered by us, and would not be - * re-created by just probing the V4L2 driver. - */ - if (client && - !client->dev.of_node && !client->dev.fwnode) - i2c_unregister_device(client); - continue; - } -#endif -#if defined(CONFIG_SPI) - if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) { - struct spi_device *spi = v4l2_get_subdevdata(sd); - - if (spi && !spi->dev.of_node && !spi->dev.fwnode) - spi_unregister_device(spi); - continue; - } -#endif + if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) + v4l2_i2c_subdev_unregister(sd); + else if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) + v4l2_spi_subdev_unregister(sd); } /* Mark as unregistered, thus preventing duplicate unregistrations */ v4l2_dev->name[0] = '\0'; diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 7e740d332a54..3bd1888787eb 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -163,7 +163,7 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, pr_debug("no lane mapping given, using defaults\n"); } - rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0); + rval = fwnode_property_count_u32(fwnode, "data-lanes"); if (rval > 0) { num_data_lanes = min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval); @@ -191,8 +191,7 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, pr_debug("lane %u position %u\n", i, array[i]); } - rval = fwnode_property_read_u32_array(fwnode, "lane-polarities", NULL, - 0); + rval = fwnode_property_count_u32(fwnode, "lane-polarities"); if (rval > 0) { if (rval != 1 + num_data_lanes /* clock+data */) { pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n", @@ -525,8 +524,7 @@ int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode, if (rval < 0) return rval; - rval = fwnode_property_read_u64_array(fwnode, "link-frequencies", - NULL, 0); + rval = fwnode_property_count_u64(fwnode, "link-frequencies"); if (rval > 0) { unsigned int i; @@ -777,23 +775,17 @@ static int v4l2_fwnode_reference_parse(struct device *dev, asd = v4l2_async_notifier_add_fwnode_subdev(notifier, args.fwnode, sizeof(*asd)); + fwnode_handle_put(args.fwnode); if (IS_ERR(asd)) { - ret = PTR_ERR(asd); /* not an error if asd already exists */ - if (ret == -EEXIST) { - fwnode_handle_put(args.fwnode); + if (PTR_ERR(asd) == -EEXIST) continue; - } - goto error; + return PTR_ERR(asd); } } return 0; - -error: - fwnode_handle_put(args.fwnode); - return ret; } /* @@ -1083,23 +1075,18 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev, asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode, sizeof(*asd)); + fwnode_handle_put(fwnode); if (IS_ERR(asd)) { ret = PTR_ERR(asd); /* not an error if asd already exists */ - if (ret == -EEXIST) { - fwnode_handle_put(fwnode); + if (ret == -EEXIST) continue; - } - goto error; + return PTR_ERR(asd); } } return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode); - -error: - fwnode_handle_put(fwnode); - return ret; } int v4l2_async_notifier_parse_fwnode_sensor_common(struct device *dev, diff --git a/drivers/media/v4l2-core/v4l2-i2c.c b/drivers/media/v4l2-core/v4l2-i2c.c new file mode 100644 index 000000000000..5bf99e7c0c09 --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-i2c.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * v4l2-i2c - I2C helpers for Video4Linux2 + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <media/v4l2-common.h> +#include <media/v4l2-device.h> + +void v4l2_i2c_subdev_unregister(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + /* + * We need to unregister the i2c client + * explicitly. We cannot rely on + * i2c_del_adapter to always unregister + * clients for us, since if the i2c bus is a + * platform bus, then it is never deleted. + * + * Device tree or ACPI based devices must not + * be unregistered as they have not been + * registered by us, and would not be + * re-created by just probing the V4L2 driver. + */ + if (client && !client->dev.of_node && !client->dev.fwnode) + i2c_unregister_device(client); +} + +void v4l2_i2c_subdev_set_name(struct v4l2_subdev *sd, + struct i2c_client *client, + const char *devname, const char *postfix) +{ + if (!devname) + devname = client->dev.driver->name; + if (!postfix) + postfix = ""; + + snprintf(sd->name, sizeof(sd->name), "%s%s %d-%04x", devname, postfix, + i2c_adapter_id(client->adapter), client->addr); +} +EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_set_name); + +void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, + const struct v4l2_subdev_ops *ops) +{ + v4l2_subdev_init(sd, ops); + sd->flags |= V4L2_SUBDEV_FL_IS_I2C; + /* the owner is the same as the i2c_client's driver owner */ + sd->owner = client->dev.driver->owner; + sd->dev = &client->dev; + /* i2c_client and v4l2_subdev point to one another */ + v4l2_set_subdevdata(sd, client); + i2c_set_clientdata(client, sd); + v4l2_i2c_subdev_set_name(sd, client, NULL, NULL); +} +EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init); + +/* Load an i2c sub-device. */ +struct v4l2_subdev +*v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, + struct i2c_adapter *adapter, + struct i2c_board_info *info, + const unsigned short *probe_addrs) +{ + struct v4l2_subdev *sd = NULL; + struct i2c_client *client; + + if (!v4l2_dev) + return NULL; + + request_module(I2C_MODULE_PREFIX "%s", info->type); + + /* Create the i2c client */ + if (info->addr == 0 && probe_addrs) + client = i2c_new_probed_device(adapter, info, probe_addrs, + NULL); + else + client = i2c_new_device(adapter, info); + + /* + * Note: by loading the module first we are certain that c->driver + * will be set if the driver was found. If the module was not loaded + * first, then the i2c core tries to delay-load the module for us, + * and then c->driver is still NULL until the module is finally + * loaded. This delay-load mechanism doesn't work if other drivers + * want to use the i2c device, so explicitly loading the module + * is the best alternative. + */ + if (!client || !client->dev.driver) + goto error; + + /* Lock the module so we can safely get the v4l2_subdev pointer */ + if (!try_module_get(client->dev.driver->owner)) + goto error; + sd = i2c_get_clientdata(client); + + /* + * Register with the v4l2_device which increases the module's + * use count as well. + */ + if (v4l2_device_register_subdev(v4l2_dev, sd)) + sd = NULL; + /* Decrease the module use count to match the first try_module_get. */ + module_put(client->dev.driver->owner); + +error: + /* + * If we have a client but no subdev, then something went wrong and + * we must unregister the client. + */ + if (client && !sd) + i2c_unregister_device(client); + return sd; +} +EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board); + +struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, + struct i2c_adapter *adapter, + const char *client_type, + u8 addr, + const unsigned short *probe_addrs) +{ + struct i2c_board_info info; + + /* + * Setup the i2c board info with the device type and + * the device address. + */ + memset(&info, 0, sizeof(info)); + strscpy(info.type, client_type, sizeof(info.type)); + info.addr = addr; + + return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, + probe_addrs); +} +EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev); + +/* Return i2c client address of v4l2_subdev. */ +unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return client ? client->addr : I2C_CLIENT_END; +} +EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr); + +/* + * Return a list of I2C tuner addresses to probe. Use only if the tuner + * addresses are unknown. + */ +const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) +{ + static const unsigned short radio_addrs[] = { +#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5761) + 0x10, +#endif + 0x60, + I2C_CLIENT_END + }; + static const unsigned short demod_addrs[] = { + 0x42, 0x43, 0x4a, 0x4b, + I2C_CLIENT_END + }; + static const unsigned short tv_addrs[] = { + 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ + 0x60, 0x61, 0x62, 0x63, 0x64, + I2C_CLIENT_END + }; + + switch (type) { + case ADDRS_RADIO: + return radio_addrs; + case ADDRS_DEMOD: + return demod_addrs; + case ADDRS_TV: + return tv_addrs; + case ADDRS_TV_WITH_DEMOD: + return tv_addrs + 4; + } + return NULL; +} +EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index b1f4b991dba6..51b912743f0f 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1057,14 +1057,19 @@ static int v4l_querycap(const struct v4l2_ioctl_ops *ops, ret = ops->vidioc_querycap(file, fh, cap); - cap->capabilities |= V4L2_CAP_EXT_PIX_FORMAT; /* - * Drivers MUST fill in device_caps, so check for this and - * warn if it was forgotten. + * Drivers must not change device_caps, so check for this and + * warn if this happened. + */ + WARN_ON(cap->device_caps != vfd->device_caps); + /* + * Check that capabilities is a superset of + * vfd->device_caps | V4L2_CAP_DEVICE_CAPS */ - WARN(!(cap->capabilities & V4L2_CAP_DEVICE_CAPS) || - !cap->device_caps, "Bad caps for driver %s, %x %x", - cap->driver, cap->capabilities, cap->device_caps); + WARN_ON((cap->capabilities & + (vfd->device_caps | V4L2_CAP_DEVICE_CAPS)) != + (vfd->device_caps | V4L2_CAP_DEVICE_CAPS)); + cap->capabilities |= V4L2_CAP_EXT_PIX_FORMAT; cap->device_caps |= V4L2_CAP_EXT_PIX_FORMAT; return ret; @@ -1169,9 +1174,21 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_RGB444: descr = "16-bit A/XRGB 4-4-4-4"; break; case V4L2_PIX_FMT_ARGB444: descr = "16-bit ARGB 4-4-4-4"; break; case V4L2_PIX_FMT_XRGB444: descr = "16-bit XRGB 4-4-4-4"; break; + case V4L2_PIX_FMT_RGBA444: descr = "16-bit RGBA 4-4-4-4"; break; + case V4L2_PIX_FMT_RGBX444: descr = "16-bit RGBX 4-4-4-4"; break; + case V4L2_PIX_FMT_ABGR444: descr = "16-bit ABGR 4-4-4-4"; break; + case V4L2_PIX_FMT_XBGR444: descr = "16-bit XBGR 4-4-4-4"; break; + case V4L2_PIX_FMT_BGRA444: descr = "16-bit BGRA 4-4-4-4"; break; + case V4L2_PIX_FMT_BGRX444: descr = "16-bit BGRX 4-4-4-4"; break; case V4L2_PIX_FMT_RGB555: descr = "16-bit A/XRGB 1-5-5-5"; break; case V4L2_PIX_FMT_ARGB555: descr = "16-bit ARGB 1-5-5-5"; break; case V4L2_PIX_FMT_XRGB555: descr = "16-bit XRGB 1-5-5-5"; break; + case V4L2_PIX_FMT_ABGR555: descr = "16-bit ABGR 1-5-5-5"; break; + case V4L2_PIX_FMT_XBGR555: descr = "16-bit XBGR 1-5-5-5"; break; + case V4L2_PIX_FMT_RGBA555: descr = "16-bit RGBA 5-5-5-1"; break; + case V4L2_PIX_FMT_RGBX555: descr = "16-bit RGBX 5-5-5-1"; break; + case V4L2_PIX_FMT_BGRA555: descr = "16-bit BGRA 5-5-5-1"; break; + case V4L2_PIX_FMT_BGRX555: descr = "16-bit BGRX 5-5-5-1"; break; case V4L2_PIX_FMT_RGB565: descr = "16-bit RGB 5-6-5"; break; case V4L2_PIX_FMT_RGB555X: descr = "16-bit A/XRGB 1-5-5-5 BE"; break; case V4L2_PIX_FMT_ARGB555X: descr = "16-bit ARGB 1-5-5-5 BE"; break; @@ -1186,6 +1203,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_RGB32: descr = "32-bit A/XRGB 8-8-8-8"; break; case V4L2_PIX_FMT_ARGB32: descr = "32-bit ARGB 8-8-8-8"; break; case V4L2_PIX_FMT_XRGB32: descr = "32-bit XRGB 8-8-8-8"; break; + case V4L2_PIX_FMT_BGRA32: descr = "32-bit ABGR 8-8-8-8"; break; + case V4L2_PIX_FMT_BGRX32: descr = "32-bit XBGR 8-8-8-8"; break; + case V4L2_PIX_FMT_RGBA32: descr = "32-bit RGBA 8-8-8-8"; break; + case V4L2_PIX_FMT_RGBX32: descr = "32-bit RGBX 8-8-8-8"; break; case V4L2_PIX_FMT_GREY: descr = "8-bit Greyscale"; break; case V4L2_PIX_FMT_Y4: descr = "4-bit Greyscale"; break; case V4L2_PIX_FMT_Y6: descr = "6-bit Greyscale"; break; @@ -1301,13 +1322,14 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_SDR_FMT_PCU16BE: descr = "Planar Complex U16BE"; break; case V4L2_SDR_FMT_PCU18BE: descr = "Planar Complex U18BE"; break; case V4L2_SDR_FMT_PCU20BE: descr = "Planar Complex U20BE"; break; - case V4L2_TCH_FMT_DELTA_TD16: descr = "16-bit signed deltas"; break; - case V4L2_TCH_FMT_DELTA_TD08: descr = "8-bit signed deltas"; break; - case V4L2_TCH_FMT_TU16: descr = "16-bit unsigned touch data"; break; - case V4L2_TCH_FMT_TU08: descr = "8-bit unsigned touch data"; break; + case V4L2_TCH_FMT_DELTA_TD16: descr = "16-bit Signed Deltas"; break; + case V4L2_TCH_FMT_DELTA_TD08: descr = "8-bit Signed Deltas"; break; + case V4L2_TCH_FMT_TU16: descr = "16-bit Unsigned Touch Data"; break; + case V4L2_TCH_FMT_TU08: descr = "8-bit Unsigned Touch Data"; break; case V4L2_META_FMT_VSP1_HGO: descr = "R-Car VSP1 1-D Histogram"; break; case V4L2_META_FMT_VSP1_HGT: descr = "R-Car VSP1 2-D Histogram"; break; - case V4L2_META_FMT_UVC: descr = "UVC payload header metadata"; break; + case V4L2_META_FMT_UVC: descr = "UVC Payload Header Metadata"; break; + case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break; default: /* Compressed formats */ @@ -1321,16 +1343,17 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_H264: descr = "H.264"; break; case V4L2_PIX_FMT_H264_NO_SC: descr = "H.264 (No Start Codes)"; break; case V4L2_PIX_FMT_H264_MVC: descr = "H.264 MVC"; break; - case V4L2_PIX_FMT_H264_SLICE_RAW: descr = "H.264 Parsed Slice Data"; break; + case V4L2_PIX_FMT_H264_SLICE: descr = "H.264 Parsed Slice Data"; break; case V4L2_PIX_FMT_H263: descr = "H.263"; break; case V4L2_PIX_FMT_MPEG1: descr = "MPEG-1 ES"; break; case V4L2_PIX_FMT_MPEG2: descr = "MPEG-2 ES"; break; case V4L2_PIX_FMT_MPEG2_SLICE: descr = "MPEG-2 Parsed Slice Data"; break; - case V4L2_PIX_FMT_MPEG4: descr = "MPEG-4 part 2 ES"; break; + case V4L2_PIX_FMT_MPEG4: descr = "MPEG-4 Part 2 ES"; break; case V4L2_PIX_FMT_XVID: descr = "Xvid"; break; case V4L2_PIX_FMT_VC1_ANNEX_G: descr = "VC-1 (SMPTE 412M Annex G)"; break; case V4L2_PIX_FMT_VC1_ANNEX_L: descr = "VC-1 (SMPTE 412M Annex L)"; break; case V4L2_PIX_FMT_VP8: descr = "VP8"; break; + case V4L2_PIX_FMT_VP8_FRAME: descr = "VP8 Frame"; break; case V4L2_PIX_FMT_VP9: descr = "VP9"; break; case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */ case V4L2_PIX_FMT_FWHT: descr = "FWHT"; break; /* used in vicodec */ @@ -1365,14 +1388,14 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) (char)((fmt->pixelformat >> 8) & 0x7f), (char)((fmt->pixelformat >> 16) & 0x7f), (char)((fmt->pixelformat >> 24) & 0x7f), - (fmt->pixelformat & (1 << 31)) ? "-BE" : ""); + (fmt->pixelformat & (1UL << 31)) ? "-BE" : ""); break; } } if (descr) WARN_ON(strscpy(fmt->description, descr, sz) < 0); - fmt->flags = flags; + fmt->flags |= flags; } static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, @@ -1645,6 +1668,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { struct v4l2_format *p = arg; + struct video_device *vfd = video_devdata(file); int ret = check_fmt(file, p->type); unsigned int i; @@ -1661,6 +1685,8 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + if (vfd->vfl_type == VFL_TYPE_TOUCH) + v4l_pix_format_touch(&p->fmt.pix); return ret; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane)) @@ -2165,9 +2191,11 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops, p->error_idx = p->count; if (vfh && vfh->ctrl_handler) - return v4l2_g_ext_ctrls(vfh->ctrl_handler, vfd->v4l2_dev->mdev, p); + return v4l2_g_ext_ctrls(vfh->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (vfd->ctrl_handler) - return v4l2_g_ext_ctrls(vfd->ctrl_handler, vfd->v4l2_dev->mdev, p); + return v4l2_g_ext_ctrls(vfd->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (ops->vidioc_g_ext_ctrls == NULL) return -ENOTTY; return check_ext_ctrls(p, 0) ? ops->vidioc_g_ext_ctrls(file, fh, p) : @@ -2184,9 +2212,11 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, p->error_idx = p->count; if (vfh && vfh->ctrl_handler) - return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, vfd->v4l2_dev->mdev, p); + return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (vfd->ctrl_handler) - return v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, vfd->v4l2_dev->mdev, p); + return v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (ops->vidioc_s_ext_ctrls == NULL) return -ENOTTY; return check_ext_ctrls(p, 0) ? ops->vidioc_s_ext_ctrls(file, fh, p) : @@ -2203,9 +2233,11 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, p->error_idx = p->count; if (vfh && vfh->ctrl_handler) - return v4l2_try_ext_ctrls(vfh->ctrl_handler, vfd->v4l2_dev->mdev, p); + return v4l2_try_ext_ctrls(vfh->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (vfd->ctrl_handler) - return v4l2_try_ext_ctrls(vfd->ctrl_handler, vfd->v4l2_dev->mdev, p); + return v4l2_try_ext_ctrls(vfd->ctrl_handler, + vfd, vfd->v4l2_dev->mdev, p); if (ops->vidioc_try_ext_ctrls == NULL) return -ENOTTY; return check_ext_ctrls(p, 0) ? ops->vidioc_try_ext_ctrls(file, fh, p) : diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 4f5176702937..19937dd3c6f6 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -603,11 +603,10 @@ int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, } EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff); -__poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct poll_table_struct *wait) +static __poll_t v4l2_m2m_poll_for_data(struct file *file, + struct v4l2_m2m_ctx *m2m_ctx, + struct poll_table_struct *wait) { - struct video_device *vfd = video_devdata(file); - __poll_t req_events = poll_requested_events(wait); struct vb2_queue *src_q, *dst_q; struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; __poll_t rc = 0; @@ -619,16 +618,6 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, poll_wait(file, &src_q->done_wq, wait); poll_wait(file, &dst_q->done_wq, wait); - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { - struct v4l2_fh *fh = file->private_data; - - poll_wait(file, &fh->wait, wait); - if (v4l2_event_pending(fh)) - rc = EPOLLPRI; - if (!(req_events & (EPOLLOUT | EPOLLWRNORM | EPOLLIN | EPOLLRDNORM))) - return rc; - } - /* * There has to be at least one buffer queued on each queued_list, which * means either in driver already or waiting for driver to claim it @@ -637,10 +626,8 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, if ((!src_q->streaming || src_q->error || list_empty(&src_q->queued_list)) && (!dst_q->streaming || dst_q->error || - list_empty(&dst_q->queued_list))) { - rc |= EPOLLERR; - goto end; - } + list_empty(&dst_q->queued_list))) + return EPOLLERR; spin_lock_irqsave(&dst_q->done_lock, flags); if (list_empty(&dst_q->done_list)) { @@ -650,7 +637,7 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, */ if (dst_q->last_buffer_dequeued) { spin_unlock_irqrestore(&dst_q->done_lock, flags); - return rc | EPOLLIN | EPOLLRDNORM; + return EPOLLIN | EPOLLRDNORM; } } spin_unlock_irqrestore(&dst_q->done_lock, flags); @@ -673,7 +660,27 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, rc |= EPOLLIN | EPOLLRDNORM; spin_unlock_irqrestore(&dst_q->done_lock, flags); -end: + return rc; +} + +__poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + struct poll_table_struct *wait) +{ + struct video_device *vfd = video_devdata(file); + __poll_t req_events = poll_requested_events(wait); + __poll_t rc = 0; + + if (req_events & (EPOLLOUT | EPOLLWRNORM | EPOLLIN | EPOLLRDNORM)) + rc = v4l2_m2m_poll_for_data(file, m2m_ctx, wait); + + if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { + struct v4l2_fh *fh = file->private_data; + + poll_wait(file, &fh->wait, wait); + if (v4l2_event_pending(fh)) + rc |= EPOLLPRI; + } + return rc; } EXPORT_SYMBOL_GPL(v4l2_m2m_poll); diff --git a/drivers/media/v4l2-core/v4l2-spi.c b/drivers/media/v4l2-core/v4l2-spi.c new file mode 100644 index 000000000000..eadecdff7349 --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-spi.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * v4l2-spi - SPI helpers for Video4Linux2 + */ + +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <media/v4l2-common.h> +#include <media/v4l2-device.h> + +void v4l2_spi_subdev_unregister(struct v4l2_subdev *sd) +{ + struct spi_device *spi = v4l2_get_subdevdata(sd); + + if (spi && !spi->dev.of_node && !spi->dev.fwnode) + spi_unregister_device(spi); +} + +void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi, + const struct v4l2_subdev_ops *ops) +{ + v4l2_subdev_init(sd, ops); + sd->flags |= V4L2_SUBDEV_FL_IS_SPI; + /* the owner is the same as the spi_device's driver owner */ + sd->owner = spi->dev.driver->owner; + sd->dev = &spi->dev; + /* spi_device and v4l2_subdev point to one another */ + v4l2_set_subdevdata(sd, spi); + spi_set_drvdata(spi, sd); + /* initialize name */ + snprintf(sd->name, sizeof(sd->name), "%s %s", + spi->dev.driver->name, dev_name(&spi->dev)); +} +EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init); + +struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, + struct spi_master *master, + struct spi_board_info *info) +{ + struct v4l2_subdev *sd = NULL; + struct spi_device *spi = NULL; + + if (!v4l2_dev) + return NULL; + if (info->modalias[0]) + request_module(info->modalias); + + spi = spi_new_device(master, info); + + if (!spi || !spi->dev.driver) + goto error; + + if (!try_module_get(spi->dev.driver->owner)) + goto error; + + sd = spi_get_drvdata(spi); + + /* + * Register with the v4l2_device which increases the module's + * use count as well. + */ + if (v4l2_device_register_subdev(v4l2_dev, sd)) + sd = NULL; + + /* Decrease the module use count to match the first try_module_get. */ + module_put(spi->dev.driver->owner); + +error: + /* + * If we have a client but no subdev, then something went wrong and + * we must unregister the client. + */ + if (!sd) + spi_unregister_device(spi); + + return sd; +} +EXPORT_SYMBOL_GPL(v4l2_spi_new_subdev); diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 25c73c13cc7e..f725cd9b66b9 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -372,19 +372,19 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (!vfh->ctrl_handler) return -ENOTTY; return v4l2_g_ext_ctrls(vfh->ctrl_handler, - sd->v4l2_dev->mdev, arg); + vdev, sd->v4l2_dev->mdev, arg); case VIDIOC_S_EXT_CTRLS: if (!vfh->ctrl_handler) return -ENOTTY; return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, - sd->v4l2_dev->mdev, arg); + vdev, sd->v4l2_dev->mdev, arg); case VIDIOC_TRY_EXT_CTRLS: if (!vfh->ctrl_handler) return -ENOTTY; return v4l2_try_ext_ctrls(vfh->ctrl_handler, - sd->v4l2_dev->mdev, arg); + vdev, sd->v4l2_dev->mdev, arg); case VIDIOC_DQEVENT: if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c index 7ef3e4d22bf6..939fc11cf080 100644 --- a/drivers/media/v4l2-core/videobuf-core.c +++ b/drivers/media/v4l2-core/videobuf-core.c @@ -1123,7 +1123,6 @@ __poll_t videobuf_poll_stream(struct file *file, struct videobuf_buffer *buf = NULL; __poll_t rc = 0; - poll_wait(file, &buf->done, wait); videobuf_queue_lock(q); if (q->streaming) { if (!list_empty(&q->stream)) @@ -1143,7 +1142,9 @@ __poll_t videobuf_poll_stream(struct file *file, } buf = q->read_buf; } - if (!buf) + if (buf) + poll_wait(file, &buf->done, wait); + else rc = EPOLLERR; if (0 == rc) { diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 534d85d6c5e3..642adc4c24d2 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -22,10 +22,6 @@ if STAGING_MEDIA && MEDIA_SUPPORT # Please keep them in alphabetic order source "drivers/staging/media/allegro-dvt/Kconfig" -source "drivers/staging/media/bcm2048/Kconfig" - -source "drivers/staging/media/davinci_vpfe/Kconfig" - source "drivers/staging/media/hantro/Kconfig" source "drivers/staging/media/imx/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index c486298194da..2f1711a8aeed 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,8 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro-dvt/ -obj-$(CONFIG_I2C_BCM2048) += bcm2048/ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ -obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ diff --git a/drivers/staging/media/bcm2048/Kconfig b/drivers/staging/media/bcm2048/Kconfig deleted file mode 100644 index ab2d50cac140..000000000000 --- a/drivers/staging/media/bcm2048/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Multimedia Video device configuration -# - -config I2C_BCM2048 - tristate "Broadcom BCM2048 FM Radio Receiver support" - depends on I2C && VIDEO_V4L2 && RADIO_ADAPTERS - help - Say Y here if you want support to BCM2048 FM Radio Receiver. - This device driver supports only i2c bus. - - To compile this driver as a module, choose M here: the - module will be called radio-bcm2048. diff --git a/drivers/staging/media/bcm2048/Makefile b/drivers/staging/media/bcm2048/Makefile deleted file mode 100644 index f42056848dc6..000000000000 --- a/drivers/staging/media/bcm2048/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_I2C_BCM2048) += radio-bcm2048.o diff --git a/drivers/staging/media/bcm2048/TODO b/drivers/staging/media/bcm2048/TODO deleted file mode 100644 index 6bee2a2dad68..000000000000 --- a/drivers/staging/media/bcm2048/TODO +++ /dev/null @@ -1,24 +0,0 @@ -TODO: - -From the initial code review: - -The main thing you need to do is to implement all the controls using the -control framework (see Documentation/media/kapi/v4l2-controls.rst). -Most drivers are by now converted to the control framework, so you will -find many examples of how to do this in drivers/media/radio. - -The sysfs stuff should be replaced by controls as well. A lot of the RDS -support is now available as controls (although there may well be some -missing features, but that is easy enough to add). Since the RDS data is -actually read() from the device I am not sure whether the RDS -properties/controls should be there at all. - -Correct Coding Style, as this driver also violates several Style -rules, and do evil tricks, like returning from a function inside a -macro. - -Finally this driver should probably be split up into two parts: one -v4l2_subdev-based core driver and one platform driver. See e.g. -radio-si4713/si4713-i2c.c as a good example. But I would wait with that -until the rest of the driver is cleaned up. Then I have a better idea of -whether this is necessary or not. diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c deleted file mode 100644 index 2c60a1fb6350..000000000000 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ /dev/null @@ -1,2689 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * drivers/staging/media/radio-bcm2048.c - * - * Driver for I2C Broadcom BCM2048 FM Radio Receiver: - * - * Copyright (C) Nokia Corporation - * Contact: Eero Nurkkala <ext-eero.nurkkala@nokia.com> - * - * Copyright (C) Nils Faerber <nils.faerber@kernelconcepts.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -/* - * History: - * Eero Nurkkala <ext-eero.nurkkala@nokia.com> - * Version 0.0.1 - * - Initial implementation - * 2010-02-21 Nils Faerber <nils.faerber@kernelconcepts.de> - * Version 0.0.2 - * - Add support for interrupt driven rds data reading - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/version.h> -#include <linux/interrupt.h> -#include <linux/sysfs.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/videodev2.h> -#include <linux/mutex.h> -#include <linux/slab.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> -#include "radio-bcm2048.h" - -/* driver definitions */ -#define BCM2048_DRIVER_AUTHOR "Eero Nurkkala <ext-eero.nurkkala@nokia.com>" -#define BCM2048_DRIVER_NAME BCM2048_NAME -#define BCM2048_DRIVER_CARD "Broadcom bcm2048 FM Radio Receiver" -#define BCM2048_DRIVER_DESC "I2C driver for BCM2048 FM Radio Receiver" - -/* I2C Control Registers */ -#define BCM2048_I2C_FM_RDS_SYSTEM 0x00 -#define BCM2048_I2C_FM_CTRL 0x01 -#define BCM2048_I2C_RDS_CTRL0 0x02 -#define BCM2048_I2C_RDS_CTRL1 0x03 -#define BCM2048_I2C_FM_AUDIO_PAUSE 0x04 -#define BCM2048_I2C_FM_AUDIO_CTRL0 0x05 -#define BCM2048_I2C_FM_AUDIO_CTRL1 0x06 -#define BCM2048_I2C_FM_SEARCH_CTRL0 0x07 -#define BCM2048_I2C_FM_SEARCH_CTRL1 0x08 -#define BCM2048_I2C_FM_SEARCH_TUNE_MODE 0x09 -#define BCM2048_I2C_FM_FREQ0 0x0a -#define BCM2048_I2C_FM_FREQ1 0x0b -#define BCM2048_I2C_FM_AF_FREQ0 0x0c -#define BCM2048_I2C_FM_AF_FREQ1 0x0d -#define BCM2048_I2C_FM_CARRIER 0x0e -#define BCM2048_I2C_FM_RSSI 0x0f -#define BCM2048_I2C_FM_RDS_MASK0 0x10 -#define BCM2048_I2C_FM_RDS_MASK1 0x11 -#define BCM2048_I2C_FM_RDS_FLAG0 0x12 -#define BCM2048_I2C_FM_RDS_FLAG1 0x13 -#define BCM2048_I2C_RDS_WLINE 0x14 -#define BCM2048_I2C_RDS_BLKB_MATCH0 0x16 -#define BCM2048_I2C_RDS_BLKB_MATCH1 0x17 -#define BCM2048_I2C_RDS_BLKB_MASK0 0x18 -#define BCM2048_I2C_RDS_BLKB_MASK1 0x19 -#define BCM2048_I2C_RDS_PI_MATCH0 0x1a -#define BCM2048_I2C_RDS_PI_MATCH1 0x1b -#define BCM2048_I2C_RDS_PI_MASK0 0x1c -#define BCM2048_I2C_RDS_PI_MASK1 0x1d -#define BCM2048_I2C_SPARE1 0x20 -#define BCM2048_I2C_SPARE2 0x21 -#define BCM2048_I2C_FM_RDS_REV 0x28 -#define BCM2048_I2C_SLAVE_CONFIGURATION 0x29 -#define BCM2048_I2C_RDS_DATA 0x80 -#define BCM2048_I2C_FM_BEST_TUNE_MODE 0x90 - -/* BCM2048_I2C_FM_RDS_SYSTEM */ -#define BCM2048_FM_ON 0x01 -#define BCM2048_RDS_ON 0x02 - -/* BCM2048_I2C_FM_CTRL */ -#define BCM2048_BAND_SELECT 0x01 -#define BCM2048_STEREO_MONO_AUTO_SELECT 0x02 -#define BCM2048_STEREO_MONO_MANUAL_SELECT 0x04 -#define BCM2048_STEREO_MONO_BLEND_SWITCH 0x08 -#define BCM2048_HI_LO_INJECTION 0x10 - -/* BCM2048_I2C_RDS_CTRL0 */ -#define BCM2048_RBDS_RDS_SELECT 0x01 -#define BCM2048_FLUSH_FIFO 0x02 - -/* BCM2048_I2C_FM_AUDIO_PAUSE */ -#define BCM2048_AUDIO_PAUSE_RSSI_TRESH 0x0f -#define BCM2048_AUDIO_PAUSE_DURATION 0xf0 - -/* BCM2048_I2C_FM_AUDIO_CTRL0 */ -#define BCM2048_RF_MUTE 0x01 -#define BCM2048_MANUAL_MUTE 0x02 -#define BCM2048_DAC_OUTPUT_LEFT 0x04 -#define BCM2048_DAC_OUTPUT_RIGHT 0x08 -#define BCM2048_AUDIO_ROUTE_DAC 0x10 -#define BCM2048_AUDIO_ROUTE_I2S 0x20 -#define BCM2048_DE_EMPHASIS_SELECT 0x40 -#define BCM2048_AUDIO_BANDWIDTH_SELECT 0x80 - -/* BCM2048_I2C_FM_SEARCH_CTRL0 */ -#define BCM2048_SEARCH_RSSI_THRESHOLD 0x7f -#define BCM2048_SEARCH_DIRECTION 0x80 - -/* BCM2048_I2C_FM_SEARCH_TUNE_MODE */ -#define BCM2048_FM_AUTO_SEARCH 0x03 - -/* BCM2048_I2C_FM_RSSI */ -#define BCM2048_RSSI_VALUE 0xff - -/* BCM2048_I2C_FM_RDS_MASK0 */ -/* BCM2048_I2C_FM_RDS_MASK1 */ -#define BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED 0x01 -#define BCM2048_FM_FLAG_SEARCH_TUNE_FAIL 0x02 -#define BCM2048_FM_FLAG_RSSI_LOW 0x04 -#define BCM2048_FM_FLAG_CARRIER_ERROR_HIGH 0x08 -#define BCM2048_FM_FLAG_AUDIO_PAUSE_INDICATION 0x10 -#define BCM2048_FLAG_STEREO_DETECTED 0x20 -#define BCM2048_FLAG_STEREO_ACTIVE 0x40 - -/* BCM2048_I2C_RDS_DATA */ -#define BCM2048_SLAVE_ADDRESS 0x3f -#define BCM2048_SLAVE_ENABLE 0x80 - -/* BCM2048_I2C_FM_BEST_TUNE_MODE */ -#define BCM2048_BEST_TUNE_MODE 0x80 - -#define BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED 0x01 -#define BCM2048_FM_FLAG_SEARCH_TUNE_FAIL 0x02 -#define BCM2048_FM_FLAG_RSSI_LOW 0x04 -#define BCM2048_FM_FLAG_CARRIER_ERROR_HIGH 0x08 -#define BCM2048_FM_FLAG_AUDIO_PAUSE_INDICATION 0x10 -#define BCM2048_FLAG_STEREO_DETECTED 0x20 -#define BCM2048_FLAG_STEREO_ACTIVE 0x40 - -#define BCM2048_RDS_FLAG_FIFO_WLINE 0x02 -#define BCM2048_RDS_FLAG_B_BLOCK_MATCH 0x08 -#define BCM2048_RDS_FLAG_SYNC_LOST 0x10 -#define BCM2048_RDS_FLAG_PI_MATCH 0x20 - -#define BCM2048_RDS_MARK_END_BYTE0 0x7C -#define BCM2048_RDS_MARK_END_BYTEN 0xFF - -#define BCM2048_FM_FLAGS_ALL (FM_FLAG_SEARCH_TUNE_FINISHED | \ - FM_FLAG_SEARCH_TUNE_FAIL | \ - FM_FLAG_RSSI_LOW | \ - FM_FLAG_CARRIER_ERROR_HIGH | \ - FM_FLAG_AUDIO_PAUSE_INDICATION | \ - FLAG_STEREO_DETECTED | FLAG_STEREO_ACTIVE) - -#define BCM2048_RDS_FLAGS_ALL (RDS_FLAG_FIFO_WLINE | \ - RDS_FLAG_B_BLOCK_MATCH | \ - RDS_FLAG_SYNC_LOST | RDS_FLAG_PI_MATCH) - -#define BCM2048_DEFAULT_TIMEOUT 1500 -#define BCM2048_AUTO_SEARCH_TIMEOUT 3000 - -#define BCM2048_FREQDEV_UNIT 10000 -#define BCM2048_FREQV4L2_MULTI 625 -#define dev_to_v4l2(f) (((f) * BCM2048_FREQDEV_UNIT) / BCM2048_FREQV4L2_MULTI) -#define v4l2_to_dev(f) (((f) * BCM2048_FREQV4L2_MULTI) / BCM2048_FREQDEV_UNIT) - -#define msb(x) ((u8)((u16)(x) >> 8)) -#define lsb(x) ((u8)((u16)(x) & 0x00FF)) -#define compose_u16(msb, lsb) (((u16)(msb) << 8) | (lsb)) - -#define BCM2048_DEFAULT_POWERING_DELAY 20 -#define BCM2048_DEFAULT_REGION 0x02 -#define BCM2048_DEFAULT_MUTE 0x01 -#define BCM2048_DEFAULT_RSSI_THRESHOLD 0x64 -#define BCM2048_DEFAULT_RDS_WLINE 0x7E - -#define BCM2048_FM_SEARCH_INACTIVE 0x00 -#define BCM2048_FM_PRE_SET_MODE 0x01 -#define BCM2048_FM_AUTO_SEARCH_MODE 0x02 -#define BCM2048_FM_AF_JUMP_MODE 0x03 - -#define BCM2048_FREQUENCY_BASE 64000 - -#define BCM2048_POWER_ON 0x01 -#define BCM2048_POWER_OFF 0x00 - -#define BCM2048_ITEM_ENABLED 0x01 -#define BCM2048_SEARCH_DIRECTION_UP 0x01 - -#define BCM2048_DE_EMPHASIS_75us 75 -#define BCM2048_DE_EMPHASIS_50us 50 - -#define BCM2048_SCAN_FAIL 0x00 -#define BCM2048_SCAN_OK 0x01 - -#define BCM2048_FREQ_ERROR_FLOOR -20 -#define BCM2048_FREQ_ERROR_ROOF 20 - -/* -60 dB is reported as full signal strength */ -#define BCM2048_RSSI_LEVEL_BASE -60 -#define BCM2048_RSSI_LEVEL_ROOF -100 -#define BCM2048_RSSI_LEVEL_ROOF_NEG 100 -#define BCM2048_SIGNAL_MULTIPLIER (0xFFFF / \ - (BCM2048_RSSI_LEVEL_ROOF_NEG + \ - BCM2048_RSSI_LEVEL_BASE)) - -#define BCM2048_RDS_FIFO_DUPLE_SIZE 0x03 -#define BCM2048_RDS_CRC_MASK 0x0F -#define BCM2048_RDS_CRC_NONE 0x00 -#define BCM2048_RDS_CRC_MAX_2BITS 0x04 -#define BCM2048_RDS_CRC_LEAST_2BITS 0x08 -#define BCM2048_RDS_CRC_UNRECOVARABLE 0x0C - -#define BCM2048_RDS_BLOCK_MASK 0xF0 -#define BCM2048_RDS_BLOCK_A 0x00 -#define BCM2048_RDS_BLOCK_B 0x10 -#define BCM2048_RDS_BLOCK_C 0x20 -#define BCM2048_RDS_BLOCK_D 0x30 -#define BCM2048_RDS_BLOCK_C_SCORED 0x40 -#define BCM2048_RDS_BLOCK_E 0x60 - -#define BCM2048_RDS_RT 0x20 -#define BCM2048_RDS_PS 0x00 - -#define BCM2048_RDS_GROUP_AB_MASK 0x08 -#define BCM2048_RDS_GROUP_A 0x00 -#define BCM2048_RDS_GROUP_B 0x08 - -#define BCM2048_RDS_RT_AB_MASK 0x10 -#define BCM2048_RDS_RT_A 0x00 -#define BCM2048_RDS_RT_B 0x10 -#define BCM2048_RDS_RT_INDEX 0x0F - -#define BCM2048_RDS_PS_INDEX 0x03 - -struct rds_info { - u16 rds_pi; -#define BCM2048_MAX_RDS_RT (64 + 1) - u8 rds_rt[BCM2048_MAX_RDS_RT]; - u8 rds_rt_group_b; - u8 rds_rt_ab; -#define BCM2048_MAX_RDS_PS (8 + 1) - u8 rds_ps[BCM2048_MAX_RDS_PS]; - u8 rds_ps_group; - u8 rds_ps_group_cnt; -#define BCM2048_MAX_RDS_RADIO_TEXT 255 - u8 radio_text[BCM2048_MAX_RDS_RADIO_TEXT + 3]; - u8 text_len; -}; - -struct region_info { - u32 bottom_frequency; - u32 top_frequency; - u8 deemphasis; - u8 channel_spacing; - u8 region; -}; - -struct bcm2048_device { - struct i2c_client *client; - struct video_device videodev; - struct work_struct work; - struct completion compl; - struct mutex mutex; - struct bcm2048_platform_data *platform_data; - struct rds_info rds_info; - struct region_info region_info; - u16 frequency; - u8 cache_fm_rds_system; - u8 cache_fm_ctrl; - u8 cache_fm_audio_ctrl0; - u8 cache_fm_search_ctrl0; - u8 power_state; - u8 rds_state; - u8 fifo_size; - u8 scan_state; - u8 mute_state; - - /* for rds data device read */ - wait_queue_head_t read_queue; - unsigned int users; - unsigned char rds_data_available; - unsigned int rd_index; -}; - -static int radio_nr = -1; /* radio device minor (-1 ==> auto assign) */ -module_param(radio_nr, int, 0000); -MODULE_PARM_DESC(radio_nr, - "Minor number for radio device (-1 ==> auto assign)"); - -static const struct region_info region_configs[] = { - /* USA */ - { - .channel_spacing = 20, - .bottom_frequency = 87500, - .top_frequency = 108000, - .deemphasis = 75, - .region = 0, - }, - /* Australia */ - { - .channel_spacing = 20, - .bottom_frequency = 87500, - .top_frequency = 108000, - .deemphasis = 50, - .region = 1, - }, - /* Europe */ - { - .channel_spacing = 10, - .bottom_frequency = 87500, - .top_frequency = 108000, - .deemphasis = 50, - .region = 2, - }, - /* Japan */ - { - .channel_spacing = 10, - .bottom_frequency = 76000, - .top_frequency = 90000, - .deemphasis = 50, - .region = 3, - }, -}; - -/* - * I2C Interface read / write - */ -static int bcm2048_send_command(struct bcm2048_device *bdev, unsigned int reg, - unsigned int value) -{ - struct i2c_client *client = bdev->client; - u8 data[2]; - - if (!bdev->power_state) { - dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n"); - return -EIO; - } - - data[0] = reg & 0xff; - data[1] = value & 0xff; - - if (i2c_master_send(client, data, 2) == 2) - return 0; - - dev_err(&bdev->client->dev, "BCM I2C error!\n"); - dev_err(&bdev->client->dev, "Is Bluetooth up and running?\n"); - return -EIO; -} - -static int bcm2048_recv_command(struct bcm2048_device *bdev, unsigned int reg, - u8 *value) -{ - struct i2c_client *client = bdev->client; - - if (!bdev->power_state) { - dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n"); - return -EIO; - } - - value[0] = i2c_smbus_read_byte_data(client, reg & 0xff); - - return 0; -} - -static int bcm2048_recv_duples(struct bcm2048_device *bdev, unsigned int reg, - u8 *value, u8 duples) -{ - struct i2c_client *client = bdev->client; - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg[2]; - u8 buf; - - if (!bdev->power_state) { - dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n"); - return -EIO; - } - - buf = reg & 0xff; - - msg[0].addr = client->addr; - msg[0].flags = client->flags & I2C_M_TEN; - msg[0].len = 1; - msg[0].buf = &buf; - - msg[1].addr = client->addr; - msg[1].flags = client->flags & I2C_M_TEN; - msg[1].flags |= I2C_M_RD; - msg[1].len = duples; - msg[1].buf = value; - - return i2c_transfer(adap, msg, 2); -} - -/* - * BCM2048 - I2C register programming helpers - */ -static int bcm2048_set_power_state(struct bcm2048_device *bdev, u8 power) -{ - int err = 0; - - mutex_lock(&bdev->mutex); - - if (power) { - bdev->power_state = BCM2048_POWER_ON; - bdev->cache_fm_rds_system |= BCM2048_FM_ON; - } else { - bdev->cache_fm_rds_system &= ~BCM2048_FM_ON; - } - - /* - * Warning! FM cannot be turned off because then - * the I2C communications get ruined! - * Comment off the "if (power)" when the chip works! - */ - if (power) - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, - bdev->cache_fm_rds_system); - msleep(BCM2048_DEFAULT_POWERING_DELAY); - - if (!power) - bdev->power_state = BCM2048_POWER_OFF; - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_power_state(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, &value); - - mutex_unlock(&bdev->mutex); - - if (!err && (value & BCM2048_FM_ON)) - return BCM2048_POWER_ON; - - return err; -} - -static int bcm2048_set_rds_no_lock(struct bcm2048_device *bdev, u8 rds_on) -{ - int err; - u8 flags; - - bdev->cache_fm_rds_system &= ~BCM2048_RDS_ON; - - if (rds_on) { - bdev->cache_fm_rds_system |= BCM2048_RDS_ON; - bdev->rds_state = BCM2048_RDS_ON; - flags = BCM2048_RDS_FLAG_FIFO_WLINE; - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1, - flags); - } else { - flags = 0; - bdev->rds_state = 0; - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1, - flags); - memset(&bdev->rds_info, 0, sizeof(bdev->rds_info)); - } - if (err) - return err; - - return bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, - bdev->cache_fm_rds_system); -} - -static int bcm2048_get_rds_no_lock(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, &value); - - if (!err && (value & BCM2048_RDS_ON)) - return BCM2048_ITEM_ENABLED; - - return err; -} - -static int bcm2048_set_rds(struct bcm2048_device *bdev, u8 rds_on) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_set_rds_no_lock(bdev, rds_on); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds(struct bcm2048_device *bdev) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_get_rds_no_lock(bdev); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_pi(struct bcm2048_device *bdev) -{ - return bdev->rds_info.rds_pi; -} - -static int bcm2048_set_fm_automatic_stereo_mono(struct bcm2048_device *bdev, - u8 enabled) -{ - int err; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_ctrl &= ~BCM2048_STEREO_MONO_AUTO_SELECT; - - if (enabled) - bdev->cache_fm_ctrl |= BCM2048_STEREO_MONO_AUTO_SELECT; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL, - bdev->cache_fm_ctrl); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_set_fm_hi_lo_injection(struct bcm2048_device *bdev, - u8 hi_lo) -{ - int err; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_ctrl &= ~BCM2048_HI_LO_INJECTION; - - if (hi_lo) - bdev->cache_fm_ctrl |= BCM2048_HI_LO_INJECTION; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL, - bdev->cache_fm_ctrl); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_hi_lo_injection(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_CTRL, &value); - - mutex_unlock(&bdev->mutex); - - if (!err && (value & BCM2048_HI_LO_INJECTION)) - return BCM2048_ITEM_ENABLED; - - return err; -} - -static int bcm2048_set_fm_frequency(struct bcm2048_device *bdev, u32 frequency) -{ - int err; - - if (frequency < bdev->region_info.bottom_frequency || - frequency > bdev->region_info.top_frequency) - return -EDOM; - - frequency -= BCM2048_FREQUENCY_BASE; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_FREQ0, lsb(frequency)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_FREQ1, - msb(frequency)); - - if (!err) - bdev->frequency = frequency; - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_frequency(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_FREQ0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_FREQ1, &msb); - - mutex_unlock(&bdev->mutex); - - if (err) - return err; - - err = compose_u16(msb, lsb); - err += BCM2048_FREQUENCY_BASE; - - return err; -} - -static int bcm2048_set_fm_af_frequency(struct bcm2048_device *bdev, - u32 frequency) -{ - int err; - - if (frequency < bdev->region_info.bottom_frequency || - frequency > bdev->region_info.top_frequency) - return -EDOM; - - frequency -= BCM2048_FREQUENCY_BASE; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AF_FREQ0, - lsb(frequency)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_AF_FREQ1, - msb(frequency)); - if (!err) - bdev->frequency = frequency; - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_af_frequency(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AF_FREQ0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_AF_FREQ1, &msb); - - mutex_unlock(&bdev->mutex); - - if (err) - return err; - - err = compose_u16(msb, lsb); - err += BCM2048_FREQUENCY_BASE; - - return err; -} - -static int bcm2048_set_fm_deemphasis(struct bcm2048_device *bdev, int d) -{ - int err; - u8 deemphasis; - - if (d == BCM2048_DE_EMPHASIS_75us) - deemphasis = BCM2048_DE_EMPHASIS_SELECT; - else - deemphasis = 0; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_audio_ctrl0 &= ~BCM2048_DE_EMPHASIS_SELECT; - bdev->cache_fm_audio_ctrl0 |= deemphasis; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, - bdev->cache_fm_audio_ctrl0); - - if (!err) - bdev->region_info.deemphasis = d; - - mutex_unlock(&bdev->mutex); - - return err; -} - -static int bcm2048_get_fm_deemphasis(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value); - - mutex_unlock(&bdev->mutex); - - if (!err) { - if (value & BCM2048_DE_EMPHASIS_SELECT) - return BCM2048_DE_EMPHASIS_75us; - - return BCM2048_DE_EMPHASIS_50us; - } - - return err; -} - -static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region) -{ - int err; - u32 new_frequency = 0; - - if (region >= ARRAY_SIZE(region_configs)) - return -EINVAL; - - mutex_lock(&bdev->mutex); - bdev->region_info = region_configs[region]; - - if (region_configs[region].bottom_frequency < 87500) - bdev->cache_fm_ctrl |= BCM2048_BAND_SELECT; - else - bdev->cache_fm_ctrl &= ~BCM2048_BAND_SELECT; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL, - bdev->cache_fm_ctrl); - if (err) { - mutex_unlock(&bdev->mutex); - goto done; - } - mutex_unlock(&bdev->mutex); - - if (bdev->frequency < region_configs[region].bottom_frequency || - bdev->frequency > region_configs[region].top_frequency) - new_frequency = region_configs[region].bottom_frequency; - - if (new_frequency > 0) { - err = bcm2048_set_fm_frequency(bdev, new_frequency); - - if (err) - goto done; - } - - err = bcm2048_set_fm_deemphasis(bdev, - region_configs[region].deemphasis); - -done: - return err; -} - -static int bcm2048_get_region(struct bcm2048_device *bdev) -{ - int err; - - mutex_lock(&bdev->mutex); - err = bdev->region_info.region; - mutex_unlock(&bdev->mutex); - - return err; -} - -static int bcm2048_set_mute(struct bcm2048_device *bdev, u16 mute) -{ - int err; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_RF_MUTE | BCM2048_MANUAL_MUTE); - - if (mute) - bdev->cache_fm_audio_ctrl0 |= (BCM2048_RF_MUTE | - BCM2048_MANUAL_MUTE); - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, - bdev->cache_fm_audio_ctrl0); - - if (!err) - bdev->mute_state = mute; - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_mute(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - if (bdev->power_state) { - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, - &value); - if (!err) - err = value & (BCM2048_RF_MUTE | BCM2048_MANUAL_MUTE); - } else { - err = bdev->mute_state; - } - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_set_audio_route(struct bcm2048_device *bdev, u8 route) -{ - int err; - - mutex_lock(&bdev->mutex); - - route &= (BCM2048_AUDIO_ROUTE_DAC | BCM2048_AUDIO_ROUTE_I2S); - bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_AUDIO_ROUTE_DAC | - BCM2048_AUDIO_ROUTE_I2S); - bdev->cache_fm_audio_ctrl0 |= route; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, - bdev->cache_fm_audio_ctrl0); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_audio_route(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value); - - mutex_unlock(&bdev->mutex); - - if (!err) - return value & (BCM2048_AUDIO_ROUTE_DAC | - BCM2048_AUDIO_ROUTE_I2S); - - return err; -} - -static int bcm2048_set_dac_output(struct bcm2048_device *bdev, u8 channels) -{ - int err; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_DAC_OUTPUT_LEFT | - BCM2048_DAC_OUTPUT_RIGHT); - bdev->cache_fm_audio_ctrl0 |= channels; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, - bdev->cache_fm_audio_ctrl0); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_dac_output(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value); - - mutex_unlock(&bdev->mutex); - - if (!err) - return value & (BCM2048_DAC_OUTPUT_LEFT | - BCM2048_DAC_OUTPUT_RIGHT); - - return err; -} - -static int bcm2048_set_fm_search_rssi_threshold(struct bcm2048_device *bdev, - u8 threshold) -{ - int err; - - mutex_lock(&bdev->mutex); - - threshold &= BCM2048_SEARCH_RSSI_THRESHOLD; - bdev->cache_fm_search_ctrl0 &= ~BCM2048_SEARCH_RSSI_THRESHOLD; - bdev->cache_fm_search_ctrl0 |= threshold; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, - bdev->cache_fm_search_ctrl0); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_search_rssi_threshold(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, &value); - - mutex_unlock(&bdev->mutex); - - if (!err) - return value & BCM2048_SEARCH_RSSI_THRESHOLD; - - return err; -} - -static int bcm2048_set_fm_search_mode_direction(struct bcm2048_device *bdev, - u8 direction) -{ - int err; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_search_ctrl0 &= ~BCM2048_SEARCH_DIRECTION; - - if (direction) - bdev->cache_fm_search_ctrl0 |= BCM2048_SEARCH_DIRECTION; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, - bdev->cache_fm_search_ctrl0); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_search_mode_direction(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, &value); - - mutex_unlock(&bdev->mutex); - - if (!err && (value & BCM2048_SEARCH_DIRECTION)) - return BCM2048_SEARCH_DIRECTION_UP; - - return err; -} - -static int bcm2048_set_fm_search_tune_mode(struct bcm2048_device *bdev, - u8 mode) -{ - int err, timeout, restart_rds = 0; - u8 value, flags; - - value = mode & BCM2048_FM_AUTO_SEARCH; - - flags = BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED | - BCM2048_FM_FLAG_SEARCH_TUNE_FAIL; - - mutex_lock(&bdev->mutex); - - /* - * If RDS is enabled, and frequency is changed, RDS quits working. - * Thus, always restart RDS if it's enabled. Moreover, RDS must - * not be enabled while changing the frequency because it can - * provide a race to the mutex from the workqueue handler if RDS - * IRQ occurs while waiting for frequency changed IRQ. - */ - if (bcm2048_get_rds_no_lock(bdev)) { - err = bcm2048_set_rds_no_lock(bdev, 0); - if (err) - goto unlock; - restart_rds = 1; - } - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK0, flags); - - if (err) - goto unlock; - - bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_TUNE_MODE, value); - - if (mode != BCM2048_FM_AUTO_SEARCH_MODE) - timeout = BCM2048_DEFAULT_TIMEOUT; - else - timeout = BCM2048_AUTO_SEARCH_TIMEOUT; - - if (!wait_for_completion_timeout(&bdev->compl, - msecs_to_jiffies(timeout))) - dev_err(&bdev->client->dev, "IRQ timeout.\n"); - - if (value) - if (!bdev->scan_state) - err = -EIO; - -unlock: - if (restart_rds) - err |= bcm2048_set_rds_no_lock(bdev, 1); - - mutex_unlock(&bdev->mutex); - - return err; -} - -static int bcm2048_get_fm_search_tune_mode(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_TUNE_MODE, - &value); - - mutex_unlock(&bdev->mutex); - - if (!err) - return value & BCM2048_FM_AUTO_SEARCH; - - return err; -} - -static int bcm2048_set_rds_b_block_mask(struct bcm2048_device *bdev, u16 mask) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MASK0, - lsb(mask)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MASK1, - msb(mask)); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_b_block_mask(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MASK0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MASK1, &msb); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(msb, lsb); - - return err; -} - -static int bcm2048_set_rds_b_block_match(struct bcm2048_device *bdev, - u16 match) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH0, - lsb(match)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH1, - msb(match)); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_b_block_match(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH1, &msb); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(msb, lsb); - - return err; -} - -static int bcm2048_set_rds_pi_mask(struct bcm2048_device *bdev, u16 mask) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MASK0, lsb(mask)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MASK1, msb(mask)); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_pi_mask(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MASK0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MASK1, &msb); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(msb, lsb); - - return err; -} - -static int bcm2048_set_rds_pi_match(struct bcm2048_device *bdev, u16 match) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MATCH0, - lsb(match)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MATCH1, - msb(match)); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_pi_match(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MATCH0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MATCH1, &msb); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(msb, lsb); - - return err; -} - -static int bcm2048_set_fm_rds_mask(struct bcm2048_device *bdev, u16 mask) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK0, lsb(mask)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1, msb(mask)); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_rds_mask(struct bcm2048_device *bdev) -{ - int err; - u8 value0 = 0, value1 = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_MASK0, &value0); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_MASK1, &value1); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(value1, value0); - - return err; -} - -static int bcm2048_get_fm_rds_flags(struct bcm2048_device *bdev) -{ - int err; - u8 value0 = 0, value1 = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG0, &value0); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG1, &value1); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(value1, value0); - - return err; -} - -static int bcm2048_get_region_bottom_frequency(struct bcm2048_device *bdev) -{ - return bdev->region_info.bottom_frequency; -} - -static int bcm2048_get_region_top_frequency(struct bcm2048_device *bdev) -{ - return bdev->region_info.top_frequency; -} - -static int bcm2048_set_fm_best_tune_mode(struct bcm2048_device *bdev, u8 mode) -{ - int err; - u8 value = 0; - - mutex_lock(&bdev->mutex); - - /* Perform read as the manual indicates */ - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE, - &value); - value &= ~BCM2048_BEST_TUNE_MODE; - - if (mode) - value |= BCM2048_BEST_TUNE_MODE; - err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE, - value); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_best_tune_mode(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE, - &value); - - mutex_unlock(&bdev->mutex); - - if (!err && (value & BCM2048_BEST_TUNE_MODE)) - return BCM2048_ITEM_ENABLED; - - return err; -} - -static int bcm2048_get_fm_carrier_error(struct bcm2048_device *bdev) -{ - int err = 0; - s8 value; - - mutex_lock(&bdev->mutex); - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_CARRIER, &value); - mutex_unlock(&bdev->mutex); - - if (!err) - return value; - - return err; -} - -static int bcm2048_get_fm_rssi(struct bcm2048_device *bdev) -{ - int err; - s8 value; - - mutex_lock(&bdev->mutex); - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RSSI, &value); - mutex_unlock(&bdev->mutex); - - if (!err) - return value; - - return err; -} - -static int bcm2048_set_rds_wline(struct bcm2048_device *bdev, u8 wline) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_WLINE, wline); - - if (!err) - bdev->fifo_size = wline; - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_wline(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_WLINE, &value); - - mutex_unlock(&bdev->mutex); - - if (!err) { - bdev->fifo_size = value; - return value; - } - - return err; -} - -static int bcm2048_checkrev(struct bcm2048_device *bdev) -{ - int err; - u8 version; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_REV, &version); - - mutex_unlock(&bdev->mutex); - - if (!err) { - dev_info(&bdev->client->dev, "BCM2048 Version 0x%x\n", - version); - return version; - } - - return err; -} - -static int bcm2048_get_rds_rt(struct bcm2048_device *bdev, char *data) -{ - int err = 0, i, j = 0, ce = 0, cr = 0; - char data_buffer[BCM2048_MAX_RDS_RT + 1]; - - mutex_lock(&bdev->mutex); - - if (!bdev->rds_info.text_len) { - err = -EINVAL; - goto unlock; - } - - for (i = 0; i < BCM2048_MAX_RDS_RT; i++) { - if (bdev->rds_info.rds_rt[i]) { - ce = i; - /* Skip the carriage return */ - if (bdev->rds_info.rds_rt[i] != 0x0d) { - data_buffer[j++] = bdev->rds_info.rds_rt[i]; - } else { - cr = i; - break; - } - } - } - - if (j <= BCM2048_MAX_RDS_RT) - data_buffer[j] = 0; - - for (i = 0; i < BCM2048_MAX_RDS_RT; i++) { - if (!bdev->rds_info.rds_rt[i]) { - if (cr && (i < cr)) { - err = -EBUSY; - goto unlock; - } - if (i < ce) { - if (cr && (i >= cr)) - break; - err = -EBUSY; - goto unlock; - } - } - } - - memcpy(data, data_buffer, sizeof(data_buffer)); - -unlock: - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_ps(struct bcm2048_device *bdev, char *data) -{ - int err = 0, i, j = 0; - char data_buffer[BCM2048_MAX_RDS_PS + 1]; - - mutex_lock(&bdev->mutex); - - if (!bdev->rds_info.text_len) { - err = -EINVAL; - goto unlock; - } - - for (i = 0; i < BCM2048_MAX_RDS_PS; i++) { - if (bdev->rds_info.rds_ps[i]) { - data_buffer[j++] = bdev->rds_info.rds_ps[i]; - } else { - if (i < (BCM2048_MAX_RDS_PS - 1)) { - err = -EBUSY; - goto unlock; - } - } - } - - if (j <= BCM2048_MAX_RDS_PS) - data_buffer[j] = 0; - - memcpy(data, data_buffer, sizeof(data_buffer)); - -unlock: - mutex_unlock(&bdev->mutex); - return err; -} - -static void bcm2048_parse_rds_pi(struct bcm2048_device *bdev) -{ - int i, cnt = 0; - u16 pi; - - for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) { - /* Block A match, only data without crc errors taken */ - if (bdev->rds_info.radio_text[i] == BCM2048_RDS_BLOCK_A) { - pi = (bdev->rds_info.radio_text[i + 1] << 8) + - bdev->rds_info.radio_text[i + 2]; - - if (!bdev->rds_info.rds_pi) { - bdev->rds_info.rds_pi = pi; - return; - } - if (pi != bdev->rds_info.rds_pi) { - cnt++; - if (cnt > 3) { - bdev->rds_info.rds_pi = pi; - cnt = 0; - } - } else { - cnt = 0; - } - } - } -} - -static int bcm2048_rds_block_crc(struct bcm2048_device *bdev, int i) -{ - return bdev->rds_info.radio_text[i] & BCM2048_RDS_CRC_MASK; -} - -static void bcm2048_parse_rds_rt_block(struct bcm2048_device *bdev, int i, - int index, int crc) -{ - /* Good data will overwrite poor data */ - if (crc) { - if (!bdev->rds_info.rds_rt[index]) - bdev->rds_info.rds_rt[index] = - bdev->rds_info.radio_text[i + 1]; - if (!bdev->rds_info.rds_rt[index + 1]) - bdev->rds_info.rds_rt[index + 1] = - bdev->rds_info.radio_text[i + 2]; - } else { - bdev->rds_info.rds_rt[index] = - bdev->rds_info.radio_text[i + 1]; - bdev->rds_info.rds_rt[index + 1] = - bdev->rds_info.radio_text[i + 2]; - } -} - -static int bcm2048_parse_rt_match_b(struct bcm2048_device *bdev, int i) -{ - int crc, rt_id, rt_group_b, rt_ab, index = 0; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return -EIO; - - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_B) { - rt_id = bdev->rds_info.radio_text[i + 1] & - BCM2048_RDS_BLOCK_MASK; - rt_group_b = bdev->rds_info.radio_text[i + 1] & - BCM2048_RDS_GROUP_AB_MASK; - rt_ab = bdev->rds_info.radio_text[i + 2] & - BCM2048_RDS_RT_AB_MASK; - - if (rt_group_b != bdev->rds_info.rds_rt_group_b) { - memset(bdev->rds_info.rds_rt, 0, - sizeof(bdev->rds_info.rds_rt)); - bdev->rds_info.rds_rt_group_b = rt_group_b; - } - - if (rt_id == BCM2048_RDS_RT) { - /* A to B or (vice versa), means: clear screen */ - if (rt_ab != bdev->rds_info.rds_rt_ab) { - memset(bdev->rds_info.rds_rt, 0, - sizeof(bdev->rds_info.rds_rt)); - bdev->rds_info.rds_rt_ab = rt_ab; - } - - index = bdev->rds_info.radio_text[i + 2] & - BCM2048_RDS_RT_INDEX; - - if (bdev->rds_info.rds_rt_group_b) - index <<= 1; - else - index <<= 2; - - return index; - } - } - - return -EIO; -} - -static int bcm2048_parse_rt_match_c(struct bcm2048_device *bdev, int i, - int index) -{ - int crc; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return 0; - - if ((index + 2) >= BCM2048_MAX_RDS_RT) { - dev_err(&bdev->client->dev, - "Incorrect index = %d\n", index); - return 0; - } - - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_C) { - if (bdev->rds_info.rds_rt_group_b) - return 1; - bcm2048_parse_rds_rt_block(bdev, i, index, crc); - return 1; - } - - return 0; -} - -static void bcm2048_parse_rt_match_d(struct bcm2048_device *bdev, int i, - int index) -{ - int crc; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return; - - if ((index + 4) >= BCM2048_MAX_RDS_RT) { - dev_err(&bdev->client->dev, - "Incorrect index = %d\n", index); - return; - } - - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_D) - bcm2048_parse_rds_rt_block(bdev, i, index + 2, crc); -} - -static void bcm2048_parse_rds_rt(struct bcm2048_device *bdev) -{ - int i, index = 0, crc, match_b = 0, match_c = 0, match_d = 0; - - for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) { - if (match_b) { - match_b = 0; - index = bcm2048_parse_rt_match_b(bdev, i); - if (index >= 0 && index <= (BCM2048_MAX_RDS_RT - 5)) - match_c = 1; - continue; - } else if (match_c) { - match_c = 0; - if (bcm2048_parse_rt_match_c(bdev, i, index)) - match_d = 1; - continue; - } else if (match_d) { - match_d = 0; - bcm2048_parse_rt_match_d(bdev, i, index); - continue; - } - - /* Skip erroneous blocks due to messed up A block altogether */ - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_A) { - crc = bcm2048_rds_block_crc(bdev, i); - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - continue; - /* Synchronize to a good RDS PI */ - if (((bdev->rds_info.radio_text[i + 1] << 8) + - bdev->rds_info.radio_text[i + 2]) == - bdev->rds_info.rds_pi) - match_b = 1; - } - } -} - -static void bcm2048_parse_rds_ps_block(struct bcm2048_device *bdev, int i, - int index, int crc) -{ - /* Good data will overwrite poor data */ - if (crc) { - if (!bdev->rds_info.rds_ps[index]) - bdev->rds_info.rds_ps[index] = - bdev->rds_info.radio_text[i + 1]; - if (!bdev->rds_info.rds_ps[index + 1]) - bdev->rds_info.rds_ps[index + 1] = - bdev->rds_info.radio_text[i + 2]; - } else { - bdev->rds_info.rds_ps[index] = - bdev->rds_info.radio_text[i + 1]; - bdev->rds_info.rds_ps[index + 1] = - bdev->rds_info.radio_text[i + 2]; - } -} - -static int bcm2048_parse_ps_match_c(struct bcm2048_device *bdev, int i, - int index) -{ - int crc; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return 0; - - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_C) - return 1; - - return 0; -} - -static void bcm2048_parse_ps_match_d(struct bcm2048_device *bdev, int i, - int index) -{ - int crc; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return; - - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_D) - bcm2048_parse_rds_ps_block(bdev, i, index, crc); -} - -static int bcm2048_parse_ps_match_b(struct bcm2048_device *bdev, int i) -{ - int crc, index, ps_id, ps_group; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return -EIO; - - /* Block B Radio PS match */ - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_B) { - ps_id = bdev->rds_info.radio_text[i + 1] & - BCM2048_RDS_BLOCK_MASK; - ps_group = bdev->rds_info.radio_text[i + 1] & - BCM2048_RDS_GROUP_AB_MASK; - - /* - * Poor RSSI will lead to RDS data corruption - * So using 3 (same) sequential values to justify major changes - */ - if (ps_group != bdev->rds_info.rds_ps_group) { - if (crc == BCM2048_RDS_CRC_NONE) { - bdev->rds_info.rds_ps_group_cnt++; - if (bdev->rds_info.rds_ps_group_cnt > 2) { - bdev->rds_info.rds_ps_group = ps_group; - bdev->rds_info.rds_ps_group_cnt = 0; - dev_err(&bdev->client->dev, - "RDS PS Group change!\n"); - } else { - return -EIO; - } - } else { - bdev->rds_info.rds_ps_group_cnt = 0; - } - } - - if (ps_id == BCM2048_RDS_PS) { - index = bdev->rds_info.radio_text[i + 2] & - BCM2048_RDS_PS_INDEX; - index <<= 1; - return index; - } - } - - return -EIO; -} - -static void bcm2048_parse_rds_ps(struct bcm2048_device *bdev) -{ - int i, index = 0, crc, match_b = 0, match_c = 0, match_d = 0; - - for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) { - if (match_b) { - match_b = 0; - index = bcm2048_parse_ps_match_b(bdev, i); - if (index >= 0 && index < (BCM2048_MAX_RDS_PS - 1)) - match_c = 1; - continue; - } else if (match_c) { - match_c = 0; - if (bcm2048_parse_ps_match_c(bdev, i, index)) - match_d = 1; - continue; - } else if (match_d) { - match_d = 0; - bcm2048_parse_ps_match_d(bdev, i, index); - continue; - } - - /* Skip erroneous blocks due to messed up A block altogether */ - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_A) { - crc = bcm2048_rds_block_crc(bdev, i); - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - continue; - /* Synchronize to a good RDS PI */ - if (((bdev->rds_info.radio_text[i + 1] << 8) + - bdev->rds_info.radio_text[i + 2]) == - bdev->rds_info.rds_pi) - match_b = 1; - } - } -} - -static void bcm2048_rds_fifo_receive(struct bcm2048_device *bdev) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_duples(bdev, BCM2048_I2C_RDS_DATA, - bdev->rds_info.radio_text, bdev->fifo_size); - if (err != 2) { - dev_err(&bdev->client->dev, "RDS Read problem\n"); - mutex_unlock(&bdev->mutex); - return; - } - - bdev->rds_info.text_len = bdev->fifo_size; - - bcm2048_parse_rds_pi(bdev); - bcm2048_parse_rds_rt(bdev); - bcm2048_parse_rds_ps(bdev); - - mutex_unlock(&bdev->mutex); - - wake_up_interruptible(&bdev->read_queue); -} - -static int bcm2048_get_rds_data(struct bcm2048_device *bdev, char *data) -{ - int err = 0, i, p = 0; - char *data_buffer; - - mutex_lock(&bdev->mutex); - - if (!bdev->rds_info.text_len) { - err = -EINVAL; - goto unlock; - } - - data_buffer = kcalloc(BCM2048_MAX_RDS_RADIO_TEXT, 5, GFP_KERNEL); - if (!data_buffer) { - err = -ENOMEM; - goto unlock; - } - - for (i = 0; i < bdev->rds_info.text_len; i++) { - p += sprintf(data_buffer + p, "%x ", - bdev->rds_info.radio_text[i]); - } - - memcpy(data, data_buffer, p); - kfree(data_buffer); - -unlock: - mutex_unlock(&bdev->mutex); - return err; -} - -/* - * BCM2048 default initialization sequence - */ -static int bcm2048_init(struct bcm2048_device *bdev) -{ - int err; - - err = bcm2048_set_power_state(bdev, BCM2048_POWER_ON); - if (err < 0) - goto exit; - - err = bcm2048_set_audio_route(bdev, BCM2048_AUDIO_ROUTE_DAC); - if (err < 0) - goto exit; - - err = bcm2048_set_dac_output(bdev, BCM2048_DAC_OUTPUT_LEFT | - BCM2048_DAC_OUTPUT_RIGHT); - -exit: - return err; -} - -/* - * BCM2048 default deinitialization sequence - */ -static int bcm2048_deinit(struct bcm2048_device *bdev) -{ - int err; - - err = bcm2048_set_audio_route(bdev, 0); - if (err < 0) - return err; - - err = bcm2048_set_dac_output(bdev, 0); - if (err < 0) - return err; - - return bcm2048_set_power_state(bdev, BCM2048_POWER_OFF); -} - -/* - * BCM2048 probe sequence - */ -static int bcm2048_probe(struct bcm2048_device *bdev) -{ - int err; - - err = bcm2048_set_power_state(bdev, BCM2048_POWER_ON); - if (err < 0) - goto unlock; - - err = bcm2048_checkrev(bdev); - if (err < 0) - goto unlock; - - err = bcm2048_set_mute(bdev, BCM2048_DEFAULT_MUTE); - if (err < 0) - goto unlock; - - err = bcm2048_set_region(bdev, BCM2048_DEFAULT_REGION); - if (err < 0) - goto unlock; - - err = bcm2048_set_fm_search_rssi_threshold(bdev, - BCM2048_DEFAULT_RSSI_THRESHOLD); - if (err < 0) - goto unlock; - - err = bcm2048_set_fm_automatic_stereo_mono(bdev, BCM2048_ITEM_ENABLED); - if (err < 0) - goto unlock; - - err = bcm2048_get_rds_wline(bdev); - if (err < BCM2048_DEFAULT_RDS_WLINE) - err = bcm2048_set_rds_wline(bdev, BCM2048_DEFAULT_RDS_WLINE); - if (err < 0) - goto unlock; - - err = bcm2048_set_power_state(bdev, BCM2048_POWER_OFF); - - init_waitqueue_head(&bdev->read_queue); - bdev->rds_data_available = 0; - bdev->rd_index = 0; - bdev->users = 0; - -unlock: - return err; -} - -/* - * BCM2048 workqueue handler - */ -static void bcm2048_work(struct work_struct *work) -{ - struct bcm2048_device *bdev; - u8 flag_lsb = 0, flag_msb = 0, flags; - - bdev = container_of(work, struct bcm2048_device, work); - bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG0, &flag_lsb); - bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG1, &flag_msb); - - if (flag_lsb & (BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED | - BCM2048_FM_FLAG_SEARCH_TUNE_FAIL)) { - if (flag_lsb & BCM2048_FM_FLAG_SEARCH_TUNE_FAIL) - bdev->scan_state = BCM2048_SCAN_FAIL; - else - bdev->scan_state = BCM2048_SCAN_OK; - - complete(&bdev->compl); - } - - if (flag_msb & BCM2048_RDS_FLAG_FIFO_WLINE) { - bcm2048_rds_fifo_receive(bdev); - if (bdev->rds_state) { - flags = BCM2048_RDS_FLAG_FIFO_WLINE; - bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1, - flags); - } - bdev->rds_data_available = 1; - bdev->rd_index = 0; /* new data, new start */ - } -} - -/* - * BCM2048 interrupt handler - */ -static irqreturn_t bcm2048_handler(int irq, void *dev) -{ - struct bcm2048_device *bdev = dev; - - dev_dbg(&bdev->client->dev, "IRQ called, queuing work\n"); - if (bdev->power_state) - schedule_work(&bdev->work); - - return IRQ_HANDLED; -} - -/* - * BCM2048 sysfs interface definitions - */ -#define property_write(prop, type, mask, check) \ -static ssize_t bcm2048_##prop##_write(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, \ - size_t count) \ -{ \ - struct bcm2048_device *bdev = dev_get_drvdata(dev); \ - type value; \ - int err; \ - \ - if (!bdev) \ - return -ENODEV; \ - \ - if (sscanf(buf, mask, &value) != 1) \ - return -EINVAL; \ - \ - if (check) \ - return -EDOM; \ - \ - err = bcm2048_set_##prop(bdev, value); \ - \ - return err < 0 ? err : count; \ -} - -#define property_read(prop, mask) \ -static ssize_t bcm2048_##prop##_read(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct bcm2048_device *bdev = dev_get_drvdata(dev); \ - int value; \ - \ - if (!bdev) \ - return -ENODEV; \ - \ - value = bcm2048_get_##prop(bdev); \ - \ - if (value >= 0) \ - value = sprintf(buf, mask "\n", value); \ - \ - return value; \ -} - -#define property_signed_read(prop, size, mask) \ -static ssize_t bcm2048_##prop##_read(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct bcm2048_device *bdev = dev_get_drvdata(dev); \ - size value; \ - \ - if (!bdev) \ - return -ENODEV; \ - \ - value = bcm2048_get_##prop(bdev); \ - \ - return sprintf(buf, mask "\n", value); \ -} - -#define DEFINE_SYSFS_PROPERTY(prop, prop_type, mask, check) \ -property_write(prop, prop_type, mask, check) \ -property_read(prop, mask) \ - -#define property_str_read(prop, size) \ -static ssize_t bcm2048_##prop##_read(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct bcm2048_device *bdev = dev_get_drvdata(dev); \ - int count; \ - u8 *out; \ - \ - if (!bdev) \ - return -ENODEV; \ - \ - out = kzalloc((size) + 1, GFP_KERNEL); \ - if (!out) \ - return -ENOMEM; \ - \ - bcm2048_get_##prop(bdev, out); \ - count = sprintf(buf, "%s\n", out); \ - \ - kfree(out); \ - \ - return count; \ -} - -DEFINE_SYSFS_PROPERTY(power_state, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(mute, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(audio_route, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(dac_output, unsigned int, "%u", 0) - -DEFINE_SYSFS_PROPERTY(fm_hi_lo_injection, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_frequency, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_af_frequency, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_deemphasis, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_rds_mask, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_best_tune_mode, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_search_rssi_threshold, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_search_mode_direction, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_search_tune_mode, unsigned int, "%u", value > 3) - -DEFINE_SYSFS_PROPERTY(rds, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(rds_b_block_mask, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(rds_b_block_match, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(rds_pi_mask, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(rds_pi_match, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(rds_wline, unsigned int, "%u", 0) -property_read(rds_pi, "%x") -property_str_read(rds_rt, (BCM2048_MAX_RDS_RT + 1)) -property_str_read(rds_ps, (BCM2048_MAX_RDS_PS + 1)) - -property_read(fm_rds_flags, "%u") -property_str_read(rds_data, BCM2048_MAX_RDS_RADIO_TEXT * 5) - -property_read(region_bottom_frequency, "%u") -property_read(region_top_frequency, "%u") -property_signed_read(fm_carrier_error, int, "%d") -property_signed_read(fm_rssi, int, "%d") -DEFINE_SYSFS_PROPERTY(region, unsigned int, "%u", 0) - -static struct device_attribute attrs[] = { - __ATTR(power_state, 0644, bcm2048_power_state_read, - bcm2048_power_state_write), - __ATTR(mute, 0644, bcm2048_mute_read, - bcm2048_mute_write), - __ATTR(audio_route, 0644, bcm2048_audio_route_read, - bcm2048_audio_route_write), - __ATTR(dac_output, 0644, bcm2048_dac_output_read, - bcm2048_dac_output_write), - __ATTR(fm_hi_lo_injection, 0644, - bcm2048_fm_hi_lo_injection_read, - bcm2048_fm_hi_lo_injection_write), - __ATTR(fm_frequency, 0644, bcm2048_fm_frequency_read, - bcm2048_fm_frequency_write), - __ATTR(fm_af_frequency, 0644, - bcm2048_fm_af_frequency_read, - bcm2048_fm_af_frequency_write), - __ATTR(fm_deemphasis, 0644, bcm2048_fm_deemphasis_read, - bcm2048_fm_deemphasis_write), - __ATTR(fm_rds_mask, 0644, bcm2048_fm_rds_mask_read, - bcm2048_fm_rds_mask_write), - __ATTR(fm_best_tune_mode, 0644, - bcm2048_fm_best_tune_mode_read, - bcm2048_fm_best_tune_mode_write), - __ATTR(fm_search_rssi_threshold, 0644, - bcm2048_fm_search_rssi_threshold_read, - bcm2048_fm_search_rssi_threshold_write), - __ATTR(fm_search_mode_direction, 0644, - bcm2048_fm_search_mode_direction_read, - bcm2048_fm_search_mode_direction_write), - __ATTR(fm_search_tune_mode, 0644, - bcm2048_fm_search_tune_mode_read, - bcm2048_fm_search_tune_mode_write), - __ATTR(rds, 0644, bcm2048_rds_read, - bcm2048_rds_write), - __ATTR(rds_b_block_mask, 0644, - bcm2048_rds_b_block_mask_read, - bcm2048_rds_b_block_mask_write), - __ATTR(rds_b_block_match, 0644, - bcm2048_rds_b_block_match_read, - bcm2048_rds_b_block_match_write), - __ATTR(rds_pi_mask, 0644, bcm2048_rds_pi_mask_read, - bcm2048_rds_pi_mask_write), - __ATTR(rds_pi_match, 0644, bcm2048_rds_pi_match_read, - bcm2048_rds_pi_match_write), - __ATTR(rds_wline, 0644, bcm2048_rds_wline_read, - bcm2048_rds_wline_write), - __ATTR(rds_pi, 0444, bcm2048_rds_pi_read, NULL), - __ATTR(rds_rt, 0444, bcm2048_rds_rt_read, NULL), - __ATTR(rds_ps, 0444, bcm2048_rds_ps_read, NULL), - __ATTR(fm_rds_flags, 0444, bcm2048_fm_rds_flags_read, NULL), - __ATTR(region_bottom_frequency, 0444, - bcm2048_region_bottom_frequency_read, NULL), - __ATTR(region_top_frequency, 0444, - bcm2048_region_top_frequency_read, NULL), - __ATTR(fm_carrier_error, 0444, - bcm2048_fm_carrier_error_read, NULL), - __ATTR(fm_rssi, 0444, - bcm2048_fm_rssi_read, NULL), - __ATTR(region, 0644, bcm2048_region_read, - bcm2048_region_write), - __ATTR(rds_data, 0444, bcm2048_rds_data_read, NULL), -}; - -static int bcm2048_sysfs_unregister_properties(struct bcm2048_device *bdev, - int size) -{ - int i; - - for (i = 0; i < size; i++) - device_remove_file(&bdev->client->dev, &attrs[i]); - - return 0; -} - -static int bcm2048_sysfs_register_properties(struct bcm2048_device *bdev) -{ - int err = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(attrs); i++) { - if (device_create_file(&bdev->client->dev, &attrs[i]) != 0) { - dev_err(&bdev->client->dev, - "could not register sysfs entry\n"); - err = -EBUSY; - bcm2048_sysfs_unregister_properties(bdev, i); - break; - } - } - - return err; -} - -static int bcm2048_fops_open(struct file *file) -{ - struct bcm2048_device *bdev = video_drvdata(file); - - bdev->users++; - bdev->rd_index = 0; - bdev->rds_data_available = 0; - - return 0; -} - -static int bcm2048_fops_release(struct file *file) -{ - struct bcm2048_device *bdev = video_drvdata(file); - - bdev->users--; - - return 0; -} - -static __poll_t bcm2048_fops_poll(struct file *file, - struct poll_table_struct *pts) -{ - struct bcm2048_device *bdev = video_drvdata(file); - __poll_t retval = 0; - - poll_wait(file, &bdev->read_queue, pts); - - if (bdev->rds_data_available) - retval = EPOLLIN | EPOLLRDNORM; - - return retval; -} - -static ssize_t bcm2048_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct bcm2048_device *bdev = video_drvdata(file); - int i; - int retval = 0; - - /* we return at least 3 bytes, one block */ - count = (count / 3) * 3; /* only multiples of 3 */ - if (count < 3) - return -ENOBUFS; - - while (!bdev->rds_data_available) { - if (file->f_flags & O_NONBLOCK) { - retval = -EWOULDBLOCK; - goto done; - } - /* interruptible_sleep_on(&bdev->read_queue); */ - if (wait_event_interruptible(bdev->read_queue, - bdev->rds_data_available) < 0) { - retval = -EINTR; - goto done; - } - } - - mutex_lock(&bdev->mutex); - /* copy data to userspace */ - i = bdev->fifo_size - bdev->rd_index; - if (count > i) - count = (i / 3) * 3; - - i = 0; - while (i < count) { - unsigned char tmpbuf[3]; - - tmpbuf[i] = bdev->rds_info.radio_text[bdev->rd_index + i + 2]; - tmpbuf[i + 1] = - bdev->rds_info.radio_text[bdev->rd_index + i + 1]; - tmpbuf[i + 2] = - (bdev->rds_info.radio_text[bdev->rd_index + i] & - 0xf0) >> 4; - if ((bdev->rds_info.radio_text[bdev->rd_index + i] & - BCM2048_RDS_CRC_MASK) == BCM2048_RDS_CRC_UNRECOVARABLE) - tmpbuf[i + 2] |= 0x80; - if (copy_to_user(buf + i, tmpbuf, 3)) { - retval = -EFAULT; - break; - } - i += 3; - } - - bdev->rd_index += i; - if (bdev->rd_index >= bdev->fifo_size) - bdev->rds_data_available = 0; - - mutex_unlock(&bdev->mutex); - if (retval == 0) - retval = i; - -done: - return retval; -} - -/* - * bcm2048_fops - file operations interface - */ -static const struct v4l2_file_operations bcm2048_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, - /* for RDS read support */ - .open = bcm2048_fops_open, - .release = bcm2048_fops_release, - .read = bcm2048_fops_read, - .poll = bcm2048_fops_poll -}; - -/* - * Video4Linux Interface - */ -static struct v4l2_queryctrl bcm2048_v4l2_queryctrl[] = { - { - .id = V4L2_CID_AUDIO_VOLUME, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_BALANCE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_BASS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_TREBLE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_MUTE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_AUDIO_LOUDNESS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, -}; - -static int bcm2048_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - - strscpy(capability->driver, BCM2048_DRIVER_NAME, - sizeof(capability->driver)); - strscpy(capability->card, BCM2048_DRIVER_CARD, - sizeof(capability->card)); - snprintf(capability->bus_info, 32, "I2C: 0x%X", bdev->client->addr); - return 0; -} - -static int bcm2048_vidioc_g_input(struct file *filp, void *priv, - unsigned int *i) -{ - *i = 0; - - return 0; -} - -static int bcm2048_vidioc_s_input(struct file *filp, void *priv, - unsigned int i) -{ - if (i) - return -EINVAL; - - return 0; -} - -static int bcm2048_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bcm2048_v4l2_queryctrl); i++) { - if (qc->id && qc->id == bcm2048_v4l2_queryctrl[i].id) { - *qc = bcm2048_v4l2_queryctrl[i]; - return 0; - } - } - - return -EINVAL; -} - -static int bcm2048_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - int err = 0; - - if (!bdev) - return -ENODEV; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - err = bcm2048_get_mute(bdev); - if (err >= 0) - ctrl->value = err; - break; - } - - return err; -} - -static int bcm2048_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - int err = 0; - - if (!bdev) - return -ENODEV; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) { - if (bdev->power_state) { - err = bcm2048_set_mute(bdev, ctrl->value); - err |= bcm2048_deinit(bdev); - } - } else { - if (!bdev->power_state) { - err = bcm2048_init(bdev); - err |= bcm2048_set_mute(bdev, ctrl->value); - } - } - break; - } - - return err; -} - -static int bcm2048_vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - if (audio->index > 1) - return -EINVAL; - - strscpy(audio->name, "Radio", sizeof(audio->name)); - audio->capability = V4L2_AUDCAP_STEREO; - - return 0; -} - -static int bcm2048_vidioc_s_audio(struct file *file, void *priv, - const struct v4l2_audio *audio) -{ - if (audio->index != 0) - return -EINVAL; - - return 0; -} - -static int bcm2048_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - s8 f_error; - s8 rssi; - - if (!bdev) - return -ENODEV; - - if (tuner->index > 0) - return -EINVAL; - - strscpy(tuner->name, "FM Receiver", sizeof(tuner->name)); - tuner->type = V4L2_TUNER_RADIO; - tuner->rangelow = - dev_to_v4l2(bcm2048_get_region_bottom_frequency(bdev)); - tuner->rangehigh = - dev_to_v4l2(bcm2048_get_region_top_frequency(bdev)); - tuner->rxsubchans = V4L2_TUNER_SUB_STEREO; - tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; - tuner->audmode = V4L2_TUNER_MODE_STEREO; - tuner->afc = 0; - if (bdev->power_state) { - /* - * Report frequencies with high carrier errors to have zero - * signal level - */ - f_error = bcm2048_get_fm_carrier_error(bdev); - if (f_error < BCM2048_FREQ_ERROR_FLOOR || - f_error > BCM2048_FREQ_ERROR_ROOF) { - tuner->signal = 0; - } else { - /* - * RSSI level -60 dB is defined to report full - * signal strength - */ - rssi = bcm2048_get_fm_rssi(bdev); - if (rssi >= BCM2048_RSSI_LEVEL_BASE) { - tuner->signal = 0xFFFF; - } else if (rssi > BCM2048_RSSI_LEVEL_ROOF) { - tuner->signal = (rssi + - BCM2048_RSSI_LEVEL_ROOF_NEG) - * BCM2048_SIGNAL_MULTIPLIER; - } else { - tuner->signal = 0; - } - } - } else { - tuner->signal = 0; - } - - return 0; -} - -static int bcm2048_vidioc_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *tuner) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - - if (!bdev) - return -ENODEV; - - if (tuner->index > 0) - return -EINVAL; - - return 0; -} - -static int bcm2048_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - int err = 0; - int f; - - if (!bdev->power_state) - return -ENODEV; - - freq->type = V4L2_TUNER_RADIO; - f = bcm2048_get_fm_frequency(bdev); - - if (f < 0) - err = f; - else - freq->frequency = dev_to_v4l2(f); - - return err; -} - -static int bcm2048_vidioc_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *freq) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - int err; - - if (freq->type != V4L2_TUNER_RADIO) - return -EINVAL; - - if (!bdev->power_state) - return -ENODEV; - - err = bcm2048_set_fm_frequency(bdev, v4l2_to_dev(freq->frequency)); - err |= bcm2048_set_fm_search_tune_mode(bdev, BCM2048_FM_PRE_SET_MODE); - - return err; -} - -static int bcm2048_vidioc_s_hw_freq_seek(struct file *file, void *priv, - const struct v4l2_hw_freq_seek *seek) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - int err; - - if (!bdev->power_state) - return -ENODEV; - - if ((seek->tuner != 0) || (seek->type != V4L2_TUNER_RADIO)) - return -EINVAL; - - err = bcm2048_set_fm_search_mode_direction(bdev, seek->seek_upward); - err |= bcm2048_set_fm_search_tune_mode(bdev, - BCM2048_FM_AUTO_SEARCH_MODE); - - return err; -} - -static const struct v4l2_ioctl_ops bcm2048_ioctl_ops = { - .vidioc_querycap = bcm2048_vidioc_querycap, - .vidioc_g_input = bcm2048_vidioc_g_input, - .vidioc_s_input = bcm2048_vidioc_s_input, - .vidioc_queryctrl = bcm2048_vidioc_queryctrl, - .vidioc_g_ctrl = bcm2048_vidioc_g_ctrl, - .vidioc_s_ctrl = bcm2048_vidioc_s_ctrl, - .vidioc_g_audio = bcm2048_vidioc_g_audio, - .vidioc_s_audio = bcm2048_vidioc_s_audio, - .vidioc_g_tuner = bcm2048_vidioc_g_tuner, - .vidioc_s_tuner = bcm2048_vidioc_s_tuner, - .vidioc_g_frequency = bcm2048_vidioc_g_frequency, - .vidioc_s_frequency = bcm2048_vidioc_s_frequency, - .vidioc_s_hw_freq_seek = bcm2048_vidioc_s_hw_freq_seek, -}; - -/* - * bcm2048_viddev_template - video device interface - */ -static const struct video_device bcm2048_viddev_template = { - .fops = &bcm2048_fops, - .name = BCM2048_DRIVER_NAME, - .release = video_device_release_empty, - .ioctl_ops = &bcm2048_ioctl_ops, - .device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | - V4L2_CAP_HW_FREQ_SEEK, -}; - -/* - * I2C driver interface - */ -static int bcm2048_i2c_driver_probe(struct i2c_client *client) -{ - struct bcm2048_device *bdev; - int err; - - bdev = kzalloc(sizeof(*bdev), GFP_KERNEL); - if (!bdev) { - err = -ENOMEM; - goto exit; - } - - bdev->client = client; - i2c_set_clientdata(client, bdev); - mutex_init(&bdev->mutex); - init_completion(&bdev->compl); - INIT_WORK(&bdev->work, bcm2048_work); - - if (client->irq) { - err = request_irq(client->irq, - bcm2048_handler, IRQF_TRIGGER_FALLING, - client->name, bdev); - if (err < 0) { - dev_err(&client->dev, "Could not request IRQ\n"); - goto free_bdev; - } - dev_dbg(&client->dev, "IRQ requested.\n"); - } else { - dev_dbg(&client->dev, "IRQ not configured. Using timeouts.\n"); - } - - bdev->videodev = bcm2048_viddev_template; - video_set_drvdata(&bdev->videodev, bdev); - if (video_register_device(&bdev->videodev, VFL_TYPE_RADIO, radio_nr)) { - dev_dbg(&client->dev, "Could not register video device.\n"); - err = -EIO; - goto free_irq; - } - - err = bcm2048_sysfs_register_properties(bdev); - if (err < 0) { - dev_dbg(&client->dev, "Could not register sysfs interface.\n"); - goto free_registration; - } - - err = bcm2048_probe(bdev); - if (err < 0) { - dev_dbg(&client->dev, "Failed to probe device information.\n"); - goto free_sysfs; - } - - return 0; - -free_sysfs: - bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs)); -free_registration: - video_unregister_device(&bdev->videodev); -free_irq: - if (client->irq) - free_irq(client->irq, bdev); -free_bdev: - i2c_set_clientdata(client, NULL); - kfree(bdev); -exit: - return err; -} - -static int bcm2048_i2c_driver_remove(struct i2c_client *client) -{ - struct bcm2048_device *bdev = i2c_get_clientdata(client); - - if (!client->adapter) - return -ENODEV; - - if (bdev) { - bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs)); - video_unregister_device(&bdev->videodev); - - if (bdev->power_state) - bcm2048_set_power_state(bdev, BCM2048_POWER_OFF); - - if (client->irq > 0) - free_irq(client->irq, bdev); - - cancel_work_sync(&bdev->work); - - kfree(bdev); - } - - return 0; -} - -/* - * bcm2048_i2c_driver - i2c driver interface - */ -static const struct i2c_device_id bcm2048_id[] = { - { "bcm2048", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, bcm2048_id); - -static struct i2c_driver bcm2048_i2c_driver = { - .driver = { - .name = BCM2048_DRIVER_NAME, - }, - .probe_new = bcm2048_i2c_driver_probe, - .remove = bcm2048_i2c_driver_remove, - .id_table = bcm2048_id, -}; - -module_i2c_driver(bcm2048_i2c_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR(BCM2048_DRIVER_AUTHOR); -MODULE_DESCRIPTION(BCM2048_DRIVER_DESC); -MODULE_VERSION("0.0.2"); diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.h b/drivers/staging/media/bcm2048/radio-bcm2048.h deleted file mode 100644 index 22887a075257..000000000000 --- a/drivers/staging/media/bcm2048/radio-bcm2048.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * drivers/staging/media/radio-bcm2048.h - * - * Property and command definitions for bcm2048 radio receiver chip. - * - * Copyright (C) Nokia Corporation - * Contact: Eero Nurkkala <ext-eero.nurkkala@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef BCM2048_H -#define BCM2048_H - -#define BCM2048_NAME "bcm2048" -#define BCM2048_I2C_ADDR 0x22 - -#endif /* ifndef BCM2048_H */ diff --git a/drivers/staging/media/davinci_vpfe/Kconfig b/drivers/staging/media/davinci_vpfe/Kconfig deleted file mode 100644 index 94bf6746c03f..000000000000 --- a/drivers/staging/media/davinci_vpfe/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config VIDEO_DM365_VPFE - tristate "DM365 VPFE Media Controller Capture Driver" - depends on VIDEO_V4L2 - depends on (ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF) || (COMPILE_TEST && !ARCH_OMAP1) - depends on VIDEO_V4L2_SUBDEV_API - depends on VIDEO_DAVINCI_VPBE_DISPLAY - select VIDEOBUF2_DMA_CONTIG - help - Support for DM365 VPFE based Media Controller Capture driver. - - To compile this driver as a module, choose M here: the - module will be called vpfe-mc-capture. diff --git a/drivers/staging/media/davinci_vpfe/Makefile b/drivers/staging/media/davinci_vpfe/Makefile deleted file mode 100644 index 0ae8c5014f74..000000000000 --- a/drivers/staging/media/davinci_vpfe/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci-vfpe.o - -davinci-vfpe-objs := \ - dm365_isif.o dm365_ipipe_hw.o dm365_ipipe.o \ - dm365_resizer.o dm365_ipipeif.o vpfe_mc_capture.o vpfe_video.o - -# Allow building it with COMPILE_TEST on other archs -ifndef CONFIG_ARCH_DAVINCI -ccflags-y += -I $(srctree)/arch/arm/mach-davinci/include/ -endif diff --git a/drivers/staging/media/davinci_vpfe/TODO b/drivers/staging/media/davinci_vpfe/TODO deleted file mode 100644 index cc8bd9306f2a..000000000000 --- a/drivers/staging/media/davinci_vpfe/TODO +++ /dev/null @@ -1,38 +0,0 @@ -TODO (general): -================================== - -- User space interface refinement - - Controls should be used when possible rather than private ioctl - - No enums should be used - - Use of MC and V4L2 subdev APIs when applicable - - Single interface header might suffice - - Current interface forces to configure everything at once -- Get rid of the dm365_ipipe_hw.[ch] layer -- Active external sub-devices defined by link configuration; no strcmp - needed -- More generic platform data (i2c adapters) -- The driver should have no knowledge of possible external subdevs; see - struct vpfe_subdev_id -- Some of the hardware control should be refactorede -- Check proper serialisation (through mutexes and spinlocks) -- Names that are visible in kernel global namespace should have a common - prefix (or a few) -- While replacing the older driver in media folder, provide a compatibility - layer and compatibility tests that warrants (using the libv4l's LD_PRELOAD - approach) there is no regression for the users using the older driver. -- make it independent of arch-specific APIs (mach/mux.h). - -Building of uImage and Applications: -================================== - -As of now since the interface will undergo few changes all the include -files are present in staging itself, to build for dm365 follow below steps, - -- copy vpfe.h from drivers/staging/media/davinci_vpfe/ to - include/media/davinci/ folder for building the uImage. -- copy davinci_vpfe_user.h from drivers/staging/media/davinci_vpfe/ to - include/uapi/linux/davinci_vpfe.h, and add a entry in Kbuild (required - for building application). -- copy dm365_ipipeif_user.h from drivers/staging/media/davinci_vpfe/ to - include/uapi/linux/dm365_ipipeif.h and a entry in Kbuild (required - for building application). diff --git a/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt b/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt deleted file mode 100644 index a1e91778aa9b..000000000000 --- a/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt +++ /dev/null @@ -1,154 +0,0 @@ -Davinci Video processing Front End (VPFE) driver - -Copyright (C) 2012 Texas Instruments Inc - -Contacts: Manjunath Hadli <manjunath.hadli@ti.com> - Prabhakar Lad <prabhakar.lad@ti.com> - - -Introduction -============ - -This file documents the Texas Instruments Davinci Video processing Front End -(VPFE) driver located under drivers/media/platform/davinci. The original driver -exists for Davinci VPFE, which is now being changed to Media Controller -Framework. - -Currently the driver has been successfully used on the following -version of Davinci: - - DM365/DM368 - -The driver implements V4L2, Media controller and v4l2_subdev interfaces. Sensor, -lens and flash drivers using the v4l2_subdev interface in the kernel are -supported. - - -Split to subdevs -================ - -The Davinci VPFE is split into V4L2 subdevs, each of the blocks inside the VPFE -having one subdev to represent it. Each of the subdevs provide a V4L2 subdev -interface to userspace. - - DAVINCI ISIF - DAVINCI IPIPEIF - DAVINCI IPIPE - DAVINCI CROP RESIZER - DAVINCI RESIZER A - DAVINCI RESIZER B - -Each possible link in the VPFE is modelled by a link in the Media controller -interface. For an example program see [1]. - - -ISIF, IPIPE, and RESIZER block IOCTLs -====================================== - -The Davinci Video processing Front End (VPFE) driver supports standard V4L2 -IOCTLs and controls where possible and practical. Much of the functions provided -by the VPFE, however, does not fall under the standard IOCTL's. - -In general, there is a private ioctl for configuring each of the blocks -containing hardware-dependent functions. - -The following private IOCTLs are supported: - - VIDIOC_VPFE_ISIF_[S/G]_RAW_PARAMS - VIDIOC_VPFE_IPIPE_[S/G]_CONFIG - VIDIOC_VPFE_RSZ_[S/G]_CONFIG - -The parameter structures used by these ioctl's are described in -include/uapi/linux/davinci_vpfe.h. - -The VIDIOC_VPFE_ISIF_S_RAW_PARAMS, VIDIOC_VPFE_IPIPE_S_CONFIG and -VIDIOC_VPFE_RSZ_S_CONFIG are used to configure, enable and disable functions in -the isif, ipipe and resizer blocks respectively. These IOCTL's control several -functions in the blocks they control. VIDIOC_VPFE_ISIF_S_RAW_PARAMS IOCTL -accepts a pointer to struct vpfe_isif_raw_config as its argument. Similarly -VIDIOC_VPFE_IPIPE_S_CONFIG accepts a pointer to struct vpfe_ipipe_config. And -VIDIOC_VPFE_RSZ_S_CONFIG accepts a pointer to struct vpfe_rsz_config as its -argument. Similarly VIDIOC_VPFE_ISIF_G_RAW_PARAMS, VIDIOC_VPFE_IPIPE_G_CONFIG -and VIDIOC_VPFE_RSZ_G_CONFIG are used to get the current configuration set in -the isif, ipipe and resizer blocks respectively. - -The detailed functions of the VPFE itself related to a given VPFE block is -described in the Technical Reference Manuals (TRMs) --- see the end of the -document for those. - - -IPIPEIF block IOCTLs -====================================== - -The following private IOCTLs are supported: - - VIDIOC_VPFE_IPIPEIF_[S/G]_CONFIG - -The parameter structures used by these ioctl's are described in -include/uapi/linux/dm365_ipipeif.h - -The VIDIOC_VPFE_IPIPEIF_S_CONFIG is used to configure the ipipeif -hardware block. The VIDIOC_VPFE_IPIPEIF_S_CONFIG and -VIDIOC_VPFE_IPIPEIF_G_CONFIG accepts a pointer to struct ipipeif_params -as its argument. - - -VPFE Operating Modes -========================================== - -a: Continuous Modes ------------------------- - -1: tvp514x/tvp7002/mt9p031---> DAVINCI ISIF---> SDRAM - -2: tvp514x/tvp7002/mt9p031---> DAVINCI ISIF---> DAVINCI IPIPEIF--->| - | - <--------------------<----------------<---------------------<---| - | - V - DAVINCI CROP RESIZER--->DAVINCI RESIZER [A/B]---> SDRAM - -3: tvp514x/tvp7002/mt9p031---> DAVINCI ISIF---> DAVINCI IPIPEIF--->| - | - <--------------------<----------------<---------------------<---| - | - V - DAVINCI IPIPE---> DAVINCI CROP RESIZER--->DAVINCI RESIZER [A/B]---> SDRAM - -a: Single Shot Modes ------------------------- - -1: SDRAM---> DAVINCI IPIPEIF---> DAVINCI IPIPE---> DAVINCI CROP RESIZER--->| - | - <----------------<----------------<------------------<---------------<--| - | - V -DAVINCI RESIZER [A/B]---> SDRAM - -2: SDRAM---> DAVINCI IPIPEIF---> DAVINCI CROP RESIZER--->| - | - <----------------<----------------<---------------<---| - | - V -DAVINCI RESIZER [A/B]---> SDRAM - - -Technical reference manuals (TRMs) and other documentation -========================================================== - -Davinci DM365 TRM: -<URL:http://www.ti.com/lit/ds/sprs457e/sprs457e.pdf> -Referenced MARCH 2009-REVISED JUNE 2011 - -Davinci DM368 TRM: -<URL:http://www.ti.com/lit/ds/sprs668c/sprs668c.pdf> -Referenced APRIL 2010-REVISED JUNE 2011 - -Davinci Video Processing Front End (VPFE) DM36x -<URL:http://www.ti.com/lit/ug/sprufg8c/sprufg8c.pdf> - - -References -========== - -[1] http://git.ideasonboard.org/?p=media-ctl.git;a=summary diff --git a/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h b/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h deleted file mode 100644 index 8d772029c91d..000000000000 --- a/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h +++ /dev/null @@ -1,1287 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#ifndef _DAVINCI_VPFE_USER_H -#define _DAVINCI_VPFE_USER_H - -#include <linux/types.h> -#include <linux/videodev2.h> - -/* - * Private IOCTL - * - * VIDIOC_VPFE_ISIF_S_RAW_PARAMS: Set raw params in isif - * VIDIOC_VPFE_ISIF_G_RAW_PARAMS: Get raw params from isif - * VIDIOC_VPFE_PRV_S_CONFIG: Set ipipe engine configuration - * VIDIOC_VPFE_PRV_G_CONFIG: Get ipipe engine configuration - * VIDIOC_VPFE_RSZ_S_CONFIG: Set resizer engine configuration - * VIDIOC_VPFE_RSZ_G_CONFIG: Get resizer engine configuration - */ - -#define VIDIOC_VPFE_ISIF_S_RAW_PARAMS \ - _IOW('V', BASE_VIDIOC_PRIVATE + 1, struct vpfe_isif_raw_config) -#define VIDIOC_VPFE_ISIF_G_RAW_PARAMS \ - _IOR('V', BASE_VIDIOC_PRIVATE + 2, struct vpfe_isif_raw_config) -#define VIDIOC_VPFE_IPIPE_S_CONFIG \ - _IOWR('P', BASE_VIDIOC_PRIVATE + 3, struct vpfe_ipipe_config) -#define VIDIOC_VPFE_IPIPE_G_CONFIG \ - _IOWR('P', BASE_VIDIOC_PRIVATE + 4, struct vpfe_ipipe_config) -#define VIDIOC_VPFE_RSZ_S_CONFIG \ - _IOWR('R', BASE_VIDIOC_PRIVATE + 5, struct vpfe_rsz_config) -#define VIDIOC_VPFE_RSZ_G_CONFIG \ - _IOWR('R', BASE_VIDIOC_PRIVATE + 6, struct vpfe_rsz_config) - -/* - * Private Control's for ISIF - */ -#define VPFE_ISIF_CID_CRGAIN (V4L2_CID_USER_BASE | 0xa001) -#define VPFE_ISIF_CID_CGRGAIN (V4L2_CID_USER_BASE | 0xa002) -#define VPFE_ISIF_CID_CGBGAIN (V4L2_CID_USER_BASE | 0xa003) -#define VPFE_ISIF_CID_CBGAIN (V4L2_CID_USER_BASE | 0xa004) -#define VPFE_ISIF_CID_GAIN_OFFSET (V4L2_CID_USER_BASE | 0xa005) - -/* - * Private Control's for ISIF and IPIPEIF - */ -#define VPFE_CID_DPCM_PREDICTOR (V4L2_CID_USER_BASE | 0xa006) - -/************************************************************************ - * Vertical Defect Correction parameters - ***********************************************************************/ - -/** - * vertical defect correction methods - */ -enum vpfe_isif_vdfc_corr_mode { - /* Defect level subtraction. Just fed through if saturating */ - VPFE_ISIF_VDFC_NORMAL, - /** - * Defect level subtraction. Horizontal interpolation ((i-2)+(i+2))/2 - * if data saturating - */ - VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT, - /* Horizontal interpolation (((i-2)+(i+2))/2) */ - VPFE_ISIF_VDFC_HORZ_INTERPOL -}; - -/** - * Max Size of the Vertical Defect Correction table - */ -#define VPFE_ISIF_VDFC_TABLE_SIZE 8 - -/** - * Values used for shifting up the vdfc defect level - */ -enum vpfe_isif_vdfc_shift { - /* No Shift */ - VPFE_ISIF_VDFC_NO_SHIFT, - /* Shift by 1 bit */ - VPFE_ISIF_VDFC_SHIFT_1, - /* Shift by 2 bit */ - VPFE_ISIF_VDFC_SHIFT_2, - /* Shift by 3 bit */ - VPFE_ISIF_VDFC_SHIFT_3, - /* Shift by 4 bit */ - VPFE_ISIF_VDFC_SHIFT_4 -}; - -/** - * Defect Correction (DFC) table entry - */ -struct vpfe_isif_vdfc_entry { - /* vertical position of defect */ - unsigned short pos_vert; - /* horizontal position of defect */ - unsigned short pos_horz; - /** - * Defect level of Vertical line defect position. This is subtracted - * from the data at the defect position - */ - unsigned char level_at_pos; - /** - * Defect level of the pixels upper than the vertical line defect. - * This is subtracted from the data - */ - unsigned char level_up_pixels; - /** - * Defect level of the pixels lower than the vertical line defect. - * This is subtracted from the data - */ - unsigned char level_low_pixels; -}; - -/** - * Structure for Defect Correction (DFC) parameter - */ -struct vpfe_isif_dfc { - /* enable vertical defect correction */ - unsigned char en; - /* Correction methods */ - enum vpfe_isif_vdfc_corr_mode corr_mode; - /** - * 0 - whole line corrected, 1 - not - * pixels upper than the defect - */ - unsigned char corr_whole_line; - /** - * defect level shift value. level_at_pos, level_upper_pos, - * and level_lower_pos can be shifted up by this value - */ - enum vpfe_isif_vdfc_shift def_level_shift; - /* defect saturation level */ - unsigned short def_sat_level; - /* number of vertical defects. Max is VPFE_ISIF_VDFC_TABLE_SIZE */ - short num_vdefects; - /* VDFC table ptr */ - struct vpfe_isif_vdfc_entry table[VPFE_ISIF_VDFC_TABLE_SIZE]; -}; - -/************************************************************************ - * Digital/Black clamp or DC Subtract parameters - ************************************************************************/ -/** - * Horizontal Black Clamp modes - */ -enum vpfe_isif_horz_bc_mode { - /** - * Horizontal clamp disabled. Only vertical clamp - * value is subtracted - */ - VPFE_ISIF_HORZ_BC_DISABLE, - /** - * Horizontal clamp value is calculated and subtracted - * from image data along with vertical clamp value - */ - VPFE_ISIF_HORZ_BC_CLAMP_CALC_ENABLED, - /** - * Horizontal clamp value calculated from previous image - * is subtracted from image data along with vertical clamp - * value. How the horizontal clamp value for the first image - * is calculated in this case ??? - */ - VPFE_ISIF_HORZ_BC_CLAMP_NOT_UPDATED -}; - -/** - * Base window selection for Horizontal Black Clamp calculations - */ -enum vpfe_isif_horz_bc_base_win_sel { - /* Select Most left window for bc calculation */ - VPFE_ISIF_SEL_MOST_LEFT_WIN, - - /* Select Most right window for bc calculation */ - VPFE_ISIF_SEL_MOST_RIGHT_WIN, -}; - -/* Size of window in horizontal direction for horizontal bc */ -enum vpfe_isif_horz_bc_sz_h { - VPFE_ISIF_HORZ_BC_SZ_H_2PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_4PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_8PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_16PIXELS -}; - -/* Size of window in vertcal direction for vertical bc */ -enum vpfe_isif_horz_bc_sz_v { - VPFE_ISIF_HORZ_BC_SZ_H_32PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_64PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_128PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_256PIXELS -}; - -/** - * Structure for Horizontal Black Clamp config params - */ -struct vpfe_isif_horz_bclamp { - /* horizontal clamp mode */ - enum vpfe_isif_horz_bc_mode mode; - /** - * pixel value limit enable. - * 0 - limit disabled - * 1 - pixel value limited to 1023 - */ - unsigned char clamp_pix_limit; - /** - * Select most left or right window for clamp val - * calculation - */ - enum vpfe_isif_horz_bc_base_win_sel base_win_sel_calc; - /* Window count per color for calculation. range 1-32 */ - unsigned char win_count_calc; - /* Window start position - horizontal for calculation. 0 - 8191 */ - unsigned short win_start_h_calc; - /* Window start position - vertical for calculation 0 - 8191 */ - unsigned short win_start_v_calc; - /* Width of the sample window in pixels for calculation */ - enum vpfe_isif_horz_bc_sz_h win_h_sz_calc; - /* Height of the sample window in pixels for calculation */ - enum vpfe_isif_horz_bc_sz_v win_v_sz_calc; -}; - -/** - * Black Clamp vertical reset values - */ -enum vpfe_isif_vert_bc_reset_val_sel { - /* Reset value used is the clamp value calculated */ - VPFE_ISIF_VERT_BC_USE_HORZ_CLAMP_VAL, - /* Reset value used is reset_clamp_val configured */ - VPFE_ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL, - /* No update, previous image value is used */ - VPFE_ISIF_VERT_BC_NO_UPDATE -}; - -enum vpfe_isif_vert_bc_sz_h { - VPFE_ISIF_VERT_BC_SZ_H_2PIXELS, - VPFE_ISIF_VERT_BC_SZ_H_4PIXELS, - VPFE_ISIF_VERT_BC_SZ_H_8PIXELS, - VPFE_ISIF_VERT_BC_SZ_H_16PIXELS, - VPFE_ISIF_VERT_BC_SZ_H_32PIXELS, - VPFE_ISIF_VERT_BC_SZ_H_64PIXELS -}; - -/** - * Structure for Vertical Black Clamp configuration params - */ -struct vpfe_isif_vert_bclamp { - /* Reset value selection for vertical clamp calculation */ - enum vpfe_isif_vert_bc_reset_val_sel reset_val_sel; - /* U12 value if reset_sel = ISIF_BC_VERT_USE_CONFIG_CLAMP_VAL */ - unsigned short reset_clamp_val; - /** - * U8Q8. Line average coefficient used in vertical clamp - * calculation - */ - unsigned char line_ave_coef; - /* Width in pixels of the optical black region used for calculation. */ - enum vpfe_isif_vert_bc_sz_h ob_h_sz_calc; - /* Height of the optical black region for calculation */ - unsigned short ob_v_sz_calc; - /* Optical black region start position - horizontal. 0 - 8191 */ - unsigned short ob_start_h; - /* Optical black region start position - vertical 0 - 8191 */ - unsigned short ob_start_v; -}; - -/** - * Structure for Black Clamp configuration params - */ -struct vpfe_isif_black_clamp { - /** - * this offset value is added irrespective of the clamp - * enable status. S13 - */ - unsigned short dc_offset; - /** - * Enable black/digital clamp value to be subtracted - * from the image data - */ - unsigned char en; - /** - * black clamp mode. same/separate clamp for 4 colors - * 0 - disable - same clamp value for all colors - * 1 - clamp value calculated separately for all colors - */ - unsigned char bc_mode_color; - /* Vertical start position for bc subtraction */ - unsigned short vert_start_sub; - /* Black clamp for horizontal direction */ - struct vpfe_isif_horz_bclamp horz; - /* Black clamp for vertical direction */ - struct vpfe_isif_vert_bclamp vert; -}; - -/************************************************************************* - ** Color Space Conversion (CSC) - *************************************************************************/ -/** - * Number of Coefficient values used for CSC - */ -#define VPFE_ISIF_CSC_NUM_COEFF 16 - -struct float_8_bit { - /* 8 bit integer part */ - __u8 integer; - /* 8 bit decimal part */ - __u8 decimal; -}; - -struct float_16_bit { - /* 16 bit integer part */ - __u16 integer; - /* 16 bit decimal part */ - __u16 decimal; -}; - -/************************************************************************* - ** Color Space Conversion parameters - *************************************************************************/ -/** - * Structure used for CSC config params - */ -struct vpfe_isif_color_space_conv { - /* Enable color space conversion */ - unsigned char en; - /** - * csc coefficient table. S8Q5, M00 at index 0, M01 at index 1, and - * so forth - */ - struct float_8_bit coeff[VPFE_ISIF_CSC_NUM_COEFF]; -}; - -enum vpfe_isif_datasft { - /* No Shift */ - VPFE_ISIF_NO_SHIFT, - /* 1 bit Shift */ - VPFE_ISIF_1BIT_SHIFT, - /* 2 bit Shift */ - VPFE_ISIF_2BIT_SHIFT, - /* 3 bit Shift */ - VPFE_ISIF_3BIT_SHIFT, - /* 4 bit Shift */ - VPFE_ISIF_4BIT_SHIFT, - /* 5 bit Shift */ - VPFE_ISIF_5BIT_SHIFT, - /* 6 bit Shift */ - VPFE_ISIF_6BIT_SHIFT -}; - -#define VPFE_ISIF_LINEAR_TAB_SIZE 192 -/************************************************************************* - ** Linearization parameters - *************************************************************************/ -/** - * Structure for Sensor data linearization - */ -struct vpfe_isif_linearize { - /* Enable or Disable linearization of data */ - unsigned char en; - /* Shift value applied */ - enum vpfe_isif_datasft corr_shft; - /* scale factor applied U11Q10 */ - struct float_16_bit scale_fact; - /* Size of the linear table */ - unsigned short table[VPFE_ISIF_LINEAR_TAB_SIZE]; -}; - -/************************************************************************* - ** ISIF Raw configuration parameters - *************************************************************************/ -enum vpfe_isif_fmt_mode { - VPFE_ISIF_SPLIT, - VPFE_ISIF_COMBINE -}; - -enum vpfe_isif_lnum { - VPFE_ISIF_1LINE, - VPFE_ISIF_2LINES, - VPFE_ISIF_3LINES, - VPFE_ISIF_4LINES -}; - -enum vpfe_isif_line { - VPFE_ISIF_1STLINE, - VPFE_ISIF_2NDLINE, - VPFE_ISIF_3RDLINE, - VPFE_ISIF_4THLINE -}; - -struct vpfe_isif_fmtplen { - /** - * number of program entries for SET0, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - unsigned short plen0; - /** - * number of program entries for SET1, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - unsigned short plen1; - /** - * number of program entries for SET2, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - unsigned short plen2; - /** - * number of program entries for SET3, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - unsigned short plen3; -}; - -struct vpfe_isif_fmt_cfg { - /* Split or combine or line alternate */ - enum vpfe_isif_fmt_mode fmtmode; - /* enable or disable line alternating mode */ - unsigned char ln_alter_en; - /* Split/combine line number */ - enum vpfe_isif_lnum lnum; - /* Address increment Range 1 - 16 */ - unsigned int addrinc; -}; - -struct vpfe_isif_fmt_addr_ptr { - /* Initial address */ - unsigned int init_addr; - /* output line number */ - enum vpfe_isif_line out_line; -}; - -struct vpfe_isif_fmtpgm_ap { - /* program address pointer */ - unsigned char pgm_aptr; - /* program address increment or decrement */ - unsigned char pgmupdt; -}; - -struct vpfe_isif_data_formatter { - /* Enable/Disable data formatter */ - unsigned char en; - /* data formatter configuration */ - struct vpfe_isif_fmt_cfg cfg; - /* Formatter program entries length */ - struct vpfe_isif_fmtplen plen; - /* first pixel in a line fed to formatter */ - unsigned short fmtrlen; - /* HD interval for output line. Only valid when split line */ - unsigned short fmthcnt; - /* formatter address pointers */ - struct vpfe_isif_fmt_addr_ptr fmtaddr_ptr[16]; - /* program enable/disable */ - unsigned char pgm_en[32]; - /* program address pointers */ - struct vpfe_isif_fmtpgm_ap fmtpgm_ap[32]; -}; - -struct vpfe_isif_df_csc { - /* Color Space Conversion configuration, 0 - csc, 1 - df */ - unsigned int df_or_csc; - /* csc configuration valid if df_or_csc is 0 */ - struct vpfe_isif_color_space_conv csc; - /* data formatter configuration valid if df_or_csc is 1 */ - struct vpfe_isif_data_formatter df; - /* start pixel in a line at the input */ - unsigned int start_pix; - /* number of pixels in input line */ - unsigned int num_pixels; - /* start line at the input */ - unsigned int start_line; - /* number of lines at the input */ - unsigned int num_lines; -}; - -struct vpfe_isif_gain_offsets_adj { - /* Enable or Disable Gain adjustment for SDRAM data */ - unsigned char gain_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - unsigned char gain_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - unsigned char gain_h3a_en; - /* Enable or Disable Gain adjustment for SDRAM data */ - unsigned char offset_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - unsigned char offset_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - unsigned char offset_h3a_en; -}; - -struct vpfe_isif_cul { - /* Horizontal Cull pattern for odd lines */ - unsigned char hcpat_odd; - /* Horizontal Cull pattern for even lines */ - unsigned char hcpat_even; - /* Vertical Cull pattern */ - unsigned char vcpat; - /* Enable or disable lpf. Apply when cull is enabled */ - unsigned char en_lpf; -}; - -/* all the stuff in this struct will be provided by userland */ -struct vpfe_isif_raw_config { - /* Linearization parameters for image sensor data input */ - struct vpfe_isif_linearize linearize; - /* Data formatter or CSC */ - struct vpfe_isif_df_csc df_csc; - /* Defect Pixel Correction (DFC) confguration */ - struct vpfe_isif_dfc dfc; - /* Black/Digital Clamp configuration */ - struct vpfe_isif_black_clamp bclamp; - /* Gain, offset adjustments */ - struct vpfe_isif_gain_offsets_adj gain_offset; - /* Culling */ - struct vpfe_isif_cul culling; - /* horizontal offset for Gain/LSC/DFC */ - unsigned short horz_offset; - /* vertical offset for Gain/LSC/DFC */ - unsigned short vert_offset; -}; - -/********************************************************************** - * IPIPE API Structures - **********************************************************************/ - -/* IPIPE module configurations */ - -/* IPIPE input configuration */ -#define VPFE_IPIPE_INPUT_CONFIG BIT(0) -/* LUT based Defect Pixel Correction */ -#define VPFE_IPIPE_LUTDPC BIT(1) -/* On the fly (OTF) Defect Pixel Correction */ -#define VPFE_IPIPE_OTFDPC BIT(2) -/* Noise Filter - 1 */ -#define VPFE_IPIPE_NF1 BIT(3) -/* Noise Filter - 2 */ -#define VPFE_IPIPE_NF2 BIT(4) -/* White Balance. Also a control ID */ -#define VPFE_IPIPE_WB BIT(5) -/* 1st RGB to RBG Blend module */ -#define VPFE_IPIPE_RGB2RGB_1 BIT(6) -/* 2nd RGB to RBG Blend module */ -#define VPFE_IPIPE_RGB2RGB_2 BIT(7) -/* Gamma Correction */ -#define VPFE_IPIPE_GAMMA BIT(8) -/* 3D LUT color conversion */ -#define VPFE_IPIPE_3D_LUT BIT(9) -/* RGB to YCbCr module */ -#define VPFE_IPIPE_RGB2YUV BIT(10) -/* YUV 422 conversion module */ -#define VPFE_IPIPE_YUV422_CONV BIT(11) -/* Edge Enhancement */ -#define VPFE_IPIPE_YEE BIT(12) -/* Green Imbalance Correction */ -#define VPFE_IPIPE_GIC BIT(13) -/* CFA Interpolation */ -#define VPFE_IPIPE_CFA BIT(14) -/* Chroma Artifact Reduction */ -#define VPFE_IPIPE_CAR BIT(15) -/* Chroma Gain Suppression */ -#define VPFE_IPIPE_CGS BIT(16) -/* Global brightness and contrast control */ -#define VPFE_IPIPE_GBCE BIT(17) - -#define VPFE_IPIPE_MAX_MODULES 18 - -struct ipipe_float_u16 { - unsigned short integer; - unsigned short decimal; -}; - -struct ipipe_float_s16 { - short integer; - unsigned short decimal; -}; - -struct ipipe_float_u8 { - unsigned char integer; - unsigned char decimal; -}; - -/* Copy method selection for vertical correction - * Used when ipipe_dfc_corr_meth is IPIPE_DPC_CTORB_AFTER_HINT - */ -enum vpfe_ipipe_dpc_corr_meth { - /* replace by black or white dot specified by repl_white */ - VPFE_IPIPE_DPC_REPL_BY_DOT = 0, - /* Copy from left */ - VPFE_IPIPE_DPC_CL = 1, - /* Copy from right */ - VPFE_IPIPE_DPC_CR = 2, - /* Horizontal interpolation */ - VPFE_IPIPE_DPC_H_INTP = 3, - /* Vertical interpolation */ - VPFE_IPIPE_DPC_V_INTP = 4, - /* Copy from top */ - VPFE_IPIPE_DPC_CT = 5, - /* Copy from bottom */ - VPFE_IPIPE_DPC_CB = 6, - /* 2D interpolation */ - VPFE_IPIPE_DPC_2D_INTP = 7, -}; - -struct vpfe_ipipe_lutdpc_entry { - /* Horizontal position */ - unsigned short horz_pos; - /* vertical position */ - unsigned short vert_pos; - enum vpfe_ipipe_dpc_corr_meth method; -}; - -#define VPFE_IPIPE_MAX_SIZE_DPC 256 - -/* Structure for configuring DPC module */ -struct vpfe_ipipe_lutdpc { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* 0 - replace with black dot, 1 - white dot when correction - * method is IPIPE_DFC_REPL_BY_DOT=0, - */ - unsigned char repl_white; - /* number of entries in the correction table. Currently only - * support up-to 256 entries. infinite mode is not supported - */ - unsigned short dpc_size; - struct vpfe_ipipe_lutdpc_entry table[VPFE_IPIPE_MAX_SIZE_DPC]; -}; - -enum vpfe_ipipe_otfdpc_det_meth { - VPFE_IPIPE_DPC_OTF_MIN_MAX, - VPFE_IPIPE_DPC_OTF_MIN_MAX2 -}; - -struct vpfe_ipipe_otfdpc_thr { - unsigned short r; - unsigned short gr; - unsigned short gb; - unsigned short b; -}; - -enum vpfe_ipipe_otfdpc_alg { - VPFE_IPIPE_OTFDPC_2_0, - VPFE_IPIPE_OTFDPC_3_0 -}; - -struct vpfe_ipipe_otfdpc_2_0_cfg { - /* defect detection threshold for MIN_MAX2 method (DPC 2.0 alg) */ - struct vpfe_ipipe_otfdpc_thr det_thr; - /* defect correction threshold for MIN_MAX2 method (DPC 2.0 alg) or - * maximum value for MIN_MAX method - */ - struct vpfe_ipipe_otfdpc_thr corr_thr; -}; - -struct vpfe_ipipe_otfdpc_3_0_cfg { - /* DPC3.0 activity adj shf. activity = (max2-min2) >> (6 -shf) - */ - unsigned char act_adj_shf; - /* DPC3.0 detection threshold, THR */ - unsigned short det_thr; - /* DPC3.0 detection threshold slope, SLP */ - unsigned short det_slp; - /* DPC3.0 detection threshold min, MIN */ - unsigned short det_thr_min; - /* DPC3.0 detection threshold max, MAX */ - unsigned short det_thr_max; - /* DPC3.0 correction threshold, THR */ - unsigned short corr_thr; - /* DPC3.0 correction threshold slope, SLP */ - unsigned short corr_slp; - /* DPC3.0 correction threshold min, MIN */ - unsigned short corr_thr_min; - /* DPC3.0 correction threshold max, MAX */ - unsigned short corr_thr_max; -}; - -struct vpfe_ipipe_otfdpc { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* defect detection method */ - enum vpfe_ipipe_otfdpc_det_meth det_method; - /* Algorithm used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is - * used - */ - enum vpfe_ipipe_otfdpc_alg alg; - union { - /* if alg is IPIPE_OTFDPC_2_0 */ - struct vpfe_ipipe_otfdpc_2_0_cfg dpc_2_0; - /* if alg is IPIPE_OTFDPC_3_0 */ - struct vpfe_ipipe_otfdpc_3_0_cfg dpc_3_0; - } alg_cfg; -}; - -/* Threshold values table size */ -#define VPFE_IPIPE_NF_THR_TABLE_SIZE 8 -/* Intensity values table size */ -#define VPFE_IPIPE_NF_STR_TABLE_SIZE 8 - -/* NF, sampling method for green pixels */ -enum vpfe_ipipe_nf_sampl_meth { - /* Same as R or B */ - VPFE_IPIPE_NF_BOX, - /* Diamond mode */ - VPFE_IPIPE_NF_DIAMOND -}; - -/* Structure for configuring NF module */ -struct vpfe_ipipe_nf { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* Sampling method for green pixels */ - enum vpfe_ipipe_nf_sampl_meth gr_sample_meth; - /* Down shift value in LUT reference address - */ - unsigned char shft_val; - /* Spread value in NF algorithm - */ - unsigned char spread_val; - /* Apply LSC gain to threshold. Enable this only if - * LSC is enabled in ISIF - */ - unsigned char apply_lsc_gain; - /* Threshold values table */ - unsigned short thr[VPFE_IPIPE_NF_THR_TABLE_SIZE]; - /* intensity values table */ - unsigned char str[VPFE_IPIPE_NF_STR_TABLE_SIZE]; - /* Edge detection minimum threshold */ - unsigned short edge_det_min_thr; - /* Edge detection maximum threshold */ - unsigned short edge_det_max_thr; -}; - -enum vpfe_ipipe_gic_alg { - VPFE_IPIPE_GIC_ALG_CONST_GAIN, - VPFE_IPIPE_GIC_ALG_ADAPT_GAIN -}; - -enum vpfe_ipipe_gic_thr_sel { - VPFE_IPIPE_GIC_THR_REG, - VPFE_IPIPE_GIC_THR_NF -}; - -enum vpfe_ipipe_gic_wt_fn_type { - /* Use difference as index */ - VPFE_IPIPE_GIC_WT_FN_TYP_DIF, - /* Use weight function as index */ - VPFE_IPIPE_GIC_WT_FN_TYP_HP_VAL -}; - -/* structure for Green Imbalance Correction */ -struct vpfe_ipipe_gic { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* 0 - Constant gain , 1 - Adaptive gain algorithm */ - enum vpfe_ipipe_gic_alg gic_alg; - /* GIC gain or weight. Used for Constant gain and Adaptive algorithms - */ - unsigned short gain; - /* Threshold selection. GIC register values or NF2 thr table */ - enum vpfe_ipipe_gic_thr_sel thr_sel; - /* thr1. Used when thr_sel is IPIPE_GIC_THR_REG */ - unsigned short thr; - /* this value is used for thr2-thr1, thr3-thr2 or - * thr4-thr3 when wt_fn_type is index. Otherwise it - * is the - */ - unsigned short slope; - /* Apply LSC gain to threshold. Enable this only if - * LSC is enabled in ISIF & thr_sel is IPIPE_GIC_THR_REG - */ - unsigned char apply_lsc_gain; - /* Multiply Nf2 threshold by this gain. Use this when thr_sel - * is IPIPE_GIC_THR_NF - */ - struct ipipe_float_u8 nf2_thr_gain; - /* Weight function uses difference as index or high pass value. - * Used for adaptive gain algorithm - */ - enum vpfe_ipipe_gic_wt_fn_type wt_fn_type; -}; - -/* Structure for configuring WB module */ -struct vpfe_ipipe_wb { - /* Offset (S12) for R */ - short ofst_r; - /* Offset (S12) for Gr */ - short ofst_gr; - /* Offset (S12) for Gb */ - short ofst_gb; - /* Offset (S12) for B */ - short ofst_b; - /* Gain (U13Q9) for Red */ - struct ipipe_float_u16 gain_r; - /* Gain (U13Q9) for Gr */ - struct ipipe_float_u16 gain_gr; - /* Gain (U13Q9) for Gb */ - struct ipipe_float_u16 gain_gb; - /* Gain (U13Q9) for Blue */ - struct ipipe_float_u16 gain_b; -}; - -enum vpfe_ipipe_cfa_alg { - /* Algorithm is 2DirAC */ - VPFE_IPIPE_CFA_ALG_2DIRAC, - /* Algorithm is 2DirAC + Digital Antialiasing (DAA) */ - VPFE_IPIPE_CFA_ALG_2DIRAC_DAA, - /* Algorithm is DAA */ - VPFE_IPIPE_CFA_ALG_DAA -}; - -/* Structure for CFA Interpolation */ -struct vpfe_ipipe_cfa { - /* 2DirAC or 2DirAC + DAA */ - enum vpfe_ipipe_cfa_alg alg; - /* 2Dir CFA HP value Low Threshold */ - unsigned short hpf_thr_2dir; - /* 2Dir CFA HP value slope */ - unsigned short hpf_slp_2dir; - /* 2Dir CFA HP mix threshold */ - unsigned short hp_mix_thr_2dir; - /* 2Dir CFA HP mix slope */ - unsigned short hp_mix_slope_2dir; - /* 2Dir Direction threshold */ - unsigned short dir_thr_2dir; - /* 2Dir Direction slope */ - unsigned short dir_slope_2dir; - /* 2Dir Non Directional Weight */ - unsigned short nd_wt_2dir; - /* DAA Mono Hue Fraction */ - unsigned short hue_fract_daa; - /* DAA Mono Edge threshold */ - unsigned short edge_thr_daa; - /* DAA Mono threshold minimum */ - unsigned short thr_min_daa; - /* DAA Mono threshold slope */ - unsigned short thr_slope_daa; - /* DAA Mono slope minimum */ - unsigned short slope_min_daa; - /* DAA Mono slope slope */ - unsigned short slope_slope_daa; - /* DAA Mono LP wight */ - unsigned short lp_wt_daa; -}; - -/* Struct for configuring RGB2RGB blending module */ -struct vpfe_ipipe_rgb2rgb { - /* Matrix coefficient for RR S12Q8 for ID = 1 and S11Q8 for ID = 2 */ - struct ipipe_float_s16 coef_rr; - /* Matrix coefficient for GR S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_gr; - /* Matrix coefficient for BR S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_br; - /* Matrix coefficient for RG S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_rg; - /* Matrix coefficient for GG S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_gg; - /* Matrix coefficient for BG S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_bg; - /* Matrix coefficient for RB S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_rb; - /* Matrix coefficient for GB S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_gb; - /* Matrix coefficient for BB S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_bb; - /* Output offset for R S13/S11 */ - int out_ofst_r; - /* Output offset for G S13/S11 */ - int out_ofst_g; - /* Output offset for B S13/S11 */ - int out_ofst_b; -}; - -#define VPFE_IPIPE_MAX_SIZE_GAMMA 512 - -enum vpfe_ipipe_gamma_tbl_size { - VPFE_IPIPE_GAMMA_TBL_SZ_64 = 64, - VPFE_IPIPE_GAMMA_TBL_SZ_128 = 128, - VPFE_IPIPE_GAMMA_TBL_SZ_256 = 256, - VPFE_IPIPE_GAMMA_TBL_SZ_512 = 512, -}; - -enum vpfe_ipipe_gamma_tbl_sel { - VPFE_IPIPE_GAMMA_TBL_RAM = 0, - VPFE_IPIPE_GAMMA_TBL_ROM = 1, -}; - -struct vpfe_ipipe_gamma_entry { - /* 10 bit slope */ - short slope; - /* 10 bit offset */ - unsigned short offset; -}; - -/* Structure for configuring Gamma correction module */ -struct vpfe_ipipe_gamma { - /* 0 - Enable Gamma correction for Red - * 1 - bypass Gamma correction. Data is divided by 16 - */ - unsigned char bypass_r; - /* 0 - Enable Gamma correction for Blue - * 1 - bypass Gamma correction. Data is divided by 16 - */ - unsigned char bypass_b; - /* 0 - Enable Gamma correction for Green - * 1 - bypass Gamma correction. Data is divided by 16 - */ - unsigned char bypass_g; - /* IPIPE_GAMMA_TBL_RAM or IPIPE_GAMMA_TBL_ROM */ - enum vpfe_ipipe_gamma_tbl_sel tbl_sel; - /* Table size for RAM gamma table. - */ - enum vpfe_ipipe_gamma_tbl_size tbl_size; - /* R table */ - struct vpfe_ipipe_gamma_entry table_r[VPFE_IPIPE_MAX_SIZE_GAMMA]; - /* Blue table */ - struct vpfe_ipipe_gamma_entry table_b[VPFE_IPIPE_MAX_SIZE_GAMMA]; - /* Green table */ - struct vpfe_ipipe_gamma_entry table_g[VPFE_IPIPE_MAX_SIZE_GAMMA]; -}; - -#define VPFE_IPIPE_MAX_SIZE_3D_LUT 729 - -struct vpfe_ipipe_3d_lut_entry { - /* 10 bit entry for red */ - unsigned short r; - /* 10 bit entry for green */ - unsigned short g; - /* 10 bit entry for blue */ - unsigned short b; -}; - -/* structure for 3D-LUT */ -struct vpfe_ipipe_3d_lut { - /* enable/disable 3D lut */ - unsigned char en; - /* 3D - LUT table entry */ - struct vpfe_ipipe_3d_lut_entry table[VPFE_IPIPE_MAX_SIZE_3D_LUT]; -}; - -/* Struct for configuring rgb2ycbcr module */ -struct vpfe_ipipe_rgb2yuv { - /* Matrix coefficient for RY S12Q8 */ - struct ipipe_float_s16 coef_ry; - /* Matrix coefficient for GY S12Q8 */ - struct ipipe_float_s16 coef_gy; - /* Matrix coefficient for BY S12Q8 */ - struct ipipe_float_s16 coef_by; - /* Matrix coefficient for RCb S12Q8 */ - struct ipipe_float_s16 coef_rcb; - /* Matrix coefficient for GCb S12Q8 */ - struct ipipe_float_s16 coef_gcb; - /* Matrix coefficient for BCb S12Q8 */ - struct ipipe_float_s16 coef_bcb; - /* Matrix coefficient for RCr S12Q8 */ - struct ipipe_float_s16 coef_rcr; - /* Matrix coefficient for GCr S12Q8 */ - struct ipipe_float_s16 coef_gcr; - /* Matrix coefficient for BCr S12Q8 */ - struct ipipe_float_s16 coef_bcr; - /* Output offset for R S11 */ - int out_ofst_y; - /* Output offset for Cb S11 */ - int out_ofst_cb; - /* Output offset for Cr S11 */ - int out_ofst_cr; -}; - -enum vpfe_ipipe_gbce_type { - VPFE_IPIPE_GBCE_Y_VAL_TBL = 0, - VPFE_IPIPE_GBCE_GAIN_TBL = 1, -}; - -#define VPFE_IPIPE_MAX_SIZE_GBCE_LUT 1024 - -/* structure for Global brightness and Contrast */ -struct vpfe_ipipe_gbce { - /* enable/disable GBCE */ - unsigned char en; - /* Y - value table or Gain table */ - enum vpfe_ipipe_gbce_type type; - /* ptr to LUT for GBCE with 1024 entries */ - unsigned short table[VPFE_IPIPE_MAX_SIZE_GBCE_LUT]; -}; - -/* Chrominance position. Applicable only for YCbCr input - * Applied after edge enhancement - */ -enum vpfe_chr_pos { - /* Co-siting, same position with luminance */ - VPFE_IPIPE_YUV422_CHR_POS_COSITE = 0, - /* Centering, In the middle of luminance */ - VPFE_IPIPE_YUV422_CHR_POS_CENTRE = 1, -}; - -/* Structure for configuring yuv422 conversion module */ -struct vpfe_ipipe_yuv422_conv { - /* Max Chrominance value */ - unsigned char en_chrom_lpf; - /* 1 - enable LPF for chrminance, 0 - disable */ - enum vpfe_chr_pos chrom_pos; -}; - -#define VPFE_IPIPE_MAX_SIZE_YEE_LUT 1024 - -enum vpfe_ipipe_yee_merge_meth { - VPFE_IPIPE_YEE_ABS_MAX = 0, - VPFE_IPIPE_YEE_EE_ES = 1, -}; - -/* Structure for configuring YUV Edge Enhancement module */ -struct vpfe_ipipe_yee { - /* 1 - enable enhancement, 0 - disable */ - unsigned char en; - /* enable/disable halo reduction in edge sharpner */ - unsigned char en_halo_red; - /* Merge method between Edge Enhancer and Edge sharpner */ - enum vpfe_ipipe_yee_merge_meth merge_meth; - /* HPF Shift length */ - unsigned char hpf_shft; - /* HPF Coefficient 00, S10 */ - short hpf_coef_00; - /* HPF Coefficient 01, S10 */ - short hpf_coef_01; - /* HPF Coefficient 02, S10 */ - short hpf_coef_02; - /* HPF Coefficient 10, S10 */ - short hpf_coef_10; - /* HPF Coefficient 11, S10 */ - short hpf_coef_11; - /* HPF Coefficient 12, S10 */ - short hpf_coef_12; - /* HPF Coefficient 20, S10 */ - short hpf_coef_20; - /* HPF Coefficient 21, S10 */ - short hpf_coef_21; - /* HPF Coefficient 22, S10 */ - short hpf_coef_22; - /* Lower threshold before referring to LUT */ - unsigned short yee_thr; - /* Edge sharpener Gain */ - unsigned short es_gain; - /* Edge sharpener lower threshold */ - unsigned short es_thr1; - /* Edge sharpener upper threshold */ - unsigned short es_thr2; - /* Edge sharpener gain on gradient */ - unsigned short es_gain_grad; - /* Edge sharpener offset on gradient */ - unsigned short es_ofst_grad; - /* Ptr to EE table. Must have 1024 entries */ - short table[VPFE_IPIPE_MAX_SIZE_YEE_LUT]; -}; - -enum vpfe_ipipe_car_meth { - /* Chromatic Gain Control */ - VPFE_IPIPE_CAR_CHR_GAIN_CTRL = 0, - /* Dynamic switching between CHR_GAIN_CTRL - * and MED_FLTR - */ - VPFE_IPIPE_CAR_DYN_SWITCH = 1, - /* Median Filter */ - VPFE_IPIPE_CAR_MED_FLTR = 2, -}; - -enum vpfe_ipipe_car_hpf_type { - VPFE_IPIPE_CAR_HPF_Y = 0, - VPFE_IPIPE_CAR_HPF_H = 1, - VPFE_IPIPE_CAR_HPF_V = 2, - VPFE_IPIPE_CAR_HPF_2D = 3, - /* 2D HPF from YUV Edge Enhancement */ - VPFE_IPIPE_CAR_HPF_2D_YEE = 4, -}; - -struct vpfe_ipipe_car_gain { - /* csup_gain */ - unsigned char gain; - /* csup_shf. */ - unsigned char shft; - /* gain minimum */ - unsigned short gain_min; -}; - -/* Structure for Chromatic Artifact Reduction */ -struct vpfe_ipipe_car { - /* enable/disable */ - unsigned char en; - /* Gain control or Dynamic switching */ - enum vpfe_ipipe_car_meth meth; - /* Gain1 function configuration for Gain control */ - struct vpfe_ipipe_car_gain gain1; - /* Gain2 function configuration for Gain control */ - struct vpfe_ipipe_car_gain gain2; - /* HPF type used for CAR */ - enum vpfe_ipipe_car_hpf_type hpf; - /* csup_thr: HPF threshold for Gain control */ - unsigned char hpf_thr; - /* Down shift value for hpf. 2 bits */ - unsigned char hpf_shft; - /* switch limit for median filter */ - unsigned char sw0; - /* switch coefficient for Gain control */ - unsigned char sw1; -}; - -/* structure for Chromatic Gain Suppression */ -struct vpfe_ipipe_cgs { - /* enable/disable */ - unsigned char en; - /* gain1 bright side threshold */ - unsigned char h_thr; - /* gain1 bright side slope */ - unsigned char h_slope; - /* gain1 down shift value for bright side */ - unsigned char h_shft; - /* gain1 bright side minimum gain */ - unsigned char h_min; -}; - -/* Max pixels allowed in the input. If above this either decimation - * or frame division mode to be enabled - */ -#define VPFE_IPIPE_MAX_INPUT_WIDTH 2600 - -struct vpfe_ipipe_input_config { - unsigned int vst; - unsigned int hst; -}; - -/** - * struct vpfe_ipipe_config - IPIPE engine configuration (user) - * @input_config: Pointer to structure for ipipe configuration. - * @flag: Specifies which ISP IPIPE functions should be enabled. - * @lutdpc: Pointer to luma enhancement structure. - * @otfdpc: Pointer to structure for defect correction. - * @nf1: Pointer to structure for Noise Filter. - * @nf2: Pointer to structure for Noise Filter. - * @gic: Pointer to structure for Green Imbalance. - * @wbal: Pointer to structure for White Balance. - * @cfa: Pointer to structure containing the CFA interpolation. - * @rgb2rgb1: Pointer to structure for RGB to RGB Blending. - * @rgb2rgb2: Pointer to structure for RGB to RGB Blending. - * @gamma: Pointer to gamma structure. - * @lut: Pointer to structure for 3D LUT. - * @rgb2yuv: Pointer to structure for RGB-YCbCr conversion. - * @gbce: Pointer to structure for Global Brightness,Contrast Control. - * @yuv422_conv: Pointer to structure for YUV 422 conversion. - * @yee: Pointer to structure for Edge Enhancer. - * @car: Pointer to structure for Chromatic Artifact Reduction. - * @cgs: Pointer to structure for Chromatic Gain Suppression. - */ -struct vpfe_ipipe_config { - __u32 flag; - struct vpfe_ipipe_input_config __user *input_config; - struct vpfe_ipipe_lutdpc __user *lutdpc; - struct vpfe_ipipe_otfdpc __user *otfdpc; - struct vpfe_ipipe_nf __user *nf1; - struct vpfe_ipipe_nf __user *nf2; - struct vpfe_ipipe_gic __user *gic; - struct vpfe_ipipe_wb __user *wbal; - struct vpfe_ipipe_cfa __user *cfa; - struct vpfe_ipipe_rgb2rgb __user *rgb2rgb1; - struct vpfe_ipipe_rgb2rgb __user *rgb2rgb2; - struct vpfe_ipipe_gamma __user *gamma; - struct vpfe_ipipe_3d_lut __user *lut; - struct vpfe_ipipe_rgb2yuv __user *rgb2yuv; - struct vpfe_ipipe_gbce __user *gbce; - struct vpfe_ipipe_yuv422_conv __user *yuv422_conv; - struct vpfe_ipipe_yee __user *yee; - struct vpfe_ipipe_car __user *car; - struct vpfe_ipipe_cgs __user *cgs; -}; - -/******************************************************************* - ** Resizer API structures - *******************************************************************/ -/* Interpolation types used for horizontal rescale */ -enum vpfe_rsz_intp_t { - VPFE_RSZ_INTP_CUBIC, - VPFE_RSZ_INTP_LINEAR -}; - -/* Horizontal LPF intensity selection */ -enum vpfe_rsz_h_lpf_lse_t { - VPFE_RSZ_H_LPF_LSE_INTERN, - VPFE_RSZ_H_LPF_LSE_USER_VAL -}; - -enum vpfe_rsz_down_scale_ave_sz { - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - VPFE_IPIPE_DWN_SCALE_1_OVER_4, - VPFE_IPIPE_DWN_SCALE_1_OVER_8, - VPFE_IPIPE_DWN_SCALE_1_OVER_16, - VPFE_IPIPE_DWN_SCALE_1_OVER_32, - VPFE_IPIPE_DWN_SCALE_1_OVER_64, - VPFE_IPIPE_DWN_SCALE_1_OVER_128, - VPFE_IPIPE_DWN_SCALE_1_OVER_256 -}; - -struct vpfe_rsz_output_spec { - /* enable horizontal flip */ - unsigned char h_flip; - /* enable vertical flip */ - unsigned char v_flip; - /* line start offset for y. */ - unsigned int vst_y; - /* line start offset for c. Only for 420 */ - unsigned int vst_c; - /* vertical rescale interpolation type, YCbCr or Luminance */ - enum vpfe_rsz_intp_t v_typ_y; - /* vertical rescale interpolation type for Chrominance */ - enum vpfe_rsz_intp_t v_typ_c; - /* vertical lpf intensity - Luminance */ - unsigned char v_lpf_int_y; - /* vertical lpf intensity - Chrominance */ - unsigned char v_lpf_int_c; - /* horizontal rescale interpolation types, YCbCr or Luminance */ - enum vpfe_rsz_intp_t h_typ_y; - /* horizontal rescale interpolation types, Chrominance */ - enum vpfe_rsz_intp_t h_typ_c; - /* horizontal lpf intensity - Luminance */ - unsigned char h_lpf_int_y; - /* horizontal lpf intensity - Chrominance */ - unsigned char h_lpf_int_c; - /* Use down scale mode for scale down */ - unsigned char en_down_scale; - /* if downscale, set the downscale more average size for horizontal - * direction. Used only if output width and height is less than - * input sizes - */ - enum vpfe_rsz_down_scale_ave_sz h_dscale_ave_sz; - /* if downscale, set the downscale more average size for vertical - * direction. Used only if output width and height is less than - * input sizes - */ - enum vpfe_rsz_down_scale_ave_sz v_dscale_ave_sz; - /* Y offset. If set, the offset would be added to the base address - */ - unsigned int user_y_ofst; - /* C offset. If set, the offset would be added to the base address - */ - unsigned int user_c_ofst; -}; - -struct vpfe_rsz_config_params { - unsigned int vst; - /* horizontal start position of the image - * data to IPIPE - */ - unsigned int hst; - /* output spec of the image data coming out of resizer - 0(UYVY). - */ - struct vpfe_rsz_output_spec output1; - /* output spec of the image data coming out of resizer - 1(UYVY). - */ - struct vpfe_rsz_output_spec output2; - /* 0 , chroma sample at odd pixel, 1 - even pixel */ - unsigned char chroma_sample_even; - unsigned char frame_div_mode_en; - unsigned char yuv_y_min; - unsigned char yuv_y_max; - unsigned char yuv_c_min; - unsigned char yuv_c_max; - enum vpfe_chr_pos out_chr_pos; - unsigned char bypass; -}; - -/* Structure for VIDIOC_VPFE_RSZ_[S/G]_CONFIG IOCTLs */ -struct vpfe_rsz_config { - struct vpfe_rsz_config_params *config; -}; - -#endif /* _DAVINCI_VPFE_USER_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c deleted file mode 100644 index 52397ad0e3e2..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c +++ /dev/null @@ -1,1852 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - * - * - * IPIPE allows fine tuning of the input image using different - * tuning modules in IPIPE. Some examples :- Noise filter, Defect - * pixel correction etc. It essentially operate on Bayer Raw data - * or YUV raw data. To do image tuning, application call, - * - */ - -#include <linux/slab.h> -#include <linux/bitops.h> - -#include "dm365_ipipe.h" -#include "dm365_ipipe_hw.h" -#include "vpfe_mc_capture.h" - -#define MIN_OUT_WIDTH 32 -#define MIN_OUT_HEIGHT 32 - -/* ipipe input format's */ -static const unsigned int ipipe_input_fmts[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_SGRBG12_1X12, - MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, - MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, -}; - -/* ipipe output format's */ -static const unsigned int ipipe_output_fmts[] = { - MEDIA_BUS_FMT_UYVY8_2X8, -}; - -static int ipipe_validate_lutdpc_params(struct vpfe_ipipe_lutdpc *lutdpc) -{ - int i; - - if (lutdpc->en > 1 || lutdpc->repl_white > 1 || - lutdpc->dpc_size > LUT_DPC_MAX_SIZE) - return -EINVAL; - - if (lutdpc->en) - return -EINVAL; - - for (i = 0; i < lutdpc->dpc_size; i++) - if (lutdpc->table[i].horz_pos > LUT_DPC_H_POS_MASK || - lutdpc->table[i].vert_pos > LUT_DPC_V_POS_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_lutdpc_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_lutdpc *lutdpc = &ipipe->config.lutdpc; - struct vpfe_ipipe_lutdpc *dpc_param; - - if (!param) { - memset((void *)lutdpc, 0, sizeof(struct vpfe_ipipe_lutdpc)); - goto success; - } - - dpc_param = param; - lutdpc->en = dpc_param->en; - lutdpc->repl_white = dpc_param->repl_white; - lutdpc->dpc_size = dpc_param->dpc_size; - memcpy(&lutdpc->table, &dpc_param->table, - (dpc_param->dpc_size * sizeof(struct vpfe_ipipe_lutdpc_entry))); - if (ipipe_validate_lutdpc_params(lutdpc) < 0) - return -EINVAL; - -success: - ipipe_set_lutdpc_regs(ipipe->base_addr, ipipe->isp5_base_addr, lutdpc); - - return 0; -} - -static int ipipe_get_lutdpc_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_lutdpc *lut_param = param; - struct vpfe_ipipe_lutdpc *lutdpc = &ipipe->config.lutdpc; - - lut_param->en = lutdpc->en; - lut_param->repl_white = lutdpc->repl_white; - lut_param->dpc_size = lutdpc->dpc_size; - memcpy(&lut_param->table, &lutdpc->table, - (lutdpc->dpc_size * sizeof(struct vpfe_ipipe_lutdpc_entry))); - - return 0; -} - -static int ipipe_set_input_config(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_input_config *config = &ipipe->config.input_config; - - if (!param) - memset(config, 0, sizeof(struct vpfe_ipipe_input_config)); - else - memcpy(config, param, sizeof(struct vpfe_ipipe_input_config)); - return 0; -} - -static int ipipe_get_input_config(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_input_config *config = &ipipe->config.input_config; - - if (!param) - return -EINVAL; - - memcpy(param, config, sizeof(struct vpfe_ipipe_input_config)); - - return 0; -} - -static int ipipe_validate_otfdpc_params(struct vpfe_ipipe_otfdpc *dpc_param) -{ - struct vpfe_ipipe_otfdpc_2_0_cfg *dpc_2_0; - struct vpfe_ipipe_otfdpc_3_0_cfg *dpc_3_0; - - if (dpc_param->en > 1) - return -EINVAL; - - if (dpc_param->alg == VPFE_IPIPE_OTFDPC_2_0) { - dpc_2_0 = &dpc_param->alg_cfg.dpc_2_0; - if (dpc_2_0->det_thr.r > OTFDPC_DPC2_THR_MASK || - dpc_2_0->det_thr.gr > OTFDPC_DPC2_THR_MASK || - dpc_2_0->det_thr.gb > OTFDPC_DPC2_THR_MASK || - dpc_2_0->det_thr.b > OTFDPC_DPC2_THR_MASK || - dpc_2_0->corr_thr.r > OTFDPC_DPC2_THR_MASK || - dpc_2_0->corr_thr.gr > OTFDPC_DPC2_THR_MASK || - dpc_2_0->corr_thr.gb > OTFDPC_DPC2_THR_MASK || - dpc_2_0->corr_thr.b > OTFDPC_DPC2_THR_MASK) - return -EINVAL; - return 0; - } - - dpc_3_0 = &dpc_param->alg_cfg.dpc_3_0; - - if (dpc_3_0->act_adj_shf > OTF_DPC3_0_SHF_MASK || - dpc_3_0->det_thr > OTF_DPC3_0_DET_MASK || - dpc_3_0->det_slp > OTF_DPC3_0_SLP_MASK || - dpc_3_0->det_thr_min > OTF_DPC3_0_DET_MASK || - dpc_3_0->det_thr_max > OTF_DPC3_0_DET_MASK || - dpc_3_0->corr_thr > OTF_DPC3_0_CORR_MASK || - dpc_3_0->corr_slp > OTF_DPC3_0_SLP_MASK || - dpc_3_0->corr_thr_min > OTF_DPC3_0_CORR_MASK || - dpc_3_0->corr_thr_max > OTF_DPC3_0_CORR_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_otfdpc_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_otfdpc *dpc_param = param; - struct vpfe_ipipe_otfdpc *otfdpc = &ipipe->config.otfdpc; - struct device *dev; - - if (!param) { - memset((void *)otfdpc, 0, sizeof(struct ipipe_otfdpc_2_0)); - goto success; - } - dev = ipipe->subdev.v4l2_dev->dev; - memcpy(otfdpc, dpc_param, sizeof(struct vpfe_ipipe_otfdpc)); - if (ipipe_validate_otfdpc_params(otfdpc) < 0) { - dev_err(dev, "Invalid otfdpc params\n"); - return -EINVAL; - } - -success: - ipipe_set_otfdpc_regs(ipipe->base_addr, otfdpc); - - return 0; -} - -static int ipipe_get_otfdpc_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_otfdpc *dpc_param = param; - struct vpfe_ipipe_otfdpc *otfdpc = &ipipe->config.otfdpc; - - memcpy(dpc_param, otfdpc, sizeof(struct vpfe_ipipe_otfdpc)); - return 0; -} - -static int ipipe_validate_nf_params(struct vpfe_ipipe_nf *nf_param) -{ - int i; - - if (nf_param->en > 1 || nf_param->shft_val > D2F_SHFT_VAL_MASK || - nf_param->spread_val > D2F_SPR_VAL_MASK || - nf_param->apply_lsc_gain > 1 || - nf_param->edge_det_min_thr > D2F_EDGE_DET_THR_MASK || - nf_param->edge_det_max_thr > D2F_EDGE_DET_THR_MASK) - return -EINVAL; - - for (i = 0; i < VPFE_IPIPE_NF_THR_TABLE_SIZE; i++) - if (nf_param->thr[i] > D2F_THR_VAL_MASK) - return -EINVAL; - - for (i = 0; i < VPFE_IPIPE_NF_STR_TABLE_SIZE; i++) - if (nf_param->str[i] > D2F_STR_VAL_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_nf_params(struct vpfe_ipipe_device *ipipe, - unsigned int id, void *param) -{ - struct vpfe_ipipe_nf *nf_param = param; - struct vpfe_ipipe_nf *nf = &ipipe->config.nf1; - struct device *dev; - - if (id == IPIPE_D2F_2ND) - nf = &ipipe->config.nf2; - - if (!nf_param) { - memset((void *)nf, 0, sizeof(struct vpfe_ipipe_nf)); - goto success; - } - - dev = ipipe->subdev.v4l2_dev->dev; - memcpy(nf, nf_param, sizeof(struct vpfe_ipipe_nf)); - if (ipipe_validate_nf_params(nf) < 0) { - dev_err(dev, "Invalid nf params\n"); - return -EINVAL; - } - -success: - ipipe_set_d2f_regs(ipipe->base_addr, id, nf); - - return 0; -} - -static int ipipe_set_nf1_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_set_nf_params(ipipe, IPIPE_D2F_1ST, param); -} - -static int ipipe_set_nf2_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_set_nf_params(ipipe, IPIPE_D2F_2ND, param); -} - -static int ipipe_get_nf_params(struct vpfe_ipipe_device *ipipe, - unsigned int id, void *param) -{ - struct vpfe_ipipe_nf *nf_param = param; - struct vpfe_ipipe_nf *nf = &ipipe->config.nf1; - - if (id == IPIPE_D2F_2ND) - nf = &ipipe->config.nf2; - - memcpy(nf_param, nf, sizeof(struct vpfe_ipipe_nf)); - - return 0; -} - -static int ipipe_get_nf1_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_get_nf_params(ipipe, IPIPE_D2F_1ST, param); -} - -static int ipipe_get_nf2_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_get_nf_params(ipipe, IPIPE_D2F_2ND, param); -} - -static int ipipe_validate_gic_params(struct vpfe_ipipe_gic *gic) -{ - if (gic->en > 1 || gic->gain > GIC_GAIN_MASK || - gic->thr > GIC_THR_MASK || gic->slope > GIC_SLOPE_MASK || - gic->apply_lsc_gain > 1 || - gic->nf2_thr_gain.integer > GIC_NFGAN_INT_MASK || - gic->nf2_thr_gain.decimal > GIC_NFGAN_DECI_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_gic_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gic *gic_param = param; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_gic *gic = &ipipe->config.gic; - - if (!gic_param) { - memset((void *)gic, 0, sizeof(struct vpfe_ipipe_gic)); - goto success; - } - - memcpy(gic, gic_param, sizeof(struct vpfe_ipipe_gic)); - if (ipipe_validate_gic_params(gic) < 0) { - dev_err(dev, "Invalid gic params\n"); - return -EINVAL; - } - -success: - ipipe_set_gic_regs(ipipe->base_addr, gic); - - return 0; -} - -static int ipipe_get_gic_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gic *gic_param = param; - struct vpfe_ipipe_gic *gic = &ipipe->config.gic; - - memcpy(gic_param, gic, sizeof(struct vpfe_ipipe_gic)); - - return 0; -} - -static int ipipe_validate_wb_params(struct vpfe_ipipe_wb *wbal) -{ - if (wbal->ofst_r > WB_OFFSET_MASK || - wbal->ofst_gr > WB_OFFSET_MASK || - wbal->ofst_gb > WB_OFFSET_MASK || - wbal->ofst_b > WB_OFFSET_MASK || - wbal->gain_r.integer > WB_GAIN_INT_MASK || - wbal->gain_r.decimal > WB_GAIN_DECI_MASK || - wbal->gain_gr.integer > WB_GAIN_INT_MASK || - wbal->gain_gr.decimal > WB_GAIN_DECI_MASK || - wbal->gain_gb.integer > WB_GAIN_INT_MASK || - wbal->gain_gb.decimal > WB_GAIN_DECI_MASK || - wbal->gain_b.integer > WB_GAIN_INT_MASK || - wbal->gain_b.decimal > WB_GAIN_DECI_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_wb_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_wb *wb_param = param; - struct vpfe_ipipe_wb *wbal = &ipipe->config.wbal; - - if (!wb_param) { - const struct vpfe_ipipe_wb wb_defaults = { - .gain_r = {2, 0x0}, - .gain_gr = {2, 0x0}, - .gain_gb = {2, 0x0}, - .gain_b = {2, 0x0} - }; - memcpy(wbal, &wb_defaults, sizeof(struct vpfe_ipipe_wb)); - goto success; - } - - memcpy(wbal, wb_param, sizeof(struct vpfe_ipipe_wb)); - if (ipipe_validate_wb_params(wbal) < 0) - return -EINVAL; - -success: - ipipe_set_wb_regs(ipipe->base_addr, wbal); - - return 0; -} - -static int ipipe_get_wb_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_wb *wb_param = param; - struct vpfe_ipipe_wb *wbal = &ipipe->config.wbal; - - memcpy(wb_param, wbal, sizeof(struct vpfe_ipipe_wb)); - return 0; -} - -static int ipipe_validate_cfa_params(struct vpfe_ipipe_cfa *cfa) -{ - if (cfa->hpf_thr_2dir > CFA_HPF_THR_2DIR_MASK || - cfa->hpf_slp_2dir > CFA_HPF_SLOPE_2DIR_MASK || - cfa->hp_mix_thr_2dir > CFA_HPF_MIX_THR_2DIR_MASK || - cfa->hp_mix_slope_2dir > CFA_HPF_MIX_SLP_2DIR_MASK || - cfa->dir_thr_2dir > CFA_DIR_THR_2DIR_MASK || - cfa->dir_slope_2dir > CFA_DIR_SLP_2DIR_MASK || - cfa->nd_wt_2dir > CFA_ND_WT_2DIR_MASK || - cfa->hue_fract_daa > CFA_DAA_HUE_FRA_MASK || - cfa->edge_thr_daa > CFA_DAA_EDG_THR_MASK || - cfa->thr_min_daa > CFA_DAA_THR_MIN_MASK || - cfa->thr_slope_daa > CFA_DAA_THR_SLP_MASK || - cfa->slope_min_daa > CFA_DAA_SLP_MIN_MASK || - cfa->slope_slope_daa > CFA_DAA_SLP_SLP_MASK || - cfa->lp_wt_daa > CFA_DAA_LP_WT_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_cfa_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_cfa *cfa_param = param; - struct vpfe_ipipe_cfa *cfa = &ipipe->config.cfa; - - if (!cfa_param) { - memset(cfa, 0, sizeof(struct vpfe_ipipe_cfa)); - cfa->alg = VPFE_IPIPE_CFA_ALG_2DIRAC; - goto success; - } - - memcpy(cfa, cfa_param, sizeof(struct vpfe_ipipe_cfa)); - if (ipipe_validate_cfa_params(cfa) < 0) - return -EINVAL; - -success: - ipipe_set_cfa_regs(ipipe->base_addr, cfa); - - return 0; -} - -static int ipipe_get_cfa_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_cfa *cfa_param = param; - struct vpfe_ipipe_cfa *cfa = &ipipe->config.cfa; - - memcpy(cfa_param, cfa, sizeof(struct vpfe_ipipe_cfa)); - return 0; -} - -static int -ipipe_validate_rgb2rgb_params(struct vpfe_ipipe_rgb2rgb *rgb2rgb, - unsigned int id) -{ - u32 gain_int_upper = RGB2RGB_1_GAIN_INT_MASK; - u32 offset_upper = RGB2RGB_1_OFST_MASK; - - if (id == IPIPE_RGB2RGB_2) { - offset_upper = RGB2RGB_2_OFST_MASK; - gain_int_upper = RGB2RGB_2_GAIN_INT_MASK; - } - - if (rgb2rgb->coef_rr.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_rr.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_gr.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_gr.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_br.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_br.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_rg.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_rg.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_gg.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_gg.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_bg.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_bg.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_rb.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_rb.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_gb.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_gb.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_bb.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_bb.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->out_ofst_r > offset_upper || - rgb2rgb->out_ofst_g > offset_upper || - rgb2rgb->out_ofst_b > offset_upper) - return -EINVAL; - - return 0; -} - -static int ipipe_set_rgb2rgb_params(struct vpfe_ipipe_device *ipipe, - unsigned int id, void *param) -{ - struct vpfe_ipipe_rgb2rgb *rgb2rgb = &ipipe->config.rgb2rgb1; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_rgb2rgb *rgb2rgb_param; - - rgb2rgb_param = param; - - if (id == IPIPE_RGB2RGB_2) - rgb2rgb = &ipipe->config.rgb2rgb2; - - if (!rgb2rgb_param) { - const struct vpfe_ipipe_rgb2rgb rgb2rgb_defaults = { - .coef_rr = {1, 0}, /* 256 */ - .coef_gr = {0, 0}, - .coef_br = {0, 0}, - .coef_rg = {0, 0}, - .coef_gg = {1, 0}, /* 256 */ - .coef_bg = {0, 0}, - .coef_rb = {0, 0}, - .coef_gb = {0, 0}, - .coef_bb = {1, 0}, /* 256 */ - }; - /* Copy defaults for rgb2rgb conversion */ - memcpy(rgb2rgb, &rgb2rgb_defaults, - sizeof(struct vpfe_ipipe_rgb2rgb)); - goto success; - } - - memcpy(rgb2rgb, rgb2rgb_param, sizeof(struct vpfe_ipipe_rgb2rgb)); - if (ipipe_validate_rgb2rgb_params(rgb2rgb, id) < 0) { - dev_err(dev, "Invalid rgb2rgb params\n"); - return -EINVAL; - } - -success: - ipipe_set_rgb2rgb_regs(ipipe->base_addr, id, rgb2rgb); - - return 0; -} - -static int -ipipe_set_rgb2rgb_1_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_set_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_1, param); -} - -static int -ipipe_set_rgb2rgb_2_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_set_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_2, param); -} - -static int ipipe_get_rgb2rgb_params(struct vpfe_ipipe_device *ipipe, - unsigned int id, void *param) -{ - struct vpfe_ipipe_rgb2rgb *rgb2rgb = &ipipe->config.rgb2rgb1; - struct vpfe_ipipe_rgb2rgb *rgb2rgb_param; - - rgb2rgb_param = param; - - if (id == IPIPE_RGB2RGB_2) - rgb2rgb = &ipipe->config.rgb2rgb2; - - memcpy(rgb2rgb_param, rgb2rgb, sizeof(struct vpfe_ipipe_rgb2rgb)); - - return 0; -} - -static int -ipipe_get_rgb2rgb_1_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_get_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_1, param); -} - -static int -ipipe_get_rgb2rgb_2_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_get_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_2, param); -} - -static int -ipipe_validate_gamma_entry(struct vpfe_ipipe_gamma_entry *table, int size) -{ - int i; - - if (!table) - return -EINVAL; - - for (i = 0; i < size; i++) - if (table[i].slope > GAMMA_MASK || - table[i].offset > GAMMA_MASK) - return -EINVAL; - - return 0; -} - -static int -ipipe_validate_gamma_params(struct vpfe_ipipe_gamma *gamma, struct device *dev) -{ - int table_size; - int err; - - if (gamma->bypass_r > 1 || - gamma->bypass_b > 1 || - gamma->bypass_g > 1) - return -EINVAL; - - if (gamma->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM) - return 0; - - table_size = gamma->tbl_size; - if (!gamma->bypass_r) { - err = ipipe_validate_gamma_entry(gamma->table_r, table_size); - if (err) { - dev_err(dev, "GAMMA R - table entry invalid\n"); - return err; - } - } - - if (!gamma->bypass_b) { - err = ipipe_validate_gamma_entry(gamma->table_b, table_size); - if (err) { - dev_err(dev, "GAMMA B - table entry invalid\n"); - return err; - } - } - - if (!gamma->bypass_g) { - err = ipipe_validate_gamma_entry(gamma->table_g, table_size); - if (err) { - dev_err(dev, "GAMMA G - table entry invalid\n"); - return err; - } - } - - return 0; -} - -static int -ipipe_set_gamma_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gamma *gamma_param = param; - struct vpfe_ipipe_gamma *gamma = &ipipe->config.gamma; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - int table_size; - - if (!gamma_param) { - memset(gamma, 0, sizeof(struct vpfe_ipipe_gamma)); - gamma->tbl_sel = VPFE_IPIPE_GAMMA_TBL_ROM; - goto success; - } - - gamma->bypass_r = gamma_param->bypass_r; - gamma->bypass_b = gamma_param->bypass_b; - gamma->bypass_g = gamma_param->bypass_g; - gamma->tbl_sel = gamma_param->tbl_sel; - gamma->tbl_size = gamma_param->tbl_size; - - if (ipipe_validate_gamma_params(gamma, dev) < 0) - return -EINVAL; - - if (gamma_param->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM) - goto success; - - table_size = gamma->tbl_size; - if (!gamma_param->bypass_r) - memcpy(&gamma->table_r, &gamma_param->table_r, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - - if (!gamma_param->bypass_b) - memcpy(&gamma->table_b, &gamma_param->table_b, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - - if (!gamma_param->bypass_g) - memcpy(&gamma->table_g, &gamma_param->table_g, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - -success: - ipipe_set_gamma_regs(ipipe->base_addr, ipipe->isp5_base_addr, gamma); - - return 0; -} - -static int ipipe_get_gamma_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gamma *gamma_param = param; - struct vpfe_ipipe_gamma *gamma = &ipipe->config.gamma; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - int table_size; - - gamma_param->bypass_r = gamma->bypass_r; - gamma_param->bypass_g = gamma->bypass_g; - gamma_param->bypass_b = gamma->bypass_b; - gamma_param->tbl_sel = gamma->tbl_sel; - gamma_param->tbl_size = gamma->tbl_size; - - if (gamma->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM) - return 0; - - table_size = gamma->tbl_size; - - if (!gamma->bypass_r) { - dev_err(dev, - "%s: table ptr empty for R\n", __func__); - return -EINVAL; - } - memcpy(gamma_param->table_r, gamma->table_r, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - - if (!gamma->bypass_g) { - dev_err(dev, "%s: table ptr empty for G\n", __func__); - return -EINVAL; - } - memcpy(gamma_param->table_g, gamma->table_g, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - - if (!gamma->bypass_b) { - dev_err(dev, "%s: table ptr empty for B\n", __func__); - return -EINVAL; - } - memcpy(gamma_param->table_b, gamma->table_b, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - - return 0; -} - -static int ipipe_validate_3d_lut_params(struct vpfe_ipipe_3d_lut *lut) -{ - int i; - - if (!lut->en) - return 0; - - for (i = 0; i < VPFE_IPIPE_MAX_SIZE_3D_LUT; i++) - if (lut->table[i].r > D3_LUT_ENTRY_MASK || - lut->table[i].g > D3_LUT_ENTRY_MASK || - lut->table[i].b > D3_LUT_ENTRY_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_get_3d_lut_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_3d_lut *lut_param = param; - struct vpfe_ipipe_3d_lut *lut = &ipipe->config.lut; - - lut_param->en = lut->en; - - memcpy(lut_param->table, &lut->table, - (VPFE_IPIPE_MAX_SIZE_3D_LUT * - sizeof(struct vpfe_ipipe_3d_lut_entry))); - - return 0; -} - -static int -ipipe_set_3d_lut_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_3d_lut *lut_param = param; - struct vpfe_ipipe_3d_lut *lut = &ipipe->config.lut; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - - if (!lut_param) { - memset(lut, 0, sizeof(struct vpfe_ipipe_3d_lut)); - goto success; - } - - memcpy(lut, lut_param, sizeof(struct vpfe_ipipe_3d_lut)); - if (ipipe_validate_3d_lut_params(lut) < 0) { - dev_err(dev, "Invalid 3D-LUT Params\n"); - return -EINVAL; - } - -success: - ipipe_set_3d_lut_regs(ipipe->base_addr, ipipe->isp5_base_addr, lut); - - return 0; -} - -static int ipipe_validate_rgb2yuv_params(struct vpfe_ipipe_rgb2yuv *rgb2yuv) -{ - if (rgb2yuv->coef_ry.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_ry.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_gy.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_gy.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_by.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_by.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_rcb.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_rcb.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_gcb.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_gcb.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_bcb.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_bcb.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_rcr.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_rcr.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_gcr.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_gcr.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_bcr.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_bcr.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->out_ofst_y > RGB2YCBCR_OFST_MASK || - rgb2yuv->out_ofst_cb > RGB2YCBCR_OFST_MASK || - rgb2yuv->out_ofst_cr > RGB2YCBCR_OFST_MASK) - return -EINVAL; - - return 0; -} - -static int -ipipe_set_rgb2yuv_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_rgb2yuv *rgb2yuv = &ipipe->config.rgb2yuv; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_rgb2yuv *rgb2yuv_param; - - rgb2yuv_param = param; - if (!rgb2yuv_param) { - /* Defaults for rgb2yuv conversion */ - const struct vpfe_ipipe_rgb2yuv rgb2yuv_defaults = { - .coef_ry = {0, 0x4d}, - .coef_gy = {0, 0x96}, - .coef_by = {0, 0x1d}, - .coef_rcb = {0xf, 0xd5}, - .coef_gcb = {0xf, 0xab}, - .coef_bcb = {0, 0x80}, - .coef_rcr = {0, 0x80}, - .coef_gcr = {0xf, 0x95}, - .coef_bcr = {0xf, 0xeb}, - .out_ofst_cb = 0x80, - .out_ofst_cr = 0x80, - }; - /* Copy defaults for rgb2yuv conversion */ - memcpy(rgb2yuv, &rgb2yuv_defaults, - sizeof(struct vpfe_ipipe_rgb2yuv)); - goto success; - } - - memcpy(rgb2yuv, rgb2yuv_param, sizeof(struct vpfe_ipipe_rgb2yuv)); - if (ipipe_validate_rgb2yuv_params(rgb2yuv) < 0) { - dev_err(dev, "Invalid rgb2yuv params\n"); - return -EINVAL; - } - -success: - ipipe_set_rgb2ycbcr_regs(ipipe->base_addr, rgb2yuv); - - return 0; -} - -static int -ipipe_get_rgb2yuv_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_rgb2yuv *rgb2yuv = &ipipe->config.rgb2yuv; - struct vpfe_ipipe_rgb2yuv *rgb2yuv_param; - - rgb2yuv_param = param; - memcpy(rgb2yuv_param, rgb2yuv, sizeof(struct vpfe_ipipe_rgb2yuv)); - return 0; -} - -static int ipipe_validate_gbce_params(struct vpfe_ipipe_gbce *gbce) -{ - u32 max = GBCE_Y_VAL_MASK; - int i; - - if (!gbce->en) - return 0; - - if (gbce->type == VPFE_IPIPE_GBCE_GAIN_TBL) - max = GBCE_GAIN_VAL_MASK; - - for (i = 0; i < VPFE_IPIPE_MAX_SIZE_GBCE_LUT; i++) - if (gbce->table[i] > max) - return -EINVAL; - - return 0; -} - -static int ipipe_set_gbce_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gbce *gbce_param = param; - struct vpfe_ipipe_gbce *gbce = &ipipe->config.gbce; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - - if (!gbce_param) { - memset(gbce, 0, sizeof(struct vpfe_ipipe_gbce)); - } else { - memcpy(gbce, gbce_param, sizeof(struct vpfe_ipipe_gbce)); - if (ipipe_validate_gbce_params(gbce) < 0) { - dev_err(dev, "Invalid gbce params\n"); - return -EINVAL; - } - } - - ipipe_set_gbce_regs(ipipe->base_addr, ipipe->isp5_base_addr, gbce); - - return 0; -} - -static int ipipe_get_gbce_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gbce *gbce_param = param; - struct vpfe_ipipe_gbce *gbce = &ipipe->config.gbce; - - gbce_param->en = gbce->en; - gbce_param->type = gbce->type; - - memcpy(gbce_param->table, gbce->table, - (VPFE_IPIPE_MAX_SIZE_GBCE_LUT * sizeof(unsigned short))); - - return 0; -} - -static int -ipipe_validate_yuv422_conv_params(struct vpfe_ipipe_yuv422_conv *yuv422_conv) -{ - if (yuv422_conv->en_chrom_lpf > 1) - return -EINVAL; - - return 0; -} - -static int -ipipe_set_yuv422_conv_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_yuv422_conv *yuv422_conv = &ipipe->config.yuv422_conv; - struct vpfe_ipipe_yuv422_conv *yuv422_conv_param; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - - yuv422_conv_param = param; - if (!yuv422_conv_param) { - memset(yuv422_conv, 0, sizeof(struct vpfe_ipipe_yuv422_conv)); - yuv422_conv->chrom_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE; - } else { - memcpy(yuv422_conv, yuv422_conv_param, - sizeof(struct vpfe_ipipe_yuv422_conv)); - if (ipipe_validate_yuv422_conv_params(yuv422_conv) < 0) { - dev_err(dev, "Invalid yuv422 params\n"); - return -EINVAL; - } - } - - ipipe_set_yuv422_conv_regs(ipipe->base_addr, yuv422_conv); - - return 0; -} - -static int -ipipe_get_yuv422_conv_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_yuv422_conv *yuv422_conv = &ipipe->config.yuv422_conv; - struct vpfe_ipipe_yuv422_conv *yuv422_conv_param; - - yuv422_conv_param = param; - memcpy(yuv422_conv_param, yuv422_conv, - sizeof(struct vpfe_ipipe_yuv422_conv)); - - return 0; -} - -static int ipipe_validate_yee_params(struct vpfe_ipipe_yee *yee) -{ - int i; - - if (yee->en > 1 || - yee->en_halo_red > 1 || - yee->hpf_shft > YEE_HPF_SHIFT_MASK) - return -EINVAL; - - if (yee->hpf_coef_00 > YEE_COEF_MASK || - yee->hpf_coef_01 > YEE_COEF_MASK || - yee->hpf_coef_02 > YEE_COEF_MASK || - yee->hpf_coef_10 > YEE_COEF_MASK || - yee->hpf_coef_11 > YEE_COEF_MASK || - yee->hpf_coef_12 > YEE_COEF_MASK || - yee->hpf_coef_20 > YEE_COEF_MASK || - yee->hpf_coef_21 > YEE_COEF_MASK || - yee->hpf_coef_22 > YEE_COEF_MASK) - return -EINVAL; - - if (yee->yee_thr > YEE_THR_MASK || - yee->es_gain > YEE_ES_GAIN_MASK || - yee->es_thr1 > YEE_ES_THR1_MASK || - yee->es_thr2 > YEE_THR_MASK || - yee->es_gain_grad > YEE_THR_MASK || - yee->es_ofst_grad > YEE_THR_MASK) - return -EINVAL; - - for (i = 0; i < VPFE_IPIPE_MAX_SIZE_YEE_LUT; i++) - if (yee->table[i] > YEE_ENTRY_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_yee_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_yee *yee_param = param; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_yee *yee = &ipipe->config.yee; - - if (!yee_param) { - memset(yee, 0, sizeof(struct vpfe_ipipe_yee)); - } else { - memcpy(yee, yee_param, sizeof(struct vpfe_ipipe_yee)); - if (ipipe_validate_yee_params(yee) < 0) { - dev_err(dev, "Invalid yee params\n"); - return -EINVAL; - } - } - - ipipe_set_ee_regs(ipipe->base_addr, ipipe->isp5_base_addr, yee); - - return 0; -} - -static int ipipe_get_yee_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_yee *yee_param = param; - struct vpfe_ipipe_yee *yee = &ipipe->config.yee; - - yee_param->en = yee->en; - yee_param->en_halo_red = yee->en_halo_red; - yee_param->merge_meth = yee->merge_meth; - yee_param->hpf_shft = yee->hpf_shft; - yee_param->hpf_coef_00 = yee->hpf_coef_00; - yee_param->hpf_coef_01 = yee->hpf_coef_01; - yee_param->hpf_coef_02 = yee->hpf_coef_02; - yee_param->hpf_coef_10 = yee->hpf_coef_10; - yee_param->hpf_coef_11 = yee->hpf_coef_11; - yee_param->hpf_coef_12 = yee->hpf_coef_12; - yee_param->hpf_coef_20 = yee->hpf_coef_20; - yee_param->hpf_coef_21 = yee->hpf_coef_21; - yee_param->hpf_coef_22 = yee->hpf_coef_22; - yee_param->yee_thr = yee->yee_thr; - yee_param->es_gain = yee->es_gain; - yee_param->es_thr1 = yee->es_thr1; - yee_param->es_thr2 = yee->es_thr2; - yee_param->es_gain_grad = yee->es_gain_grad; - yee_param->es_ofst_grad = yee->es_ofst_grad; - memcpy(yee_param->table, &yee->table, - (VPFE_IPIPE_MAX_SIZE_YEE_LUT * sizeof(short))); - - return 0; -} - -static int ipipe_validate_car_params(struct vpfe_ipipe_car *car) -{ - if (car->en > 1 || car->hpf_shft > CAR_HPF_SHIFT_MASK || - car->gain1.shft > CAR_GAIN1_SHFT_MASK || - car->gain1.gain_min > CAR_GAIN_MIN_MASK || - car->gain2.shft > CAR_GAIN2_SHFT_MASK || - car->gain2.gain_min > CAR_GAIN_MIN_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_car_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_car *car_param = param; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_car *car = &ipipe->config.car; - - if (!car_param) { - memset(car, 0, sizeof(struct vpfe_ipipe_car)); - } else { - memcpy(car, car_param, sizeof(struct vpfe_ipipe_car)); - if (ipipe_validate_car_params(car) < 0) { - dev_err(dev, "Invalid car params\n"); - return -EINVAL; - } - } - - ipipe_set_car_regs(ipipe->base_addr, car); - - return 0; -} - -static int ipipe_get_car_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_car *car_param = param; - struct vpfe_ipipe_car *car = &ipipe->config.car; - - memcpy(car_param, car, sizeof(struct vpfe_ipipe_car)); - return 0; -} - -static int ipipe_validate_cgs_params(struct vpfe_ipipe_cgs *cgs) -{ - if (cgs->en > 1 || cgs->h_shft > CAR_SHIFT_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_cgs_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_cgs *cgs_param = param; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_cgs *cgs = &ipipe->config.cgs; - - if (!cgs_param) { - memset(cgs, 0, sizeof(struct vpfe_ipipe_cgs)); - } else { - memcpy(cgs, cgs_param, sizeof(struct vpfe_ipipe_cgs)); - if (ipipe_validate_cgs_params(cgs) < 0) { - dev_err(dev, "Invalid cgs params\n"); - return -EINVAL; - } - } - - ipipe_set_cgs_regs(ipipe->base_addr, cgs); - - return 0; -} - -static int ipipe_get_cgs_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_cgs *cgs_param = param; - struct vpfe_ipipe_cgs *cgs = &ipipe->config.cgs; - - memcpy(cgs_param, cgs, sizeof(struct vpfe_ipipe_cgs)); - - return 0; -} - -static const struct ipipe_module_if ipipe_modules[VPFE_IPIPE_MAX_MODULES] = { - /* VPFE_IPIPE_INPUT_CONFIG */ { - offsetof(struct ipipe_module_params, input_config), - FIELD_SIZEOF(struct ipipe_module_params, input_config), - offsetof(struct vpfe_ipipe_config, input_config), - ipipe_set_input_config, - ipipe_get_input_config, - }, /* VPFE_IPIPE_LUTDPC */ { - offsetof(struct ipipe_module_params, lutdpc), - FIELD_SIZEOF(struct ipipe_module_params, lutdpc), - offsetof(struct vpfe_ipipe_config, lutdpc), - ipipe_set_lutdpc_params, - ipipe_get_lutdpc_params, - }, /* VPFE_IPIPE_OTFDPC */ { - offsetof(struct ipipe_module_params, otfdpc), - FIELD_SIZEOF(struct ipipe_module_params, otfdpc), - offsetof(struct vpfe_ipipe_config, otfdpc), - ipipe_set_otfdpc_params, - ipipe_get_otfdpc_params, - }, /* VPFE_IPIPE_NF1 */ { - offsetof(struct ipipe_module_params, nf1), - FIELD_SIZEOF(struct ipipe_module_params, nf1), - offsetof(struct vpfe_ipipe_config, nf1), - ipipe_set_nf1_params, - ipipe_get_nf1_params, - }, /* VPFE_IPIPE_NF2 */ { - offsetof(struct ipipe_module_params, nf2), - FIELD_SIZEOF(struct ipipe_module_params, nf2), - offsetof(struct vpfe_ipipe_config, nf2), - ipipe_set_nf2_params, - ipipe_get_nf2_params, - }, /* VPFE_IPIPE_WB */ { - offsetof(struct ipipe_module_params, wbal), - FIELD_SIZEOF(struct ipipe_module_params, wbal), - offsetof(struct vpfe_ipipe_config, wbal), - ipipe_set_wb_params, - ipipe_get_wb_params, - }, /* VPFE_IPIPE_RGB2RGB_1 */ { - offsetof(struct ipipe_module_params, rgb2rgb1), - FIELD_SIZEOF(struct ipipe_module_params, rgb2rgb1), - offsetof(struct vpfe_ipipe_config, rgb2rgb1), - ipipe_set_rgb2rgb_1_params, - ipipe_get_rgb2rgb_1_params, - }, /* VPFE_IPIPE_RGB2RGB_2 */ { - offsetof(struct ipipe_module_params, rgb2rgb2), - FIELD_SIZEOF(struct ipipe_module_params, rgb2rgb2), - offsetof(struct vpfe_ipipe_config, rgb2rgb2), - ipipe_set_rgb2rgb_2_params, - ipipe_get_rgb2rgb_2_params, - }, /* VPFE_IPIPE_GAMMA */ { - offsetof(struct ipipe_module_params, gamma), - FIELD_SIZEOF(struct ipipe_module_params, gamma), - offsetof(struct vpfe_ipipe_config, gamma), - ipipe_set_gamma_params, - ipipe_get_gamma_params, - }, /* VPFE_IPIPE_3D_LUT */ { - offsetof(struct ipipe_module_params, lut), - FIELD_SIZEOF(struct ipipe_module_params, lut), - offsetof(struct vpfe_ipipe_config, lut), - ipipe_set_3d_lut_params, - ipipe_get_3d_lut_params, - }, /* VPFE_IPIPE_RGB2YUV */ { - offsetof(struct ipipe_module_params, rgb2yuv), - FIELD_SIZEOF(struct ipipe_module_params, rgb2yuv), - offsetof(struct vpfe_ipipe_config, rgb2yuv), - ipipe_set_rgb2yuv_params, - ipipe_get_rgb2yuv_params, - }, /* VPFE_IPIPE_YUV422_CONV */ { - offsetof(struct ipipe_module_params, yuv422_conv), - FIELD_SIZEOF(struct ipipe_module_params, yuv422_conv), - offsetof(struct vpfe_ipipe_config, yuv422_conv), - ipipe_set_yuv422_conv_params, - ipipe_get_yuv422_conv_params, - }, /* VPFE_IPIPE_YEE */ { - offsetof(struct ipipe_module_params, yee), - FIELD_SIZEOF(struct ipipe_module_params, yee), - offsetof(struct vpfe_ipipe_config, yee), - ipipe_set_yee_params, - ipipe_get_yee_params, - }, /* VPFE_IPIPE_GIC */ { - offsetof(struct ipipe_module_params, gic), - FIELD_SIZEOF(struct ipipe_module_params, gic), - offsetof(struct vpfe_ipipe_config, gic), - ipipe_set_gic_params, - ipipe_get_gic_params, - }, /* VPFE_IPIPE_CFA */ { - offsetof(struct ipipe_module_params, cfa), - FIELD_SIZEOF(struct ipipe_module_params, cfa), - offsetof(struct vpfe_ipipe_config, cfa), - ipipe_set_cfa_params, - ipipe_get_cfa_params, - }, /* VPFE_IPIPE_CAR */ { - offsetof(struct ipipe_module_params, car), - FIELD_SIZEOF(struct ipipe_module_params, car), - offsetof(struct vpfe_ipipe_config, car), - ipipe_set_car_params, - ipipe_get_car_params, - }, /* VPFE_IPIPE_CGS */ { - offsetof(struct ipipe_module_params, cgs), - FIELD_SIZEOF(struct ipipe_module_params, cgs), - offsetof(struct vpfe_ipipe_config, cgs), - ipipe_set_cgs_params, - ipipe_get_cgs_params, - }, /* VPFE_IPIPE_GBCE */ { - offsetof(struct ipipe_module_params, gbce), - FIELD_SIZEOF(struct ipipe_module_params, gbce), - offsetof(struct vpfe_ipipe_config, gbce), - ipipe_set_gbce_params, - ipipe_get_gbce_params, - }, -}; - -static int ipipe_s_config(struct v4l2_subdev *sd, struct vpfe_ipipe_config *cfg) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - unsigned int i; - int rval = 0; - struct ipipe_module_params *params; - - for (i = 0; i < ARRAY_SIZE(ipipe_modules); i++) { - const struct ipipe_module_if *module_if; - void *from, *to; - size_t size; - - if (!(cfg->flag & BIT(i))) - continue; - - module_if = &ipipe_modules[i]; - from = *(void **)((void *)cfg + module_if->config_offset); - - params = kmalloc(sizeof(*params), GFP_KERNEL); - if (!params) - return -ENOMEM; - to = (void *)params + module_if->param_offset; - size = module_if->param_size; - - if (to && from && size) { - if (copy_from_user(to, (void __user *)from, size)) { - rval = -EFAULT; - goto error_free; - } - rval = module_if->set(ipipe, to); - if (rval) - goto error_free; - } else if (to && !from && size) { - rval = module_if->set(ipipe, NULL); - if (rval) - goto error_free; - } - kfree(params); - } - return rval; - -error_free: - kfree(params); - return rval; -} - -static int ipipe_g_config(struct v4l2_subdev *sd, struct vpfe_ipipe_config *cfg) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - unsigned int i; - int rval = 0; - - for (i = 1; i < ARRAY_SIZE(ipipe_modules); i++) { - const struct ipipe_module_if *module_if; - struct ipipe_module_params *params; - void *from, *to; - size_t size; - - if (!(cfg->flag & BIT(i))) - continue; - - module_if = &ipipe_modules[i]; - to = *(void **)((void *)cfg + module_if->config_offset); - - params = kmalloc(sizeof(*params), GFP_KERNEL); - from = (void *)params + module_if->param_offset; - size = module_if->param_size; - - if (to && from && size) { - rval = module_if->get(ipipe, from); - if (rval) - goto error; - if (copy_to_user((void __user *)to, from, size)) { - rval = -EFAULT; - break; - } - } - kfree(params); - } -error: - return rval; -} - -/* - * ipipe_ioctl() - Handle ipipe module private ioctl's - * @sd: pointer to v4l2 subdev structure - * @cmd: configuration command - * @arg: configuration argument - */ -static long ipipe_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - switch (cmd) { - case VIDIOC_VPFE_IPIPE_S_CONFIG: - return ipipe_s_config(sd, arg); - - case VIDIOC_VPFE_IPIPE_G_CONFIG: - return ipipe_g_config(sd, arg); - - default: - return -ENOIOCTLCMD; - } -} - -void vpfe_ipipe_enable(struct vpfe_device *vpfe_dev, int en) -{ - struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif; - struct vpfe_ipipe_device *ipipe = &vpfe_dev->vpfe_ipipe; - unsigned char val; - - if (ipipe->input == IPIPE_INPUT_NONE) - return; - - /* ipipe is set to single shot */ - if (ipipeif->input == IPIPEIF_INPUT_MEMORY && en) { - /* for single-shot mode, need to wait for h/w to - * reset many register bits - */ - do { - val = regr_ip(vpfe_dev->vpfe_ipipe.base_addr, - IPIPE_SRC_EN); - } while (val); - } - regw_ip(vpfe_dev->vpfe_ipipe.base_addr, en, IPIPE_SRC_EN); -} - -/* - * ipipe_set_stream() - Enable/Disable streaming on the ipipe subdevice - * @sd: pointer to v4l2 subdev structure - * @enable: 1 == Enable, 0 == Disable - */ -static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe_dev = to_vpfe_device(ipipe); - - if (enable && ipipe->input != IPIPE_INPUT_NONE && - ipipe->output != IPIPE_OUTPUT_NONE) { - if (config_ipipe_hw(ipipe) < 0) - return -EINVAL; - } - - vpfe_ipipe_enable(vpfe_dev, enable); - - return 0; -} - -/* - * __ipipe_get_format() - helper function for getting ipipe format - * @ipipe: pointer to ipipe private structure. - * @pad: pad number. - * @cfg: V4L2 subdev pad config - * @which: wanted subdev format. - * - */ -static struct v4l2_mbus_framefmt * -__ipipe_get_format(struct vpfe_ipipe_device *ipipe, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ipipe->subdev, cfg, pad); - - return &ipipe->formats[pad]; -} - -/* - * ipipe_try_format() - Handle try format by pad subdev method - * @ipipe: VPFE ipipe device. - * @cfg: V4L2 subdev pad config - * @pad: pad num. - * @fmt: pointer to v4l2 format structure. - * @which : wanted subdev format - */ -static void -ipipe_try_format(struct vpfe_ipipe_device *ipipe, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, - struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - unsigned int max_out_height; - unsigned int max_out_width; - unsigned int i; - - max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A; - max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A; - - if (pad == IPIPE_PAD_SINK) { - for (i = 0; i < ARRAY_SIZE(ipipe_input_fmts); i++) - if (fmt->code == ipipe_input_fmts[i]) - break; - - /* If not found, use SBGGR10 as default */ - if (i >= ARRAY_SIZE(ipipe_input_fmts)) - fmt->code = MEDIA_BUS_FMT_SGRBG12_1X12; - } else if (pad == IPIPE_PAD_SOURCE) { - for (i = 0; i < ARRAY_SIZE(ipipe_output_fmts); i++) - if (fmt->code == ipipe_output_fmts[i]) - break; - - /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(ipipe_output_fmts)) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; - } - - fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width); - fmt->height = clamp_t(u32, fmt->height, MIN_OUT_WIDTH, max_out_height); -} - -/* - * ipipe_set_format() - Handle set format by pads subdev method - * @sd: pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int -ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - return 0; - - if (fmt->pad == IPIPE_PAD_SINK && - (ipipe->input == IPIPE_INPUT_CCDC || - ipipe->input == IPIPE_INPUT_MEMORY)) - ipipe->formats[fmt->pad] = fmt->format; - else if (fmt->pad == IPIPE_PAD_SOURCE && - ipipe->output == IPIPE_OUTPUT_RESIZER) - ipipe->formats[fmt->pad] = fmt->format; - else - return -EINVAL; - - return 0; -} - -/* - * ipipe_get_format() - Handle get format by pads subdev method. - * @sd: pointer to v4l2 subdev structure. - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure. - */ -static int -ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - fmt->format = ipipe->formats[fmt->pad]; - else - fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad)); - - return 0; -} - -/* - * ipipe_enum_frame_size() - enum frame sizes on pads - * @sd: pointer to v4l2 subdev structure. - * @cfg: V4L2 subdev pad config - * @fse: pointer to v4l2_subdev_frame_size_enum structure. - */ -static int -ipipe_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * ipipe_enum_mbus_code() - enum mbus codes for pads - * @sd: pointer to v4l2 subdev structure. - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - */ -static int -ipipe_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - switch (code->pad) { - case IPIPE_PAD_SINK: - if (code->index >= ARRAY_SIZE(ipipe_input_fmts)) - return -EINVAL; - code->code = ipipe_input_fmts[code->index]; - break; - - case IPIPE_PAD_SOURCE: - if (code->index >= ARRAY_SIZE(ipipe_output_fmts)) - return -EINVAL; - code->code = ipipe_output_fmts[code->index]; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * ipipe_s_ctrl() - Handle set control subdev method - * @ctrl: pointer to v4l2 control structure - */ -static int ipipe_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vpfe_ipipe_device *ipipe = - container_of(ctrl->handler, struct vpfe_ipipe_device, ctrls); - struct ipipe_lum_adj *lum_adj = &ipipe->config.lum_adj; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - lum_adj->brightness = ctrl->val; - ipipe_set_lum_adj_regs(ipipe->base_addr, lum_adj); - break; - - case V4L2_CID_CONTRAST: - lum_adj->contrast = ctrl->val; - ipipe_set_lum_adj_regs(ipipe->base_addr, lum_adj); - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * ipipe_init_formats() - Initialize formats on all pads - * @sd: pointer to v4l2 subdev structure. - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. Try formats are initialized - * on the file handle. - */ -static int -ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = IPIPE_PAD_SINK; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipe_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = IPIPE_PAD_SOURCE; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipe_set_format(sd, fh->pad, &format); - - return 0; -} - -/* subdev core operations */ -static const struct v4l2_subdev_core_ops ipipe_v4l2_core_ops = { - .ioctl = ipipe_ioctl, -}; - -static const struct v4l2_ctrl_ops ipipe_ctrl_ops = { - .s_ctrl = ipipe_s_ctrl, -}; - -/* subdev file operations */ -static const struct v4l2_subdev_internal_ops ipipe_v4l2_internal_ops = { - .open = ipipe_init_formats, -}; - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops ipipe_v4l2_video_ops = { - .s_stream = ipipe_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops ipipe_v4l2_pad_ops = { - .enum_mbus_code = ipipe_enum_mbus_code, - .enum_frame_size = ipipe_enum_frame_size, - .get_fmt = ipipe_get_format, - .set_fmt = ipipe_set_format, -}; - -/* v4l2 subdev operation */ -static const struct v4l2_subdev_ops ipipe_v4l2_ops = { - .core = &ipipe_v4l2_core_ops, - .video = &ipipe_v4l2_video_ops, - .pad = &ipipe_v4l2_pad_ops, -}; - -/* - * Media entity operations - */ - -/* - * ipipe_link_setup() - Setup ipipe connections - * @entity: ipipe media entity - * @local: Pad at the local end of the link - * @remote: Pad at the remote end of the link - * @flags: Link flags - * - * return -EINVAL or zero on success - */ -static int -ipipe_link_setup(struct media_entity *entity, const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe_dev = to_vpfe_device(ipipe); - u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; - - if (!is_media_entity_v4l2_subdev(remote->entity)) - return -EINVAL; - - switch (local->index) { - case IPIPE_PAD_SINK: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ipipe->input = IPIPE_INPUT_NONE; - break; - } - if (ipipe->input != IPIPE_INPUT_NONE) - return -EBUSY; - if (ipipeif_sink == IPIPEIF_INPUT_MEMORY) - ipipe->input = IPIPE_INPUT_MEMORY; - else - ipipe->input = IPIPE_INPUT_CCDC; - break; - - case IPIPE_PAD_SOURCE: - /* out to RESIZER */ - if (flags & MEDIA_LNK_FL_ENABLED) - ipipe->output = IPIPE_OUTPUT_RESIZER; - else - ipipe->output = IPIPE_OUTPUT_NONE; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static const struct media_entity_operations ipipe_media_ops = { - .link_setup = ipipe_link_setup, -}; - -/* - * vpfe_ipipe_unregister_entities() - ipipe unregister entity - * @vpfe_ipipe: pointer to ipipe subdevice structure. - */ -void vpfe_ipipe_unregister_entities(struct vpfe_ipipe_device *vpfe_ipipe) -{ - /* unregister subdev */ - v4l2_device_unregister_subdev(&vpfe_ipipe->subdev); - /* cleanup entity */ - media_entity_cleanup(&vpfe_ipipe->subdev.entity); -} - -/* - * vpfe_ipipe_register_entities() - ipipe register entity - * @ipipe: pointer to ipipe subdevice structure. - * @vdev: pointer to v4l2 device structure. - */ -int -vpfe_ipipe_register_entities(struct vpfe_ipipe_device *ipipe, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev */ - ret = v4l2_device_register_subdev(vdev, &ipipe->subdev); - if (ret) { - pr_err("Failed to register ipipe as v4l2 subdevice\n"); - return ret; - } - - return ret; -} - -#define IPIPE_CONTRAST_HIGH 0xff -#define IPIPE_BRIGHT_HIGH 0xff - -/* - * vpfe_ipipe_init() - ipipe module initialization. - * @ipipe: pointer to ipipe subdevice structure. - * @pdev: platform device pointer. - */ -int -vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe, struct platform_device *pdev) -{ - struct media_pad *pads = &ipipe->pads[0]; - struct v4l2_subdev *sd = &ipipe->subdev; - struct media_entity *me = &sd->entity; - struct resource *res, *res2, *memres; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 4); - if (!res) - return -ENOENT; - - memres = request_mem_region(res->start, resource_size(res), res->name); - if (!memres) - return -EBUSY; - ipipe->base_addr = ioremap_nocache(memres->start, - resource_size(memres)); - if (!ipipe->base_addr) - goto error_release; - - res2 = platform_get_resource(pdev, IORESOURCE_MEM, 6); - if (!res2) - goto error_unmap; - ipipe->isp5_base_addr = ioremap_nocache(res2->start, - resource_size(res2)); - if (!ipipe->isp5_base_addr) - goto error_unmap; - - v4l2_subdev_init(sd, &ipipe_v4l2_ops); - sd->internal_ops = &ipipe_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI IPIPE", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - v4l2_set_subdevdata(sd, ipipe); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[IPIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[IPIPE_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - ipipe->input = IPIPE_INPUT_NONE; - ipipe->output = IPIPE_OUTPUT_NONE; - - me->ops = &ipipe_media_ops; - v4l2_ctrl_handler_init(&ipipe->ctrls, 2); - v4l2_ctrl_new_std(&ipipe->ctrls, &ipipe_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, - IPIPE_BRIGHT_HIGH, 1, 16); - v4l2_ctrl_new_std(&ipipe->ctrls, &ipipe_ctrl_ops, - V4L2_CID_CONTRAST, 0, - IPIPE_CONTRAST_HIGH, 1, 16); - v4l2_ctrl_handler_setup(&ipipe->ctrls); - sd->ctrl_handler = &ipipe->ctrls; - - return media_entity_pads_init(me, IPIPE_PADS_NUM, pads); - -error_unmap: - iounmap(ipipe->base_addr); -error_release: - release_mem_region(memres->start, resource_size(memres)); - return -ENOMEM; -} - -/* - * vpfe_ipipe_cleanup() - ipipe subdevice cleanup. - * @ipipe: pointer to ipipe subdevice - * @dev: pointer to platform device - */ -void vpfe_ipipe_cleanup(struct vpfe_ipipe_device *ipipe, - struct platform_device *pdev) -{ - struct resource *res; - - v4l2_ctrl_handler_free(&ipipe->ctrls); - - iounmap(ipipe->base_addr); - iounmap(ipipe->isp5_base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 4); - if (res) - release_mem_region(res->start, resource_size(res)); -} diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.h b/drivers/staging/media/davinci_vpfe/dm365_ipipe.h deleted file mode 100644 index 866ae12aeb07..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.h +++ /dev/null @@ -1,174 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#ifndef _DAVINCI_VPFE_DM365_IPIPE_H -#define _DAVINCI_VPFE_DM365_IPIPE_H - -#include <linux/platform_device.h> - -#include <media/v4l2-ctrls.h> -#include <media/v4l2-subdev.h> - -#include "davinci_vpfe_user.h" -#include "vpfe_video.h" - -enum ipipe_noise_filter { - IPIPE_D2F_1ST = 0, - IPIPE_D2F_2ND = 1, -}; - -/* Used for driver storage */ -struct ipipe_otfdpc_2_0 { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* defect detection method */ - enum vpfe_ipipe_otfdpc_det_meth det_method; - /* Algorithm used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is - * used - */ - enum vpfe_ipipe_otfdpc_alg alg; - struct vpfe_ipipe_otfdpc_2_0_cfg otfdpc_2_0; -}; - -struct ipipe_otfdpc_3_0 { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* defect detection method */ - enum vpfe_ipipe_otfdpc_det_meth det_method; - /* Algorithm used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is - * used - */ - enum vpfe_ipipe_otfdpc_alg alg; - struct vpfe_ipipe_otfdpc_3_0_cfg otfdpc_3_0; -}; - -/* Structure for configuring Luminance Adjustment module */ -struct ipipe_lum_adj { - /* Brightness adjustments */ - unsigned char brightness; - /* contrast adjustments */ - unsigned char contrast; -}; - -enum ipipe_rgb2rgb { - IPIPE_RGB2RGB_1 = 0, - IPIPE_RGB2RGB_2 = 1, -}; - -struct ipipe_module_params { - __u32 flag; - struct vpfe_ipipe_input_config input_config; - struct vpfe_ipipe_lutdpc lutdpc; - struct vpfe_ipipe_otfdpc otfdpc; - struct vpfe_ipipe_nf nf1; - struct vpfe_ipipe_nf nf2; - struct vpfe_ipipe_gic gic; - struct vpfe_ipipe_wb wbal; - struct vpfe_ipipe_cfa cfa; - struct vpfe_ipipe_rgb2rgb rgb2rgb1; - struct vpfe_ipipe_rgb2rgb rgb2rgb2; - struct vpfe_ipipe_gamma gamma; - struct vpfe_ipipe_3d_lut lut; - struct vpfe_ipipe_rgb2yuv rgb2yuv; - struct vpfe_ipipe_gbce gbce; - struct vpfe_ipipe_yuv422_conv yuv422_conv; - struct vpfe_ipipe_yee yee; - struct vpfe_ipipe_car car; - struct vpfe_ipipe_cgs cgs; - struct ipipe_lum_adj lum_adj; -}; - -#define IPIPE_PAD_SINK 0 -#define IPIPE_PAD_SOURCE 1 - -#define IPIPE_PADS_NUM 2 - -#define IPIPE_OUTPUT_NONE 0 -#define IPIPE_OUTPUT_RESIZER (1 << 0) - -enum ipipe_input_entity { - IPIPE_INPUT_NONE = 0, - IPIPE_INPUT_MEMORY = 1, - IPIPE_INPUT_CCDC = 2, -}; - - -struct vpfe_ipipe_device { - struct v4l2_subdev subdev; - struct media_pad pads[IPIPE_PADS_NUM]; - struct v4l2_mbus_framefmt formats[IPIPE_PADS_NUM]; - enum ipipe_input_entity input; - unsigned int output; - struct v4l2_ctrl_handler ctrls; - void __iomem *base_addr; - void __iomem *isp5_base_addr; - struct ipipe_module_params config; -}; - -struct ipipe_module_if { - unsigned int param_offset; - unsigned int param_size; - unsigned int config_offset; - int (*set)(struct vpfe_ipipe_device *ipipe, void *param); - int (*get)(struct vpfe_ipipe_device *ipipe, void *param); -}; - -/* data paths */ -enum ipipe_data_paths { - IPIPE_RAW2YUV, - /* Bayer RAW input to YCbCr output */ - IPIPE_RAW2RAW, - /* Bayer Raw to Bayer output */ - IPIPE_RAW2BOX, - /* Bayer Raw to Boxcar output */ - IPIPE_YUV2YUV - /* YUV Raw to YUV Raw output */ -}; - -#define IPIPE_COLPTN_R_Ye 0x0 -#define IPIPE_COLPTN_Gr_Cy 0x1 -#define IPIPE_COLPTN_Gb_G 0x2 -#define IPIPE_COLPTN_B_Mg 0x3 - -#define COLPAT_EE_SHIFT 0 -#define COLPAT_EO_SHIFT 2 -#define COLPAT_OE_SHIFT 4 -#define COLPAT_OO_SHIFT 6 - -#define ipipe_sgrbg_pattern \ - (IPIPE_COLPTN_Gr_Cy << COLPAT_EE_SHIFT | \ - IPIPE_COLPTN_R_Ye << COLPAT_EO_SHIFT | \ - IPIPE_COLPTN_B_Mg << COLPAT_OE_SHIFT | \ - IPIPE_COLPTN_Gb_G << COLPAT_OO_SHIFT) - -#define ipipe_srggb_pattern \ - (IPIPE_COLPTN_R_Ye << COLPAT_EE_SHIFT | \ - IPIPE_COLPTN_Gr_Cy << COLPAT_EO_SHIFT | \ - IPIPE_COLPTN_Gb_G << COLPAT_OE_SHIFT | \ - IPIPE_COLPTN_B_Mg << COLPAT_OO_SHIFT) - -int vpfe_ipipe_register_entities(struct vpfe_ipipe_device *ipipe, - struct v4l2_device *v4l2_dev); -int vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe, - struct platform_device *pdev); -void vpfe_ipipe_unregister_entities(struct vpfe_ipipe_device *ipipe); -void vpfe_ipipe_cleanup(struct vpfe_ipipe_device *ipipe, - struct platform_device *pdev); -void vpfe_ipipe_enable(struct vpfe_device *vpfe_dev, int en); - -#endif /* _DAVINCI_VPFE_DM365_IPIPE_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c deleted file mode 100644 index 110473c30577..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c +++ /dev/null @@ -1,1038 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#include "dm365_ipipe_hw.h" - -#define IPIPE_MODE_CONTINUOUS 0 -#define IPIPE_MODE_SINGLE_SHOT 1 - -static void ipipe_clock_enable(void __iomem *base_addr) -{ - /* enable IPIPE MMR for register write access */ - regw_ip(base_addr, IPIPE_GCK_MMR_DEFAULT, IPIPE_GCK_MMR); - - /* enable the clock wb,cfa,dfc,d2f,pre modules */ - regw_ip(base_addr, IPIPE_GCK_PIX_DEFAULT, IPIPE_GCK_PIX); -} - -static void -rsz_set_common_params(void __iomem *rsz_base, struct resizer_params *params) -{ - struct rsz_common_params *rsz_common = ¶ms->rsz_common; - u32 val; - - /* Set mode */ - regw_rsz(rsz_base, params->oper_mode, RSZ_SRC_MODE); - - /* data source selection and bypass */ - val = (rsz_common->passthrough << RSZ_BYPASS_SHIFT) | - rsz_common->source; - regw_rsz(rsz_base, val, RSZ_SRC_FMT0); - - /* src image selection */ - val = (rsz_common->raw_flip & 1) | - (rsz_common->src_img_fmt << RSZ_SRC_IMG_FMT_SHIFT) | - ((rsz_common->y_c & 1) << RSZ_SRC_Y_C_SEL_SHIFT); - regw_rsz(rsz_base, val, RSZ_SRC_FMT1); - - regw_rsz(rsz_base, rsz_common->vps & IPIPE_RSZ_VPS_MASK, RSZ_SRC_VPS); - regw_rsz(rsz_base, rsz_common->hps & IPIPE_RSZ_HPS_MASK, RSZ_SRC_HPS); - regw_rsz(rsz_base, rsz_common->vsz & IPIPE_RSZ_VSZ_MASK, RSZ_SRC_VSZ); - regw_rsz(rsz_base, rsz_common->hsz & IPIPE_RSZ_HSZ_MASK, RSZ_SRC_HSZ); - regw_rsz(rsz_base, rsz_common->yuv_y_min, RSZ_YUV_Y_MIN); - regw_rsz(rsz_base, rsz_common->yuv_y_max, RSZ_YUV_Y_MAX); - regw_rsz(rsz_base, rsz_common->yuv_c_min, RSZ_YUV_C_MIN); - regw_rsz(rsz_base, rsz_common->yuv_c_max, RSZ_YUV_C_MAX); - /* chromatic position */ - regw_rsz(rsz_base, rsz_common->out_chr_pos, RSZ_YUV_PHS); -} - -static void -rsz_set_rsz_regs(void __iomem *rsz_base, unsigned int rsz_id, - struct resizer_params *params) -{ - struct resizer_scale_param *rsc_params; - struct rsz_ext_mem_param *ext_mem; - struct resizer_rgb *rgb; - u32 reg_base; - u32 val; - - rsc_params = ¶ms->rsz_rsc_param[rsz_id]; - rgb = ¶ms->rsz2rgb[rsz_id]; - ext_mem = ¶ms->ext_mem_param[rsz_id]; - - if (rsz_id == RSZ_A) { - val = rsc_params->h_flip << RSZA_H_FLIP_SHIFT; - val |= rsc_params->v_flip << RSZA_V_FLIP_SHIFT; - reg_base = RSZ_EN_A; - } else { - val = rsc_params->h_flip << RSZB_H_FLIP_SHIFT; - val |= rsc_params->v_flip << RSZB_V_FLIP_SHIFT; - reg_base = RSZ_EN_B; - } - /* update flip settings */ - regw_rsz(rsz_base, val, RSZ_SEQ); - - regw_rsz(rsz_base, params->oper_mode, reg_base + RSZ_MODE); - - val = (rsc_params->cen << RSZ_CEN_SHIFT) | rsc_params->yen; - regw_rsz(rsz_base, val, reg_base + RSZ_420); - - regw_rsz(rsz_base, rsc_params->i_vps & RSZ_VPS_MASK, - reg_base + RSZ_I_VPS); - regw_rsz(rsz_base, rsc_params->i_hps & RSZ_HPS_MASK, - reg_base + RSZ_I_HPS); - regw_rsz(rsz_base, rsc_params->o_vsz & RSZ_O_VSZ_MASK, - reg_base + RSZ_O_VSZ); - regw_rsz(rsz_base, rsc_params->o_hsz & RSZ_O_HSZ_MASK, - reg_base + RSZ_O_HSZ); - regw_rsz(rsz_base, rsc_params->v_phs_y & RSZ_V_PHS_MASK, - reg_base + RSZ_V_PHS_Y); - regw_rsz(rsz_base, rsc_params->v_phs_c & RSZ_V_PHS_MASK, - reg_base + RSZ_V_PHS_C); - - /* keep this additional adjustment to zero for now */ - regw_rsz(rsz_base, rsc_params->v_dif & RSZ_V_DIF_MASK, - reg_base + RSZ_V_DIF); - - val = (rsc_params->v_typ_y & 1) | - ((rsc_params->v_typ_c & 1) << RSZ_TYP_C_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_V_TYP); - - val = (rsc_params->v_lpf_int_y & RSZ_LPF_INT_MASK) | - ((rsc_params->v_lpf_int_c & RSZ_LPF_INT_MASK) << - RSZ_LPF_INT_C_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_V_LPF); - - regw_rsz(rsz_base, rsc_params->h_phs & - RSZ_H_PHS_MASK, reg_base + RSZ_H_PHS); - - regw_rsz(rsz_base, 0, reg_base + RSZ_H_PHS_ADJ); - regw_rsz(rsz_base, rsc_params->h_dif & - RSZ_H_DIF_MASK, reg_base + RSZ_H_DIF); - - val = (rsc_params->h_typ_y & 1) | - ((rsc_params->h_typ_c & 1) << RSZ_TYP_C_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_H_TYP); - - val = (rsc_params->h_lpf_int_y & RSZ_LPF_INT_MASK) | - ((rsc_params->h_lpf_int_c & RSZ_LPF_INT_MASK) << - RSZ_LPF_INT_C_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_H_LPF); - - regw_rsz(rsz_base, rsc_params->dscale_en & 1, reg_base + RSZ_DWN_EN); - - val = (rsc_params->h_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK) | - ((rsc_params->v_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK) << - RSZ_DWN_SCALE_AV_SZ_V_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_DWN_AV); - - /* setting rgb conversion parameters */ - regw_rsz(rsz_base, rgb->rgb_en, reg_base + RSZ_RGB_EN); - - val = (rgb->rgb_typ << RSZ_RGB_TYP_SHIFT) | - (rgb->rgb_msk0 << RSZ_RGB_MSK0_SHIFT) | - (rgb->rgb_msk1 << RSZ_RGB_MSK1_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_RGB_TYP); - - regw_rsz(rsz_base, rgb->rgb_alpha_val & RSZ_RGB_ALPHA_MASK, - reg_base + RSZ_RGB_BLD); - - /* setting external memory parameters */ - regw_rsz(rsz_base, ext_mem->rsz_sdr_oft_y, reg_base + RSZ_SDR_Y_OFT); - regw_rsz(rsz_base, ext_mem->rsz_sdr_ptr_s_y, - reg_base + RSZ_SDR_Y_PTR_S); - regw_rsz(rsz_base, ext_mem->rsz_sdr_ptr_e_y, - reg_base + RSZ_SDR_Y_PTR_E); - regw_rsz(rsz_base, ext_mem->rsz_sdr_oft_c, reg_base + RSZ_SDR_C_OFT); - regw_rsz(rsz_base, ext_mem->rsz_sdr_ptr_s_c, - reg_base + RSZ_SDR_C_PTR_S); - regw_rsz(rsz_base, (ext_mem->rsz_sdr_ptr_e_c >> 1), - reg_base + RSZ_SDR_C_PTR_E); -} - -/*set the registers of either RSZ0 or RSZ1 */ -static void -ipipe_setup_resizer(void __iomem *rsz_base, struct resizer_params *params) -{ - /* enable MMR gate to write to Resizer */ - regw_rsz(rsz_base, 1, RSZ_GCK_MMR); - - /* Enable resizer if it is not in bypass mode */ - if (params->rsz_common.passthrough) - regw_rsz(rsz_base, 0, RSZ_GCK_SDR); - else - regw_rsz(rsz_base, 1, RSZ_GCK_SDR); - - rsz_set_common_params(rsz_base, params); - - regw_rsz(rsz_base, params->rsz_en[RSZ_A], RSZ_EN_A); - - if (params->rsz_en[RSZ_A]) - /*setting rescale parameters */ - rsz_set_rsz_regs(rsz_base, RSZ_A, params); - - regw_rsz(rsz_base, params->rsz_en[RSZ_B], RSZ_EN_B); - - if (params->rsz_en[RSZ_B]) - rsz_set_rsz_regs(rsz_base, RSZ_B, params); -} - -static u32 ipipe_get_color_pat(u32 pix) -{ - switch (pix) { - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - case MEDIA_BUS_FMT_SGRBG12_1X12: - return ipipe_sgrbg_pattern; - - default: - return ipipe_srggb_pattern; - } -} - -static int ipipe_get_data_path(struct vpfe_ipipe_device *ipipe) -{ - u32 temp_pix_fmt; - - switch (ipipe->formats[IPIPE_PAD_SINK].code) { - case MEDIA_BUS_FMT_SBGGR8_1X8: - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - case MEDIA_BUS_FMT_SGRBG12_1X12: - temp_pix_fmt = MEDIA_BUS_FMT_SGRBG12_1X12; - break; - - default: - temp_pix_fmt = MEDIA_BUS_FMT_UYVY8_2X8; - } - - if (temp_pix_fmt == MEDIA_BUS_FMT_SGRBG12_1X12) { - if (ipipe->formats[IPIPE_PAD_SOURCE].code == - MEDIA_BUS_FMT_SGRBG12_1X12) - return IPIPE_RAW2RAW; - return IPIPE_RAW2YUV; - } - - return IPIPE_YUV2YUV; -} - -static int get_ipipe_mode(struct vpfe_ipipe_device *ipipe) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(ipipe); - u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; - - if (ipipeif_sink == IPIPEIF_INPUT_MEMORY) - return IPIPE_MODE_SINGLE_SHOT; - if (ipipeif_sink == IPIPEIF_INPUT_ISIF) - return IPIPE_MODE_CONTINUOUS; - - return -EINVAL; -} - -int config_ipipe_hw(struct vpfe_ipipe_device *ipipe) -{ - struct vpfe_ipipe_input_config *config = &ipipe->config.input_config; - void __iomem *ipipe_base = ipipe->base_addr; - struct v4l2_mbus_framefmt *outformat; - u32 color_pat; - int ipipe_mode; - u32 data_path; - - /* enable clock to IPIPE */ - vpss_enable_clock(VPSS_IPIPE_CLOCK, 1); - ipipe_clock_enable(ipipe_base); - - if (ipipe->input == IPIPE_INPUT_NONE) { - regw_ip(ipipe_base, 0, IPIPE_SRC_EN); - return 0; - } - - ipipe_mode = get_ipipe_mode(ipipe); - if (ipipe_mode < 0) { - pr_err("Failed to get ipipe mode"); - return -EINVAL; - } - regw_ip(ipipe_base, ipipe_mode, IPIPE_SRC_MODE); - - data_path = ipipe_get_data_path(ipipe); - regw_ip(ipipe_base, data_path, IPIPE_SRC_FMT); - - regw_ip(ipipe_base, config->vst & IPIPE_RSZ_VPS_MASK, IPIPE_SRC_VPS); - regw_ip(ipipe_base, config->hst & IPIPE_RSZ_HPS_MASK, IPIPE_SRC_HPS); - - outformat = &ipipe->formats[IPIPE_PAD_SOURCE]; - regw_ip(ipipe_base, (outformat->height + 1) & IPIPE_RSZ_VSZ_MASK, - IPIPE_SRC_VSZ); - regw_ip(ipipe_base, (outformat->width + 1) & IPIPE_RSZ_HSZ_MASK, - IPIPE_SRC_HSZ); - - if (data_path == IPIPE_RAW2YUV || - data_path == IPIPE_RAW2RAW) { - color_pat = - ipipe_get_color_pat(ipipe->formats[IPIPE_PAD_SINK].code); - regw_ip(ipipe_base, color_pat, IPIPE_SRC_COL); - } - - return 0; -} - -/* - * config_rsz_hw() - Performs hardware setup of resizer. - */ -int config_rsz_hw(struct vpfe_resizer_device *resizer, - struct resizer_params *config) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - void __iomem *ipipe_base = vpfe_dev->vpfe_ipipe.base_addr; - void __iomem *rsz_base = vpfe_dev->vpfe_resizer.base_addr; - - /* enable VPSS clock */ - vpss_enable_clock(VPSS_IPIPE_CLOCK, 1); - ipipe_clock_enable(ipipe_base); - - ipipe_setup_resizer(rsz_base, config); - - return 0; -} - -static void -rsz_set_y_address(void __iomem *rsz_base, unsigned int address, - unsigned int offset) -{ - u32 val; - - val = address & SET_LOW_ADDR; - regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_BAD_L); - regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_SAD_L); - - val = (address & SET_HIGH_ADDR) >> 16; - regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_BAD_H); - regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_SAD_H); -} - -static void -rsz_set_c_address(void __iomem *rsz_base, unsigned int address, - unsigned int offset) -{ - u32 val; - - val = address & SET_LOW_ADDR; - regw_rsz(rsz_base, val, offset + RSZ_SDR_C_BAD_L); - regw_rsz(rsz_base, val, offset + RSZ_SDR_C_SAD_L); - - val = (address & SET_HIGH_ADDR) >> 16; - regw_rsz(rsz_base, val, offset + RSZ_SDR_C_BAD_H); - regw_rsz(rsz_base, val, offset + RSZ_SDR_C_SAD_H); -} - -/* - * resizer_set_outaddr() - set the address for given resize_no - * @rsz_base: resizer base address - * @params: pointer to ipipe_params structure - * @resize_no: 0 - Resizer-A, 1 - Resizer B - * @address: the address to set - */ -int -resizer_set_outaddr(void __iomem *rsz_base, struct resizer_params *params, - int resize_no, unsigned int address) -{ - struct resizer_scale_param *rsc_param; - struct rsz_ext_mem_param *mem_param; - struct rsz_common_params *rsz_common; - unsigned int rsz_start_add; - unsigned int val; - - if (resize_no != RSZ_A && resize_no != RSZ_B) - return -EINVAL; - - mem_param = ¶ms->ext_mem_param[resize_no]; - rsc_param = ¶ms->rsz_rsc_param[resize_no]; - rsz_common = ¶ms->rsz_common; - - if (resize_no == RSZ_A) - rsz_start_add = RSZ_EN_A; - else - rsz_start_add = RSZ_EN_B; - - /* y_c = 0 for y, = 1 for c */ - if (rsz_common->src_img_fmt == RSZ_IMG_420) { - if (rsz_common->y_c) { - /* C channel */ - val = address + mem_param->flip_ofst_c; - rsz_set_c_address(rsz_base, val, rsz_start_add); - } else { - val = address + mem_param->flip_ofst_y; - rsz_set_y_address(rsz_base, val, rsz_start_add); - } - } else { - if (rsc_param->cen && rsc_param->yen) { - /* 420 */ - val = address + mem_param->c_offset + - mem_param->flip_ofst_c + - mem_param->user_y_ofst + - mem_param->user_c_ofst; - if (resize_no == RSZ_B) - val += - params->ext_mem_param[RSZ_A].user_y_ofst + - params->ext_mem_param[RSZ_A].user_c_ofst; - /* set C address */ - rsz_set_c_address(rsz_base, val, rsz_start_add); - } - val = address + mem_param->flip_ofst_y + mem_param->user_y_ofst; - if (resize_no == RSZ_B) - val += params->ext_mem_param[RSZ_A].user_y_ofst + - params->ext_mem_param[RSZ_A].user_c_ofst; - /* set Y address */ - rsz_set_y_address(rsz_base, val, rsz_start_add); - } - /* resizer must be enabled */ - regw_rsz(rsz_base, params->rsz_en[resize_no], rsz_start_add); - - return 0; -} - -void -ipipe_set_lutdpc_regs(void __iomem *base_addr, void __iomem *isp5_base_addr, - struct vpfe_ipipe_lutdpc *dpc) -{ - u32 max_tbl_size = LUT_DPC_MAX_SIZE >> 1; - u32 lut_start_addr = DPC_TB0_START_ADDR; - u32 val; - u32 count; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, dpc->en, DPC_LUT_EN); - - if (dpc->en != 1) - return; - - val = LUTDPC_TBL_256_EN | (dpc->repl_white & 1); - regw_ip(base_addr, val, DPC_LUT_SEL); - regw_ip(base_addr, LUT_DPC_START_ADDR, DPC_LUT_ADR); - regw_ip(base_addr, dpc->dpc_size, DPC_LUT_SIZ & LUT_DPC_SIZE_MASK); - - for (count = 0; count < dpc->dpc_size; count++) { - if (count >= max_tbl_size) - lut_start_addr = DPC_TB1_START_ADDR; - val = (dpc->table[count].horz_pos & LUT_DPC_H_POS_MASK) | - ((dpc->table[count].vert_pos & LUT_DPC_V_POS_MASK) << - LUT_DPC_V_POS_SHIFT) | (dpc->table[count].method << - LUT_DPC_CORR_METH_SHIFT); - w_ip_table(isp5_base_addr, val, (lut_start_addr + - ((count % max_tbl_size) << 2))); - } -} - -static void -set_dpc_thresholds(void __iomem *base_addr, - struct vpfe_ipipe_otfdpc_2_0_cfg *dpc_thr) -{ - regw_ip(base_addr, dpc_thr->corr_thr.r & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2C_THR_R); - regw_ip(base_addr, dpc_thr->corr_thr.gr & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2C_THR_GR); - regw_ip(base_addr, dpc_thr->corr_thr.gb & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2C_THR_GB); - regw_ip(base_addr, dpc_thr->corr_thr.b & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2C_THR_B); - regw_ip(base_addr, dpc_thr->det_thr.r & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2D_THR_R); - regw_ip(base_addr, dpc_thr->det_thr.gr & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2D_THR_GR); - regw_ip(base_addr, dpc_thr->det_thr.gb & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2D_THR_GB); - regw_ip(base_addr, dpc_thr->det_thr.b & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2D_THR_B); -} - -void ipipe_set_otfdpc_regs(void __iomem *base_addr, - struct vpfe_ipipe_otfdpc *otfdpc) -{ - struct vpfe_ipipe_otfdpc_2_0_cfg *dpc_2_0 = &otfdpc->alg_cfg.dpc_2_0; - struct vpfe_ipipe_otfdpc_3_0_cfg *dpc_3_0 = &otfdpc->alg_cfg.dpc_3_0; - u32 val; - - ipipe_clock_enable(base_addr); - - regw_ip(base_addr, (otfdpc->en & 1), DPC_OTF_EN); - if (!otfdpc->en) - return; - - /* dpc enabled */ - val = (otfdpc->det_method << OTF_DET_METHOD_SHIFT) | otfdpc->alg; - regw_ip(base_addr, val, DPC_OTF_TYP); - - if (otfdpc->det_method == VPFE_IPIPE_DPC_OTF_MIN_MAX) { - /* ALG= 0, TYP = 0, DPC_OTF_2D_THR_[x]=0 - * DPC_OTF_2C_THR_[x] = Maximum thresohld - * MinMax method - */ - dpc_2_0->det_thr.r = dpc_2_0->det_thr.gb = - dpc_2_0->det_thr.gr = dpc_2_0->det_thr.b = 0; - set_dpc_thresholds(base_addr, dpc_2_0); - return; - } - /* MinMax2 */ - if (otfdpc->alg == VPFE_IPIPE_OTFDPC_2_0) { - set_dpc_thresholds(base_addr, dpc_2_0); - return; - } - regw_ip(base_addr, dpc_3_0->act_adj_shf & - OTF_DPC3_0_SHF_MASK, DPC_OTF_3_SHF); - /* Detection thresholds */ - regw_ip(base_addr, ((dpc_3_0->det_thr & OTF_DPC3_0_THR_MASK) << - OTF_DPC3_0_THR_SHIFT), DPC_OTF_3D_THR); - regw_ip(base_addr, dpc_3_0->det_slp & - OTF_DPC3_0_SLP_MASK, DPC_OTF_3D_SLP); - regw_ip(base_addr, dpc_3_0->det_thr_min & - OTF_DPC3_0_DET_MASK, DPC_OTF_3D_MIN); - regw_ip(base_addr, dpc_3_0->det_thr_max & - OTF_DPC3_0_DET_MASK, DPC_OTF_3D_MAX); - /* Correction thresholds */ - regw_ip(base_addr, ((dpc_3_0->corr_thr & OTF_DPC3_0_THR_MASK) << - OTF_DPC3_0_THR_SHIFT), DPC_OTF_3C_THR); - regw_ip(base_addr, dpc_3_0->corr_slp & - OTF_DPC3_0_SLP_MASK, DPC_OTF_3C_SLP); - regw_ip(base_addr, dpc_3_0->corr_thr_min & - OTF_DPC3_0_CORR_MASK, DPC_OTF_3C_MIN); - regw_ip(base_addr, dpc_3_0->corr_thr_max & - OTF_DPC3_0_CORR_MASK, DPC_OTF_3C_MAX); -} - -/* 2D Noise filter */ -void -ipipe_set_d2f_regs(void __iomem *base_addr, unsigned int id, - struct vpfe_ipipe_nf *noise_filter) -{ - - u32 offset = D2F_1ST; - int count; - u32 val; - - if (id == IPIPE_D2F_2ND) - offset = D2F_2ND; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, noise_filter->en & 1, offset + D2F_EN); - if (!noise_filter->en) - return; - - /*noise filter enabled */ - /* Combine all the fields to make D2F_CFG register of IPIPE */ - val = ((noise_filter->spread_val & D2F_SPR_VAL_MASK) << - D2F_SPR_VAL_SHIFT) | ((noise_filter->shft_val & - D2F_SHFT_VAL_MASK) << D2F_SHFT_VAL_SHIFT) | - (noise_filter->gr_sample_meth << D2F_SAMPLE_METH_SHIFT) | - ((noise_filter->apply_lsc_gain & 1) << - D2F_APPLY_LSC_GAIN_SHIFT) | D2F_USE_SPR_REG_VAL; - regw_ip(base_addr, val, offset + D2F_TYP); - - /* edge detection minimum */ - regw_ip(base_addr, noise_filter->edge_det_min_thr & - D2F_EDGE_DET_THR_MASK, offset + D2F_EDG_MIN); - - /* edge detection maximum */ - regw_ip(base_addr, noise_filter->edge_det_max_thr & - D2F_EDGE_DET_THR_MASK, offset + D2F_EDG_MAX); - - for (count = 0; count < VPFE_IPIPE_NF_STR_TABLE_SIZE; count++) - regw_ip(base_addr, - (noise_filter->str[count] & D2F_STR_VAL_MASK), - offset + D2F_STR + count * 4); - - for (count = 0; count < VPFE_IPIPE_NF_THR_TABLE_SIZE; count++) - regw_ip(base_addr, noise_filter->thr[count] & D2F_THR_VAL_MASK, - offset + D2F_THR + count * 4); -} - -#define IPIPE_U8Q5(decimal, integer) \ - (((decimal & 0x1f) | ((integer & 0x7) << 5))) - -/* Green Imbalance Correction */ -void ipipe_set_gic_regs(void __iomem *base_addr, struct vpfe_ipipe_gic *gic) -{ - u32 val; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, gic->en & 1, GIC_EN); - - if (!gic->en) - return; - - /*gic enabled */ - val = (gic->wt_fn_type << GIC_TYP_SHIFT) | - (gic->thr_sel << GIC_THR_SEL_SHIFT) | - ((gic->apply_lsc_gain & 1) << GIC_APPLY_LSC_GAIN_SHIFT); - regw_ip(base_addr, val, GIC_TYP); - - regw_ip(base_addr, gic->gain & GIC_GAIN_MASK, GIC_GAN); - - if (gic->gic_alg != VPFE_IPIPE_GIC_ALG_ADAPT_GAIN) { - /* Constant Gain. Set threshold to maximum */ - regw_ip(base_addr, GIC_THR_MASK, GIC_THR); - return; - } - - if (gic->thr_sel == VPFE_IPIPE_GIC_THR_REG) { - regw_ip(base_addr, gic->thr & GIC_THR_MASK, GIC_THR); - regw_ip(base_addr, gic->slope & GIC_SLOPE_MASK, GIC_SLP); - } else { - /* Use NF thresholds */ - val = IPIPE_U8Q5(gic->nf2_thr_gain.decimal, - gic->nf2_thr_gain.integer); - regw_ip(base_addr, val, GIC_NFGAN); - } -} - -#define IPIPE_U13Q9(decimal, integer) \ - (((decimal & 0x1ff) | ((integer & 0xf) << 9))) -/* White balance */ -void ipipe_set_wb_regs(void __iomem *base_addr, struct vpfe_ipipe_wb *wb) -{ - u32 val; - - ipipe_clock_enable(base_addr); - /* Ofsets. S12 */ - regw_ip(base_addr, wb->ofst_r & WB_OFFSET_MASK, WB2_OFT_R); - regw_ip(base_addr, wb->ofst_gr & WB_OFFSET_MASK, WB2_OFT_GR); - regw_ip(base_addr, wb->ofst_gb & WB_OFFSET_MASK, WB2_OFT_GB); - regw_ip(base_addr, wb->ofst_b & WB_OFFSET_MASK, WB2_OFT_B); - - /* Gains. U13Q9 */ - val = IPIPE_U13Q9(wb->gain_r.decimal, wb->gain_r.integer); - regw_ip(base_addr, val, WB2_WGN_R); - - val = IPIPE_U13Q9(wb->gain_gr.decimal, wb->gain_gr.integer); - regw_ip(base_addr, val, WB2_WGN_GR); - - val = IPIPE_U13Q9(wb->gain_gb.decimal, wb->gain_gb.integer); - regw_ip(base_addr, val, WB2_WGN_GB); - - val = IPIPE_U13Q9(wb->gain_b.decimal, wb->gain_b.integer); - regw_ip(base_addr, val, WB2_WGN_B); -} - -/* CFA */ -void ipipe_set_cfa_regs(void __iomem *base_addr, struct vpfe_ipipe_cfa *cfa) -{ - ipipe_clock_enable(base_addr); - - regw_ip(base_addr, cfa->alg, CFA_MODE); - regw_ip(base_addr, cfa->hpf_thr_2dir & CFA_HPF_THR_2DIR_MASK, - CFA_2DIR_HPF_THR); - regw_ip(base_addr, cfa->hpf_slp_2dir & CFA_HPF_SLOPE_2DIR_MASK, - CFA_2DIR_HPF_SLP); - regw_ip(base_addr, cfa->hp_mix_thr_2dir & CFA_HPF_MIX_THR_2DIR_MASK, - CFA_2DIR_MIX_THR); - regw_ip(base_addr, cfa->hp_mix_slope_2dir & CFA_HPF_MIX_SLP_2DIR_MASK, - CFA_2DIR_MIX_SLP); - regw_ip(base_addr, cfa->dir_thr_2dir & CFA_DIR_THR_2DIR_MASK, - CFA_2DIR_DIR_THR); - regw_ip(base_addr, cfa->dir_slope_2dir & CFA_DIR_SLP_2DIR_MASK, - CFA_2DIR_DIR_SLP); - regw_ip(base_addr, cfa->nd_wt_2dir & CFA_ND_WT_2DIR_MASK, - CFA_2DIR_NDWT); - regw_ip(base_addr, cfa->hue_fract_daa & CFA_DAA_HUE_FRA_MASK, - CFA_MONO_HUE_FRA); - regw_ip(base_addr, cfa->edge_thr_daa & CFA_DAA_EDG_THR_MASK, - CFA_MONO_EDG_THR); - regw_ip(base_addr, cfa->thr_min_daa & CFA_DAA_THR_MIN_MASK, - CFA_MONO_THR_MIN); - regw_ip(base_addr, cfa->thr_slope_daa & CFA_DAA_THR_SLP_MASK, - CFA_MONO_THR_SLP); - regw_ip(base_addr, cfa->slope_min_daa & CFA_DAA_SLP_MIN_MASK, - CFA_MONO_SLP_MIN); - regw_ip(base_addr, cfa->slope_slope_daa & CFA_DAA_SLP_SLP_MASK, - CFA_MONO_SLP_SLP); - regw_ip(base_addr, cfa->lp_wt_daa & CFA_DAA_LP_WT_MASK, - CFA_MONO_LPWT); -} - -void -ipipe_set_rgb2rgb_regs(void __iomem *base_addr, unsigned int id, - struct vpfe_ipipe_rgb2rgb *rgb) -{ - u32 offset_mask = RGB2RGB_1_OFST_MASK; - u32 offset = RGB1_MUL_BASE; - u32 integ_mask = 0xf; - u32 val; - - ipipe_clock_enable(base_addr); - - if (id == IPIPE_RGB2RGB_2) { - /* - * For second RGB module, gain integer is 3 bits instead - * of 4, offset has 11 bits insread of 13 - */ - offset = RGB2_MUL_BASE; - integ_mask = 0x7; - offset_mask = RGB2RGB_2_OFST_MASK; - } - /* Gains */ - val = (rgb->coef_rr.decimal & 0xff) | - ((rgb->coef_rr.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_RR); - val = (rgb->coef_gr.decimal & 0xff) | - ((rgb->coef_gr.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_GR); - val = (rgb->coef_br.decimal & 0xff) | - ((rgb->coef_br.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_BR); - val = (rgb->coef_rg.decimal & 0xff) | - ((rgb->coef_rg.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_RG); - val = (rgb->coef_gg.decimal & 0xff) | - ((rgb->coef_gg.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_GG); - val = (rgb->coef_bg.decimal & 0xff) | - ((rgb->coef_bg.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_BG); - val = (rgb->coef_rb.decimal & 0xff) | - ((rgb->coef_rb.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_RB); - val = (rgb->coef_gb.decimal & 0xff) | - ((rgb->coef_gb.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_GB); - val = (rgb->coef_bb.decimal & 0xff) | - ((rgb->coef_bb.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_BB); - - /* Offsets */ - regw_ip(base_addr, rgb->out_ofst_r & offset_mask, offset + RGB_OFT_OR); - regw_ip(base_addr, rgb->out_ofst_g & offset_mask, offset + RGB_OFT_OG); - regw_ip(base_addr, rgb->out_ofst_b & offset_mask, offset + RGB_OFT_OB); -} - -static void -ipipe_update_gamma_tbl(void __iomem *isp5_base_addr, - struct vpfe_ipipe_gamma_entry *table, int size, u32 addr) -{ - int count; - u32 val; - - for (count = 0; count < size; count++) { - val = table[count].slope & GAMMA_MASK; - val |= (table[count].offset & GAMMA_MASK) << GAMMA_SHIFT; - w_ip_table(isp5_base_addr, val, (addr + (count * 4))); - } -} - -void -ipipe_set_gamma_regs(void __iomem *base_addr, void __iomem *isp5_base_addr, - struct vpfe_ipipe_gamma *gamma) -{ - int table_size; - u32 val; - - ipipe_clock_enable(base_addr); - val = (gamma->bypass_r << GAMMA_BYPR_SHIFT) | - (gamma->bypass_b << GAMMA_BYPG_SHIFT) | - (gamma->bypass_g << GAMMA_BYPB_SHIFT) | - (gamma->tbl_sel << GAMMA_TBL_SEL_SHIFT) | - (gamma->tbl_size << GAMMA_TBL_SIZE_SHIFT); - - regw_ip(base_addr, val, GMM_CFG); - - if (gamma->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM) - return; - - table_size = gamma->tbl_size; - - if (!gamma->bypass_r) - ipipe_update_gamma_tbl(isp5_base_addr, gamma->table_r, - table_size, GAMMA_R_START_ADDR); - if (!gamma->bypass_b) - ipipe_update_gamma_tbl(isp5_base_addr, gamma->table_b, - table_size, GAMMA_B_START_ADDR); - if (!gamma->bypass_g) - ipipe_update_gamma_tbl(isp5_base_addr, gamma->table_g, - table_size, GAMMA_G_START_ADDR); -} - -void -ipipe_set_3d_lut_regs(void __iomem *base_addr, void __iomem *isp5_base_addr, - struct vpfe_ipipe_3d_lut *lut_3d) -{ - struct vpfe_ipipe_3d_lut_entry *tbl; - u32 bnk_index; - u32 tbl_index; - u32 val; - u32 i; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, lut_3d->en, D3LUT_EN); - - if (!lut_3d->en) - return; - - /* valid table */ - tbl = lut_3d->table; - for (i = 0; i < VPFE_IPIPE_MAX_SIZE_3D_LUT; i++) { - /* - * Each entry has 0-9 (B), 10-19 (G) and - * 20-29 R values - */ - val = tbl[i].b & D3_LUT_ENTRY_MASK; - val |= (tbl[i].g & D3_LUT_ENTRY_MASK) << - D3_LUT_ENTRY_G_SHIFT; - val |= (tbl[i].r & D3_LUT_ENTRY_MASK) << - D3_LUT_ENTRY_R_SHIFT; - bnk_index = i % 4; - tbl_index = i >> 2; - tbl_index <<= 2; - if (bnk_index == 0) - w_ip_table(isp5_base_addr, val, - tbl_index + D3L_TB0_START_ADDR); - else if (bnk_index == 1) - w_ip_table(isp5_base_addr, val, - tbl_index + D3L_TB1_START_ADDR); - else if (bnk_index == 2) - w_ip_table(isp5_base_addr, val, - tbl_index + D3L_TB2_START_ADDR); - else - w_ip_table(isp5_base_addr, val, - tbl_index + D3L_TB3_START_ADDR); - } -} - -/* Lumina adjustments */ -void -ipipe_set_lum_adj_regs(void __iomem *base_addr, struct ipipe_lum_adj *lum_adj) -{ - u32 val; - - ipipe_clock_enable(base_addr); - - /* combine fields of YUV_ADJ to set brightness and contrast */ - val = lum_adj->contrast << LUM_ADJ_CONTR_SHIFT | - lum_adj->brightness << LUM_ADJ_BRIGHT_SHIFT; - regw_ip(base_addr, val, YUV_ADJ); -} - -inline u32 ipipe_s12q8(unsigned short decimal, short integer) -{ - return (decimal & 0xff) | ((integer & 0xf) << 8); -} - -void ipipe_set_rgb2ycbcr_regs(void __iomem *base_addr, - struct vpfe_ipipe_rgb2yuv *yuv) -{ - u32 val; - - /* S10Q8 */ - ipipe_clock_enable(base_addr); - val = ipipe_s12q8(yuv->coef_ry.decimal, yuv->coef_ry.integer); - regw_ip(base_addr, val, YUV_MUL_RY); - val = ipipe_s12q8(yuv->coef_gy.decimal, yuv->coef_gy.integer); - regw_ip(base_addr, val, YUV_MUL_GY); - val = ipipe_s12q8(yuv->coef_by.decimal, yuv->coef_by.integer); - regw_ip(base_addr, val, YUV_MUL_BY); - val = ipipe_s12q8(yuv->coef_rcb.decimal, yuv->coef_rcb.integer); - regw_ip(base_addr, val, YUV_MUL_RCB); - val = ipipe_s12q8(yuv->coef_gcb.decimal, yuv->coef_gcb.integer); - regw_ip(base_addr, val, YUV_MUL_GCB); - val = ipipe_s12q8(yuv->coef_bcb.decimal, yuv->coef_bcb.integer); - regw_ip(base_addr, val, YUV_MUL_BCB); - val = ipipe_s12q8(yuv->coef_rcr.decimal, yuv->coef_rcr.integer); - regw_ip(base_addr, val, YUV_MUL_RCR); - val = ipipe_s12q8(yuv->coef_gcr.decimal, yuv->coef_gcr.integer); - regw_ip(base_addr, val, YUV_MUL_GCR); - val = ipipe_s12q8(yuv->coef_bcr.decimal, yuv->coef_bcr.integer); - regw_ip(base_addr, val, YUV_MUL_BCR); - regw_ip(base_addr, yuv->out_ofst_y & RGB2YCBCR_OFST_MASK, YUV_OFT_Y); - regw_ip(base_addr, yuv->out_ofst_cb & RGB2YCBCR_OFST_MASK, YUV_OFT_CB); - regw_ip(base_addr, yuv->out_ofst_cr & RGB2YCBCR_OFST_MASK, YUV_OFT_CR); -} - -/* YUV 422 conversion */ -void -ipipe_set_yuv422_conv_regs(void __iomem *base_addr, - struct vpfe_ipipe_yuv422_conv *conv) -{ - u32 val; - - ipipe_clock_enable(base_addr); - - /* Combine all the fields to make YUV_PHS register of IPIPE */ - val = (conv->chrom_pos << 0) | (conv->en_chrom_lpf << 1); - regw_ip(base_addr, val, YUV_PHS); -} - -void -ipipe_set_gbce_regs(void __iomem *base_addr, void __iomem *isp5_base_addr, - struct vpfe_ipipe_gbce *gbce) -{ - unsigned int count; - u32 mask = GBCE_Y_VAL_MASK; - - if (gbce->type == VPFE_IPIPE_GBCE_GAIN_TBL) - mask = GBCE_GAIN_VAL_MASK; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, gbce->en & 1, GBCE_EN); - - if (!gbce->en) - return; - - regw_ip(base_addr, gbce->type, GBCE_TYP); - - for (count = 0; count < VPFE_IPIPE_MAX_SIZE_GBCE_LUT; count += 2) - w_ip_table(isp5_base_addr, ((gbce->table[count + 1] & mask) << - GBCE_ENTRY_SHIFT) | (gbce->table[count] & mask), - ((count/2) << 2) + GBCE_TB_START_ADDR); -} - -void -ipipe_set_ee_regs(void __iomem *base_addr, void __iomem *isp5_base_addr, - struct vpfe_ipipe_yee *ee) -{ - unsigned int count; - u32 val; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, ee->en, YEE_EN); - - if (!ee->en) - return; - - val = ee->en_halo_red & 1; - val |= ee->merge_meth << YEE_HALO_RED_EN_SHIFT; - regw_ip(base_addr, val, YEE_TYP); - - regw_ip(base_addr, ee->hpf_shft, YEE_SHF); - regw_ip(base_addr, ee->hpf_coef_00 & YEE_COEF_MASK, YEE_MUL_00); - regw_ip(base_addr, ee->hpf_coef_01 & YEE_COEF_MASK, YEE_MUL_01); - regw_ip(base_addr, ee->hpf_coef_02 & YEE_COEF_MASK, YEE_MUL_02); - regw_ip(base_addr, ee->hpf_coef_10 & YEE_COEF_MASK, YEE_MUL_10); - regw_ip(base_addr, ee->hpf_coef_11 & YEE_COEF_MASK, YEE_MUL_11); - regw_ip(base_addr, ee->hpf_coef_12 & YEE_COEF_MASK, YEE_MUL_12); - regw_ip(base_addr, ee->hpf_coef_20 & YEE_COEF_MASK, YEE_MUL_20); - regw_ip(base_addr, ee->hpf_coef_21 & YEE_COEF_MASK, YEE_MUL_21); - regw_ip(base_addr, ee->hpf_coef_22 & YEE_COEF_MASK, YEE_MUL_22); - regw_ip(base_addr, ee->yee_thr & YEE_THR_MASK, YEE_THR); - regw_ip(base_addr, ee->es_gain & YEE_ES_GAIN_MASK, YEE_E_GAN); - regw_ip(base_addr, ee->es_thr1 & YEE_ES_THR1_MASK, YEE_E_THR1); - regw_ip(base_addr, ee->es_thr2 & YEE_THR_MASK, YEE_E_THR2); - regw_ip(base_addr, ee->es_gain_grad & YEE_THR_MASK, YEE_G_GAN); - regw_ip(base_addr, ee->es_ofst_grad & YEE_THR_MASK, YEE_G_OFT); - - for (count = 0; count < VPFE_IPIPE_MAX_SIZE_YEE_LUT; count += 2) - w_ip_table(isp5_base_addr, ((ee->table[count + 1] & - YEE_ENTRY_MASK) << YEE_ENTRY_SHIFT) | - (ee->table[count] & YEE_ENTRY_MASK), - ((count/2) << 2) + YEE_TB_START_ADDR); -} - -/* Chromatic Artifact Correction. CAR */ -static void ipipe_set_mf(void __iomem *base_addr) -{ - /* typ to dynamic switch */ - regw_ip(base_addr, VPFE_IPIPE_CAR_DYN_SWITCH, CAR_TYP); - /* Set SW0 to maximum */ - regw_ip(base_addr, CAR_MF_THR, CAR_SW); -} - -static void -ipipe_set_gain_ctrl(void __iomem *base_addr, struct vpfe_ipipe_car *car) -{ - regw_ip(base_addr, VPFE_IPIPE_CAR_CHR_GAIN_CTRL, CAR_TYP); - regw_ip(base_addr, car->hpf, CAR_HPF_TYP); - regw_ip(base_addr, car->hpf_shft & CAR_HPF_SHIFT_MASK, CAR_HPF_SHF); - regw_ip(base_addr, car->hpf_thr, CAR_HPF_THR); - regw_ip(base_addr, car->gain1.gain, CAR_GN1_GAN); - regw_ip(base_addr, car->gain1.shft & CAR_GAIN1_SHFT_MASK, CAR_GN1_SHF); - regw_ip(base_addr, car->gain1.gain_min & CAR_GAIN_MIN_MASK, - CAR_GN1_MIN); - regw_ip(base_addr, car->gain2.gain, CAR_GN2_GAN); - regw_ip(base_addr, car->gain2.shft & CAR_GAIN2_SHFT_MASK, CAR_GN2_SHF); - regw_ip(base_addr, car->gain2.gain_min & CAR_GAIN_MIN_MASK, - CAR_GN2_MIN); -} - -void ipipe_set_car_regs(void __iomem *base_addr, struct vpfe_ipipe_car *car) -{ - u32 val; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, car->en, CAR_EN); - - if (!car->en) - return; - - switch (car->meth) { - case VPFE_IPIPE_CAR_MED_FLTR: - ipipe_set_mf(base_addr); - break; - - case VPFE_IPIPE_CAR_CHR_GAIN_CTRL: - ipipe_set_gain_ctrl(base_addr, car); - break; - - default: - /* Dynamic switch between MF and Gain Ctrl. */ - ipipe_set_mf(base_addr); - ipipe_set_gain_ctrl(base_addr, car); - /* Set the threshold for switching between - * the two Here we overwrite the MF SW0 value - */ - regw_ip(base_addr, VPFE_IPIPE_CAR_DYN_SWITCH, CAR_TYP); - val = car->sw1; - val <<= CAR_SW1_SHIFT; - val |= car->sw0; - regw_ip(base_addr, val, CAR_SW); - } -} - -/* Chromatic Gain Suppression */ -void ipipe_set_cgs_regs(void __iomem *base_addr, struct vpfe_ipipe_cgs *cgs) -{ - ipipe_clock_enable(base_addr); - regw_ip(base_addr, cgs->en, CGS_EN); - - if (!cgs->en) - return; - - /* Set the bright side parameters */ - regw_ip(base_addr, cgs->h_thr, CGS_GN1_H_THR); - regw_ip(base_addr, cgs->h_slope, CGS_GN1_H_GAN); - regw_ip(base_addr, cgs->h_shft & CAR_SHIFT_MASK, CGS_GN1_H_SHF); - regw_ip(base_addr, cgs->h_min, CGS_GN1_H_MIN); -} - -void rsz_src_enable(void __iomem *rsz_base, int enable) -{ - regw_rsz(rsz_base, enable, RSZ_SRC_EN); -} - -int rsz_enable(void __iomem *rsz_base, int rsz_id, int enable) -{ - if (rsz_id == RSZ_A) { - regw_rsz(rsz_base, enable, RSZ_EN_A); - /* We always enable RSZ_A. RSZ_B is enable upon request from - * application. So enable RSZ_SRC_EN along with RSZ_A - */ - regw_rsz(rsz_base, enable, RSZ_SRC_EN); - } else if (rsz_id == RSZ_B) { - regw_rsz(rsz_base, enable, RSZ_EN_B); - } else { - BUG(); - } - - return 0; -} diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h b/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h deleted file mode 100644 index 16b6a14b7058..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h +++ /dev/null @@ -1,556 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#ifndef _DAVINCI_VPFE_DM365_IPIPE_HW_H -#define _DAVINCI_VPFE_DM365_IPIPE_HW_H - -#include "vpfe_mc_capture.h" - -#define SET_LOW_ADDR 0x0000ffff -#define SET_HIGH_ADDR 0xffff0000 - -/* Below are the internal tables */ -#define DPC_TB0_START_ADDR 0x8000 -#define DPC_TB1_START_ADDR 0x8400 - -#define GAMMA_R_START_ADDR 0xa800 -#define GAMMA_G_START_ADDR 0xb000 -#define GAMMA_B_START_ADDR 0xb800 - -/* RAM table addresses for edge enhancement correction*/ -#define YEE_TB_START_ADDR 0x8800 - -/* RAM table address for GBC LUT */ -#define GBCE_TB_START_ADDR 0x9000 - -/* RAM table for 3D NF LUT */ -#define D3L_TB0_START_ADDR 0x9800 -#define D3L_TB1_START_ADDR 0x9c00 -#define D3L_TB2_START_ADDR 0xa000 -#define D3L_TB3_START_ADDR 0xa400 - -/* IPIPE Register Offsets from the base address */ -#define IPIPE_SRC_EN 0x0000 -#define IPIPE_SRC_MODE 0x0004 -#define IPIPE_SRC_FMT 0x0008 -#define IPIPE_SRC_COL 0x000c -#define IPIPE_SRC_VPS 0x0010 -#define IPIPE_SRC_VSZ 0x0014 -#define IPIPE_SRC_HPS 0x0018 -#define IPIPE_SRC_HSZ 0x001c - -#define IPIPE_SEL_SBU 0x0020 - -#define IPIPE_DMA_STA 0x0024 -#define IPIPE_GCK_MMR 0x0028 -#define IPIPE_GCK_PIX 0x002c -#define IPIPE_RESERVED0 0x0030 - -/* Defect Correction */ -#define DPC_LUT_EN 0x0034 -#define DPC_LUT_SEL 0x0038 -#define DPC_LUT_ADR 0x003c -#define DPC_LUT_SIZ 0x0040 -#define DPC_OTF_EN 0x0044 -#define DPC_OTF_TYP 0x0048 -#define DPC_OTF_2D_THR_R 0x004c -#define DPC_OTF_2D_THR_GR 0x0050 -#define DPC_OTF_2D_THR_GB 0x0054 -#define DPC_OTF_2D_THR_B 0x0058 -#define DPC_OTF_2C_THR_R 0x005c -#define DPC_OTF_2C_THR_GR 0x0060 -#define DPC_OTF_2C_THR_GB 0x0064 -#define DPC_OTF_2C_THR_B 0x0068 -#define DPC_OTF_3_SHF 0x006c -#define DPC_OTF_3D_THR 0x0070 -#define DPC_OTF_3D_SLP 0x0074 -#define DPC_OTF_3D_MIN 0x0078 -#define DPC_OTF_3D_MAX 0x007c -#define DPC_OTF_3C_THR 0x0080 -#define DPC_OTF_3C_SLP 0x0084 -#define DPC_OTF_3C_MIN 0x0088 -#define DPC_OTF_3C_MAX 0x008c - -/* Lense Shading Correction */ -#define LSC_VOFT 0x90 -#define LSC_VA2 0x94 -#define LSC_VA1 0x98 -#define LSC_VS 0x9c -#define LSC_HOFT 0xa0 -#define LSC_HA2 0xa4 -#define LSC_HA1 0xa8 -#define LSC_HS 0xac -#define LSC_GAIN_R 0xb0 -#define LSC_GAIN_GR 0xb4 -#define LSC_GAIN_GB 0xb8 -#define LSC_GAIN_B 0xbc -#define LSC_OFT_R 0xc0 -#define LSC_OFT_GR 0xc4 -#define LSC_OFT_GB 0xc8 -#define LSC_OFT_B 0xcc -#define LSC_SHF 0xd0 -#define LSC_MAX 0xd4 - -/* Noise Filter 1. Ofsets from start address given */ -#define D2F_1ST 0xd8 -#define D2F_EN 0x0 -#define D2F_TYP 0x4 -#define D2F_THR 0x8 -#define D2F_STR 0x28 -#define D2F_SPR 0x48 -#define D2F_EDG_MIN 0x68 -#define D2F_EDG_MAX 0x6c - -/* Noise Filter 2 */ -#define D2F_2ND 0x148 - -/* GIC */ -#define GIC_EN 0x1b8 -#define GIC_TYP 0x1bc -#define GIC_GAN 0x1c0 -#define GIC_NFGAN 0x1c4 -#define GIC_THR 0x1c8 -#define GIC_SLP 0x1cc - -/* White Balance */ -#define WB2_OFT_R 0x1d0 -#define WB2_OFT_GR 0x1d4 -#define WB2_OFT_GB 0x1d8 -#define WB2_OFT_B 0x1dc -#define WB2_WGN_R 0x1e0 -#define WB2_WGN_GR 0x1e4 -#define WB2_WGN_GB 0x1e8 -#define WB2_WGN_B 0x1ec - -/* CFA interpolation */ -#define CFA_MODE 0x1f0 -#define CFA_2DIR_HPF_THR 0x1f4 -#define CFA_2DIR_HPF_SLP 0x1f8 -#define CFA_2DIR_MIX_THR 0x1fc -#define CFA_2DIR_MIX_SLP 0x200 -#define CFA_2DIR_DIR_THR 0x204 -#define CFA_2DIR_DIR_SLP 0x208 -#define CFA_2DIR_NDWT 0x20c -#define CFA_MONO_HUE_FRA 0x210 -#define CFA_MONO_EDG_THR 0x214 -#define CFA_MONO_THR_MIN 0x218 -#define CFA_MONO_THR_SLP 0x21c -#define CFA_MONO_SLP_MIN 0x220 -#define CFA_MONO_SLP_SLP 0x224 -#define CFA_MONO_LPWT 0x228 - -/* RGB to RGB conversiona - 1st */ -#define RGB1_MUL_BASE 0x22c -/* Offsets from base */ -#define RGB_MUL_RR 0x0 -#define RGB_MUL_GR 0x4 -#define RGB_MUL_BR 0x8 -#define RGB_MUL_RG 0xc -#define RGB_MUL_GG 0x10 -#define RGB_MUL_BG 0x14 -#define RGB_MUL_RB 0x18 -#define RGB_MUL_GB 0x1c -#define RGB_MUL_BB 0x20 -#define RGB_OFT_OR 0x24 -#define RGB_OFT_OG 0x28 -#define RGB_OFT_OB 0x2c - -/* Gamma */ -#define GMM_CFG 0x25c - -/* RGB to RGB conversiona - 2nd */ -#define RGB2_MUL_BASE 0x260 - -/* 3D LUT */ -#define D3LUT_EN 0x290 - -/* RGB to YUV(YCbCr) conversion */ -#define YUV_ADJ 0x294 -#define YUV_MUL_RY 0x298 -#define YUV_MUL_GY 0x29c -#define YUV_MUL_BY 0x2a0 -#define YUV_MUL_RCB 0x2a4 -#define YUV_MUL_GCB 0x2a8 -#define YUV_MUL_BCB 0x2ac -#define YUV_MUL_RCR 0x2b0 -#define YUV_MUL_GCR 0x2b4 -#define YUV_MUL_BCR 0x2b8 -#define YUV_OFT_Y 0x2bc -#define YUV_OFT_CB 0x2c0 -#define YUV_OFT_CR 0x2c4 -#define YUV_PHS 0x2c8 - -/* Global Brightness and Contrast */ -#define GBCE_EN 0x2cc -#define GBCE_TYP 0x2d0 - -/* Edge Enhancer */ -#define YEE_EN 0x2d4 -#define YEE_TYP 0x2d8 -#define YEE_SHF 0x2dc -#define YEE_MUL_00 0x2e0 -#define YEE_MUL_01 0x2e4 -#define YEE_MUL_02 0x2e8 -#define YEE_MUL_10 0x2ec -#define YEE_MUL_11 0x2f0 -#define YEE_MUL_12 0x2f4 -#define YEE_MUL_20 0x2f8 -#define YEE_MUL_21 0x2fc -#define YEE_MUL_22 0x300 -#define YEE_THR 0x304 -#define YEE_E_GAN 0x308 -#define YEE_E_THR1 0x30c -#define YEE_E_THR2 0x310 -#define YEE_G_GAN 0x314 -#define YEE_G_OFT 0x318 - -/* Chroma Artifact Reduction */ -#define CAR_EN 0x31c -#define CAR_TYP 0x320 -#define CAR_SW 0x324 -#define CAR_HPF_TYP 0x328 -#define CAR_HPF_SHF 0x32c -#define CAR_HPF_THR 0x330 -#define CAR_GN1_GAN 0x334 -#define CAR_GN1_SHF 0x338 -#define CAR_GN1_MIN 0x33c -#define CAR_GN2_GAN 0x340 -#define CAR_GN2_SHF 0x344 -#define CAR_GN2_MIN 0x348 - -/* Chroma Gain Suppression */ -#define CGS_EN 0x34c -#define CGS_GN1_L_THR 0x350 -#define CGS_GN1_L_GAN 0x354 -#define CGS_GN1_L_SHF 0x358 -#define CGS_GN1_L_MIN 0x35c -#define CGS_GN1_H_THR 0x360 -#define CGS_GN1_H_GAN 0x364 -#define CGS_GN1_H_SHF 0x368 -#define CGS_GN1_H_MIN 0x36c -#define CGS_GN2_L_THR 0x370 -#define CGS_GN2_L_GAN 0x374 -#define CGS_GN2_L_SHF 0x378 -#define CGS_GN2_L_MIN 0x37c - -/* Resizer */ -#define RSZ_SRC_EN 0x0 -#define RSZ_SRC_MODE 0x4 -#define RSZ_SRC_FMT0 0x8 -#define RSZ_SRC_FMT1 0xc -#define RSZ_SRC_VPS 0x10 -#define RSZ_SRC_VSZ 0x14 -#define RSZ_SRC_HPS 0x18 -#define RSZ_SRC_HSZ 0x1c -#define RSZ_DMA_RZA 0x20 -#define RSZ_DMA_RZB 0x24 -#define RSZ_DMA_STA 0x28 -#define RSZ_GCK_MMR 0x2c -#define RSZ_RESERVED0 0x30 -#define RSZ_GCK_SDR 0x34 -#define RSZ_IRQ_RZA 0x38 -#define RSZ_IRQ_RZB 0x3c -#define RSZ_YUV_Y_MIN 0x40 -#define RSZ_YUV_Y_MAX 0x44 -#define RSZ_YUV_C_MIN 0x48 -#define RSZ_YUV_C_MAX 0x4c -#define RSZ_YUV_PHS 0x50 -#define RSZ_SEQ 0x54 - -/* Resizer Rescale Parameters */ -#define RSZ_EN_A 0x58 -#define RSZ_EN_B 0xe8 -/* - * offset of the registers to be added with base register of - * either RSZ0 or RSZ1 - */ -#define RSZ_MODE 0x4 -#define RSZ_420 0x8 -#define RSZ_I_VPS 0xc -#define RSZ_I_HPS 0x10 -#define RSZ_O_VSZ 0x14 -#define RSZ_O_HSZ 0x18 -#define RSZ_V_PHS_Y 0x1c -#define RSZ_V_PHS_C 0x20 -#define RSZ_V_DIF 0x24 -#define RSZ_V_TYP 0x28 -#define RSZ_V_LPF 0x2c -#define RSZ_H_PHS 0x30 -#define RSZ_H_PHS_ADJ 0x34 -#define RSZ_H_DIF 0x38 -#define RSZ_H_TYP 0x3c -#define RSZ_H_LPF 0x40 -#define RSZ_DWN_EN 0x44 -#define RSZ_DWN_AV 0x48 - -/* Resizer RGB Conversion Parameters */ -#define RSZ_RGB_EN 0x4c -#define RSZ_RGB_TYP 0x50 -#define RSZ_RGB_BLD 0x54 - -/* Resizer External Memory Parameters */ -#define RSZ_SDR_Y_BAD_H 0x58 -#define RSZ_SDR_Y_BAD_L 0x5c -#define RSZ_SDR_Y_SAD_H 0x60 -#define RSZ_SDR_Y_SAD_L 0x64 -#define RSZ_SDR_Y_OFT 0x68 -#define RSZ_SDR_Y_PTR_S 0x6c -#define RSZ_SDR_Y_PTR_E 0x70 -#define RSZ_SDR_C_BAD_H 0x74 -#define RSZ_SDR_C_BAD_L 0x78 -#define RSZ_SDR_C_SAD_H 0x7c -#define RSZ_SDR_C_SAD_L 0x80 -#define RSZ_SDR_C_OFT 0x84 -#define RSZ_SDR_C_PTR_S 0x88 -#define RSZ_SDR_C_PTR_E 0x8c - -/* Macro for resizer */ -#define RSZ_YUV_Y_MIN 0x40 -#define RSZ_YUV_Y_MAX 0x44 -#define RSZ_YUV_C_MIN 0x48 -#define RSZ_YUV_C_MAX 0x4c - -#define IPIPE_GCK_MMR_DEFAULT 1 -#define IPIPE_GCK_PIX_DEFAULT 0xe -#define RSZ_GCK_MMR_DEFAULT 1 -#define RSZ_GCK_SDR_DEFAULT 1 - -/* LUTDPC */ -#define LUTDPC_TBL_256_EN 0 -#define LUTDPC_INF_TBL_EN 1 -#define LUT_DPC_START_ADDR 0 -#define LUT_DPC_H_POS_MASK 0x1fff -#define LUT_DPC_V_POS_MASK 0x1fff -#define LUT_DPC_V_POS_SHIFT 13 -#define LUT_DPC_CORR_METH_SHIFT 26 -#define LUT_DPC_MAX_SIZE 256 -#define LUT_DPC_SIZE_MASK 0x3ff - -/* OTFDPC */ -#define OTFDPC_DPC2_THR_MASK 0xfff -#define OTF_DET_METHOD_SHIFT 1 -#define OTF_DPC3_0_SHF_MASK 3 -#define OTF_DPC3_0_THR_SHIFT 6 -#define OTF_DPC3_0_THR_MASK 0x3f -#define OTF_DPC3_0_SLP_MASK 0x3f -#define OTF_DPC3_0_DET_MASK 0xfff -#define OTF_DPC3_0_CORR_MASK 0xfff - -/* NF (D2F) */ -#define D2F_SPR_VAL_MASK 0x1f -#define D2F_SPR_VAL_SHIFT 0 -#define D2F_SHFT_VAL_MASK 3 -#define D2F_SHFT_VAL_SHIFT 5 -#define D2F_SAMPLE_METH_SHIFT 7 -#define D2F_APPLY_LSC_GAIN_SHIFT 8 -#define D2F_USE_SPR_REG_VAL 0 -#define D2F_STR_VAL_MASK 0x1f -#define D2F_THR_VAL_MASK 0x3ff -#define D2F_EDGE_DET_THR_MASK 0x7ff - -/* Green Imbalance Correction */ -#define GIC_TYP_SHIFT 0 -#define GIC_THR_SEL_SHIFT 1 -#define GIC_APPLY_LSC_GAIN_SHIFT 2 -#define GIC_GAIN_MASK 0xff -#define GIC_THR_MASK 0xfff -#define GIC_SLOPE_MASK 0xfff -#define GIC_NFGAN_INT_MASK 7 -#define GIC_NFGAN_DECI_MASK 0x1f - -/* WB */ -#define WB_OFFSET_MASK 0xfff -#define WB_GAIN_INT_MASK 0xf -#define WB_GAIN_DECI_MASK 0x1ff - -/* CFA */ -#define CFA_HPF_THR_2DIR_MASK 0x1fff -#define CFA_HPF_SLOPE_2DIR_MASK 0x3ff -#define CFA_HPF_MIX_THR_2DIR_MASK 0x1fff -#define CFA_HPF_MIX_SLP_2DIR_MASK 0x3ff -#define CFA_DIR_THR_2DIR_MASK 0x3ff -#define CFA_DIR_SLP_2DIR_MASK 0x7f -#define CFA_ND_WT_2DIR_MASK 0x3f -#define CFA_DAA_HUE_FRA_MASK 0x3f -#define CFA_DAA_EDG_THR_MASK 0xff -#define CFA_DAA_THR_MIN_MASK 0x3ff -#define CFA_DAA_THR_SLP_MASK 0x3ff -#define CFA_DAA_SLP_MIN_MASK 0x3ff -#define CFA_DAA_SLP_SLP_MASK 0x3ff -#define CFA_DAA_LP_WT_MASK 0x3f - -/* RGB2RGB */ -#define RGB2RGB_1_OFST_MASK 0x1fff -#define RGB2RGB_1_GAIN_INT_MASK 0xf -#define RGB2RGB_GAIN_DECI_MASK 0xff -#define RGB2RGB_2_OFST_MASK 0x7ff -#define RGB2RGB_2_GAIN_INT_MASK 0x7 - -/* Gamma */ -#define GAMMA_BYPR_SHIFT 0 -#define GAMMA_BYPG_SHIFT 1 -#define GAMMA_BYPB_SHIFT 2 -#define GAMMA_TBL_SEL_SHIFT 4 -#define GAMMA_TBL_SIZE_SHIFT 5 -#define GAMMA_MASK 0x3ff -#define GAMMA_SHIFT 10 - -/* 3D LUT */ -#define D3_LUT_ENTRY_MASK 0x3ff -#define D3_LUT_ENTRY_R_SHIFT 20 -#define D3_LUT_ENTRY_G_SHIFT 10 -#define D3_LUT_ENTRY_B_SHIFT 0 - -/* Lumina adj */ -#define LUM_ADJ_CONTR_SHIFT 0 -#define LUM_ADJ_BRIGHT_SHIFT 8 - -/* RGB2YCbCr */ -#define RGB2YCBCR_OFST_MASK 0x7ff -#define RGB2YCBCR_COEF_INT_MASK 0xf -#define RGB2YCBCR_COEF_DECI_MASK 0xff - -/* GBCE */ -#define GBCE_Y_VAL_MASK 0xff -#define GBCE_GAIN_VAL_MASK 0x3ff -#define GBCE_ENTRY_SHIFT 10 - -/* Edge Enhancements */ -#define YEE_HALO_RED_EN_SHIFT 1 -#define YEE_HPF_SHIFT_MASK 0xf -#define YEE_COEF_MASK 0x3ff -#define YEE_THR_MASK 0x3f -#define YEE_ES_GAIN_MASK 0xfff -#define YEE_ES_THR1_MASK 0xfff -#define YEE_ENTRY_SHIFT 9 -#define YEE_ENTRY_MASK 0x1ff - -/* CAR */ -#define CAR_MF_THR 0xff -#define CAR_SW1_SHIFT 8 -#define CAR_GAIN1_SHFT_MASK 7 -#define CAR_GAIN_MIN_MASK 0x1ff -#define CAR_GAIN2_SHFT_MASK 0xf -#define CAR_HPF_SHIFT_MASK 3 - -/* CGS */ -#define CAR_SHIFT_MASK 3 - -/* Resizer */ -#define RSZ_BYPASS_SHIFT 1 -#define RSZ_SRC_IMG_FMT_SHIFT 1 -#define RSZ_SRC_Y_C_SEL_SHIFT 2 -#define IPIPE_RSZ_VPS_MASK 0xffff -#define IPIPE_RSZ_HPS_MASK 0xffff -#define IPIPE_RSZ_VSZ_MASK 0x1fff -#define IPIPE_RSZ_HSZ_MASK 0x1fff -#define RSZ_HPS_MASK 0x1fff -#define RSZ_VPS_MASK 0x1fff -#define RSZ_O_HSZ_MASK 0x1fff -#define RSZ_O_VSZ_MASK 0x1fff -#define RSZ_V_PHS_MASK 0x3fff -#define RSZ_V_DIF_MASK 0x3fff - -#define RSZA_H_FLIP_SHIFT 0 -#define RSZA_V_FLIP_SHIFT 1 -#define RSZB_H_FLIP_SHIFT 2 -#define RSZB_V_FLIP_SHIFT 3 -#define RSZ_A 0 -#define RSZ_B 1 -#define RSZ_CEN_SHIFT 1 -#define RSZ_YEN_SHIFT 0 -#define RSZ_TYP_Y_SHIFT 0 -#define RSZ_TYP_C_SHIFT 1 -#define RSZ_LPF_INT_MASK 0x3f -#define RSZ_LPF_INT_C_SHIFT 6 -#define RSZ_H_PHS_MASK 0x3fff -#define RSZ_H_DIF_MASK 0x3fff -#define RSZ_DIFF_DOWN_THR 256 -#define RSZ_DWN_SCALE_AV_SZ_V_SHIFT 3 -#define RSZ_DWN_SCALE_AV_SZ_MASK 7 -#define RSZ_RGB_MSK1_SHIFT 2 -#define RSZ_RGB_MSK0_SHIFT 1 -#define RSZ_RGB_TYP_SHIFT 0 -#define RSZ_RGB_ALPHA_MASK 0xff - -static inline u32 regr_ip(void __iomem *addr, u32 offset) -{ - return readl(addr + offset); -} - -static inline void regw_ip(void __iomem *addr, u32 val, u32 offset) -{ - writel(val, addr + offset); -} - -static inline u32 w_ip_table(void __iomem *addr, u32 val, u32 offset) -{ - writel(val, addr + offset); - - return val; -} - -static inline u32 regr_rsz(void __iomem *addr, u32 offset) -{ - return readl(addr + offset); -} - -static inline u32 regw_rsz(void __iomem *addr, u32 val, u32 offset) -{ - writel(val, addr + offset); - - return val; -} - -int config_ipipe_hw(struct vpfe_ipipe_device *ipipe); -int resizer_set_outaddr(void __iomem *rsz_base, struct resizer_params *params, - int resize_no, unsigned int address); -int rsz_enable(void __iomem *rsz_base, int rsz_id, int enable); -void rsz_src_enable(void __iomem *rsz_base, int enable); -void rsz_set_in_pix_format(unsigned char y_c); -int config_rsz_hw(struct vpfe_resizer_device *resizer, - struct resizer_params *config); -void ipipe_set_d2f_regs(void __iomem *base_addr, unsigned int id, - struct vpfe_ipipe_nf *noise_filter); -void ipipe_set_rgb2rgb_regs(void __iomem *base_addr, unsigned int id, - struct vpfe_ipipe_rgb2rgb *rgb); -void ipipe_set_yuv422_conv_regs(void __iomem *base_addr, - struct vpfe_ipipe_yuv422_conv *conv); -void ipipe_set_lum_adj_regs(void __iomem *base_addr, - struct ipipe_lum_adj *lum_adj); -void ipipe_set_rgb2ycbcr_regs(void __iomem *base_addr, - struct vpfe_ipipe_rgb2yuv *yuv); -void ipipe_set_lutdpc_regs(void __iomem *base_addr, - void __iomem *isp5_base_addr, struct vpfe_ipipe_lutdpc *lutdpc); -void ipipe_set_otfdpc_regs(void __iomem *base_addr, - struct vpfe_ipipe_otfdpc *otfdpc); -void ipipe_set_3d_lut_regs(void __iomem *base_addr, - void __iomem *isp5_base_addr, struct vpfe_ipipe_3d_lut *lut_3d); -void ipipe_set_gamma_regs(void __iomem *base_addr, - void __iomem *isp5_base_addr, struct vpfe_ipipe_gamma *gamma); -void ipipe_set_ee_regs(void __iomem *base_addr, - void __iomem *isp5_base_addr, struct vpfe_ipipe_yee *ee); -void ipipe_set_gbce_regs(void __iomem *base_addr, - void __iomem *isp5_base_addr, struct vpfe_ipipe_gbce *gbce); -void ipipe_set_gic_regs(void __iomem *base_addr, struct vpfe_ipipe_gic *gic); -void ipipe_set_cfa_regs(void __iomem *base_addr, struct vpfe_ipipe_cfa *cfa); -void ipipe_set_car_regs(void __iomem *base_addr, struct vpfe_ipipe_car *car); -void ipipe_set_cgs_regs(void __iomem *base_addr, struct vpfe_ipipe_cgs *cgs); -void ipipe_set_wb_regs(void __iomem *base_addr, struct vpfe_ipipe_wb *wb); - -#endif /* _DAVINCI_VPFE_DM365_IPIPE_HW_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c deleted file mode 100644 index 51d4cd1bdb97..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c +++ /dev/null @@ -1,1070 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#include "dm365_ipipeif.h" -#include "vpfe_mc_capture.h" - -static const unsigned int ipipeif_input_fmts[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_SGRBG12_1X12, - MEDIA_BUS_FMT_Y8_1X8, - MEDIA_BUS_FMT_UV8_1X8, - MEDIA_BUS_FMT_YDYUYDYV8_1X16, - MEDIA_BUS_FMT_SBGGR8_1X8, -}; - -static const unsigned int ipipeif_output_fmts[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_SGRBG12_1X12, - MEDIA_BUS_FMT_Y8_1X8, - MEDIA_BUS_FMT_UV8_1X8, - MEDIA_BUS_FMT_YDYUYDYV8_1X16, - MEDIA_BUS_FMT_SBGGR8_1X8, - MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, - MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, -}; - -static int -ipipeif_get_pack_mode(u32 in_pix_fmt) -{ - switch (in_pix_fmt) { - case MEDIA_BUS_FMT_SBGGR8_1X8: - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - case MEDIA_BUS_FMT_UV8_1X8: - return IPIPEIF_5_1_PACK_8_BIT; - - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - return IPIPEIF_5_1_PACK_8_BIT_A_LAW; - - case MEDIA_BUS_FMT_SGRBG12_1X12: - return IPIPEIF_5_1_PACK_16_BIT; - - case MEDIA_BUS_FMT_SBGGR12_1X12: - return IPIPEIF_5_1_PACK_12_BIT; - - default: - return IPIPEIF_5_1_PACK_16_BIT; - } -} - -static inline u32 ipipeif_read(void __iomem *addr, u32 offset) -{ - return readl(addr + offset); -} - -static inline void ipipeif_write(u32 val, void __iomem *addr, u32 offset) -{ - writel(val, addr + offset); -} - -static void ipipeif_config_dpc(void __iomem *addr, struct ipipeif_dpc *dpc) -{ - u32 val = 0; - - if (dpc->en) { - val = (dpc->en & 1) << IPIPEIF_DPC2_EN_SHIFT; - val |= dpc->thr & IPIPEIF_DPC2_THR_MASK; - } - ipipeif_write(val, addr, IPIPEIF_DPC2); -} - -#define IPIPEIF_MODE_CONTINUOUS 0 -#define IPIPEIF_MODE_ONE_SHOT 1 - -static int get_oneshot_mode(enum ipipeif_input_entity input) -{ - if (input == IPIPEIF_INPUT_MEMORY) - return IPIPEIF_MODE_ONE_SHOT; - if (input == IPIPEIF_INPUT_ISIF) - return IPIPEIF_MODE_CONTINUOUS; - - return -EINVAL; -} - -static int -ipipeif_get_cfg_src1(struct vpfe_ipipeif_device *ipipeif) -{ - struct v4l2_mbus_framefmt *informat; - - informat = &ipipeif->formats[IPIPEIF_PAD_SINK]; - if (ipipeif->input == IPIPEIF_INPUT_MEMORY && - (informat->code == MEDIA_BUS_FMT_Y8_1X8 || - informat->code == MEDIA_BUS_FMT_UV8_1X8)) - return IPIPEIF_CCDC; - - return IPIPEIF_SRC1_PARALLEL_PORT; -} - -static int -ipipeif_get_data_shift(struct vpfe_ipipeif_device *ipipeif) -{ - struct v4l2_mbus_framefmt *informat; - - informat = &ipipeif->formats[IPIPEIF_PAD_SINK]; - - switch (informat->code) { - case MEDIA_BUS_FMT_SGRBG12_1X12: - return IPIPEIF_5_1_BITS11_0; - - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_UV8_1X8: - return IPIPEIF_5_1_BITS11_0; - - default: - return IPIPEIF_5_1_BITS7_0; - } -} - -static enum ipipeif_input_source -ipipeif_get_source(struct vpfe_ipipeif_device *ipipeif) -{ - struct v4l2_mbus_framefmt *informat; - - informat = &ipipeif->formats[IPIPEIF_PAD_SINK]; - if (ipipeif->input == IPIPEIF_INPUT_ISIF) - return IPIPEIF_CCDC; - - if (informat->code == MEDIA_BUS_FMT_UYVY8_2X8) - return IPIPEIF_SDRAM_YUV; - - return IPIPEIF_SDRAM_RAW; -} - -void vpfe_ipipeif_ss_buffer_isr(struct vpfe_ipipeif_device *ipipeif) -{ - struct vpfe_video_device *video_in = &ipipeif->video_in; - - if (ipipeif->input != IPIPEIF_INPUT_MEMORY) - return; - - spin_lock(&video_in->dma_queue_lock); - vpfe_video_process_buffer_complete(video_in); - video_in->state = VPFE_VIDEO_BUFFER_NOT_QUEUED; - vpfe_video_schedule_next_buffer(video_in); - spin_unlock(&video_in->dma_queue_lock); -} - -int vpfe_ipipeif_decimation_enabled(struct vpfe_device *vpfe_dev) -{ - struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif; - - return ipipeif->config.decimation; -} - -int vpfe_ipipeif_get_rsz(struct vpfe_device *vpfe_dev) -{ - struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif; - - return ipipeif->config.rsz; -} - -#define RD_DATA_15_2 0x7 - -/* - * ipipeif_hw_setup() - This function sets up IPIPEIF - * @sd: pointer to v4l2 subdev structure - * return -EINVAL or zero on success - */ -static int ipipeif_hw_setup(struct v4l2_subdev *sd) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *informat, *outformat; - struct ipipeif_params params = ipipeif->config; - enum ipipeif_input_source ipipeif_source; - u32 isif_port_if; - void __iomem *ipipeif_base_addr; - unsigned long val; - int data_shift; - int pack_mode; - int source1; - int tmp; - - ipipeif_base_addr = ipipeif->ipipeif_base_addr; - - /* Enable clock to IPIPEIF and IPIPE */ - vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); - - informat = &ipipeif->formats[IPIPEIF_PAD_SINK]; - outformat = &ipipeif->formats[IPIPEIF_PAD_SOURCE]; - - /* Combine all the fields to make CFG1 register of IPIPEIF */ - tmp = val = get_oneshot_mode(ipipeif->input); - if (tmp < 0) { - dev_err(&sd->devnode->dev, "ipipeif: links setup required"); - return -EINVAL; - } - val <<= ONESHOT_SHIFT; - - ipipeif_source = ipipeif_get_source(ipipeif); - val |= ipipeif_source << INPSRC_SHIFT; - - val |= params.clock_select << CLKSEL_SHIFT; - val |= params.avg_filter << AVGFILT_SHIFT; - val |= params.decimation << DECIM_SHIFT; - - pack_mode = ipipeif_get_pack_mode(informat->code); - val |= pack_mode << PACK8IN_SHIFT; - - source1 = ipipeif_get_cfg_src1(ipipeif); - val |= source1 << INPSRC1_SHIFT; - - data_shift = ipipeif_get_data_shift(ipipeif); - if (ipipeif_source != IPIPEIF_SDRAM_YUV) - val |= data_shift << DATASFT_SHIFT; - else - val &= ~(RD_DATA_15_2 << DATASFT_SHIFT); - - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG1); - - switch (ipipeif_source) { - case IPIPEIF_CCDC: - ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN); - break; - - case IPIPEIF_SDRAM_RAW: - case IPIPEIF_CCDC_DARKFM: - ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN); - /* fall through */ - case IPIPEIF_SDRAM_YUV: - val |= data_shift << DATASFT_SHIFT; - ipipeif_write(params.ppln, ipipeif_base_addr, IPIPEIF_PPLN); - ipipeif_write(params.lpfr, ipipeif_base_addr, IPIPEIF_LPFR); - ipipeif_write(informat->width, ipipeif_base_addr, IPIPEIF_HNUM); - ipipeif_write(informat->height, - ipipeif_base_addr, IPIPEIF_VNUM); - break; - - default: - return -EINVAL; - } - - /*check if decimation is enable or not */ - if (params.decimation) - ipipeif_write(params.rsz, ipipeif_base_addr, IPIPEIF_RSZ); - - /* Setup sync alignment and initial rsz position */ - val = params.if_5_1.align_sync & 1; - val <<= IPIPEIF_INIRSZ_ALNSYNC_SHIFT; - val |= params.if_5_1.rsz_start & IPIPEIF_INIRSZ_MASK; - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_INIRSZ); - isif_port_if = informat->code; - - if (isif_port_if == MEDIA_BUS_FMT_Y8_1X8) - isif_port_if = MEDIA_BUS_FMT_YUYV8_1X16; - else if (isif_port_if == MEDIA_BUS_FMT_UV8_1X8) - isif_port_if = MEDIA_BUS_FMT_SGRBG12_1X12; - - /* Enable DPCM decompression */ - switch (ipipeif_source) { - case IPIPEIF_SDRAM_RAW: - val = 0; - if (outformat->code == MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8) { - val = 1; - val |= (IPIPEIF_DPCM_8BIT_10BIT & 1) << - IPIPEIF_DPCM_BITS_SHIFT; - val |= (ipipeif->dpcm_predictor & 1) << - IPIPEIF_DPCM_PRED_SHIFT; - } - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DPCM); - - /* set DPC */ - ipipeif_config_dpc(ipipeif_base_addr, ¶ms.if_5_1.dpc); - - ipipeif_write(params.if_5_1.clip, - ipipeif_base_addr, IPIPEIF_OCLIP); - - /* fall through for SDRAM YUV mode */ - /* configure CFG2 */ - val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CFG2); - switch (isif_port_if) { - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_Y8_1X8: - clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val); - set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val); - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2); - break; - - default: - clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val); - clear_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val); - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2); - break; - } - /* fall through */ - - case IPIPEIF_SDRAM_YUV: - /* Set clock divider */ - if (params.clock_select == IPIPEIF_SDRAM_CLK) { - val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CLKDIV); - val |= (params.if_5_1.clk_div.m - 1) << - IPIPEIF_CLKDIV_M_SHIFT; - val |= (params.if_5_1.clk_div.n - 1); - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CLKDIV); - } - break; - - case IPIPEIF_CCDC: - case IPIPEIF_CCDC_DARKFM: - /* set DPC */ - ipipeif_config_dpc(ipipeif_base_addr, ¶ms.if_5_1.dpc); - - /* Set DF gain & threshold control */ - val = 0; - if (params.if_5_1.df_gain_en) { - val = params.if_5_1.df_gain_thr & - IPIPEIF_DF_GAIN_THR_MASK; - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGTH); - val = (params.if_5_1.df_gain_en & 1) << - IPIPEIF_DF_GAIN_EN_SHIFT; - val |= params.if_5_1.df_gain & - IPIPEIF_DF_GAIN_MASK; - } - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGVL); - /* configure CFG2 */ - val = VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_HDPOL_SHIFT; - val |= VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_VDPOL_SHIFT; - - switch (isif_port_if) { - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_YUYV10_1X20: - clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val); - set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val); - break; - - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_YUYV10_2X10: - set_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val); - set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val); - val |= IPIPEIF_CBCR_Y << IPIPEIF_CFG2_YUV8P_SHIFT; - break; - - default: - /* Bayer */ - ipipeif_write(params.if_5_1.clip, ipipeif_base_addr, - IPIPEIF_OCLIP); - } - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int -ipipeif_set_config(struct v4l2_subdev *sd, struct ipipeif_params *config) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct device *dev = ipipeif->subdev.v4l2_dev->dev; - - if (!config) { - dev_err(dev, "Invalid configuration pointer\n"); - return -EINVAL; - } - - ipipeif->config.clock_select = config->clock_select; - ipipeif->config.ppln = config->ppln; - ipipeif->config.lpfr = config->lpfr; - ipipeif->config.rsz = config->rsz; - ipipeif->config.decimation = config->decimation; - if (ipipeif->config.decimation && - (ipipeif->config.rsz < IPIPEIF_RSZ_MIN || - ipipeif->config.rsz > IPIPEIF_RSZ_MAX)) { - dev_err(dev, "rsz range is %d to %d\n", - IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX); - return -EINVAL; - } - - ipipeif->config.avg_filter = config->avg_filter; - - ipipeif->config.if_5_1.df_gain_thr = config->if_5_1.df_gain_thr; - ipipeif->config.if_5_1.df_gain = config->if_5_1.df_gain; - ipipeif->config.if_5_1.df_gain_en = config->if_5_1.df_gain_en; - - ipipeif->config.if_5_1.rsz_start = config->if_5_1.rsz_start; - ipipeif->config.if_5_1.align_sync = config->if_5_1.align_sync; - ipipeif->config.if_5_1.clip = config->if_5_1.clip; - - ipipeif->config.if_5_1.dpc.en = config->if_5_1.dpc.en; - ipipeif->config.if_5_1.dpc.thr = config->if_5_1.dpc.thr; - - ipipeif->config.if_5_1.clk_div.m = config->if_5_1.clk_div.m; - ipipeif->config.if_5_1.clk_div.n = config->if_5_1.clk_div.n; - - return 0; -} - -static int -ipipeif_get_config(struct v4l2_subdev *sd, void *arg) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct ipipeif_params *config = arg; - struct device *dev = ipipeif->subdev.v4l2_dev->dev; - - if (!arg) { - dev_err(dev, "Invalid configuration pointer\n"); - return -EINVAL; - } - - config->clock_select = ipipeif->config.clock_select; - config->ppln = ipipeif->config.ppln; - config->lpfr = ipipeif->config.lpfr; - config->rsz = ipipeif->config.rsz; - config->decimation = ipipeif->config.decimation; - config->avg_filter = ipipeif->config.avg_filter; - - config->if_5_1.df_gain_thr = ipipeif->config.if_5_1.df_gain_thr; - config->if_5_1.df_gain = ipipeif->config.if_5_1.df_gain; - config->if_5_1.df_gain_en = ipipeif->config.if_5_1.df_gain_en; - - config->if_5_1.rsz_start = ipipeif->config.if_5_1.rsz_start; - config->if_5_1.align_sync = ipipeif->config.if_5_1.align_sync; - config->if_5_1.clip = ipipeif->config.if_5_1.clip; - - config->if_5_1.dpc.en = ipipeif->config.if_5_1.dpc.en; - config->if_5_1.dpc.thr = ipipeif->config.if_5_1.dpc.thr; - - config->if_5_1.clk_div.m = ipipeif->config.if_5_1.clk_div.m; - config->if_5_1.clk_div.n = ipipeif->config.if_5_1.clk_div.n; - - return 0; -} - -/* - * ipipeif_ioctl() - Handle ipipeif module private ioctl's - * @sd: pointer to v4l2 subdev structure - * @cmd: configuration command - * @arg: configuration argument - */ -static long ipipeif_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct ipipeif_params *config = arg; - int ret = -ENOIOCTLCMD; - - switch (cmd) { - case VIDIOC_VPFE_IPIPEIF_S_CONFIG: - ret = ipipeif_set_config(sd, config); - break; - - case VIDIOC_VPFE_IPIPEIF_G_CONFIG: - ret = ipipeif_get_config(sd, arg); - break; - } - return ret; -} - -/* - * ipipeif_s_ctrl() - Handle set control subdev method - * @ctrl: pointer to v4l2 control structure - */ -static int ipipeif_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vpfe_ipipeif_device *ipipeif = - container_of(ctrl->handler, struct vpfe_ipipeif_device, ctrls); - - switch (ctrl->id) { - case VPFE_CID_DPCM_PREDICTOR: - ipipeif->dpcm_predictor = ctrl->val; - break; - - case V4L2_CID_GAIN: - ipipeif->gain = ctrl->val; - break; - - default: - return -EINVAL; - } - - return 0; -} - -#define ENABLE_IPIPEIF 0x1 - -void vpfe_ipipeif_enable(struct vpfe_device *vpfe_dev) -{ - struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif; - void __iomem *ipipeif_base_addr = ipipeif->ipipeif_base_addr; - unsigned char val; - - if (ipipeif->input != IPIPEIF_INPUT_MEMORY) - return; - - do { - val = ipipeif_read(ipipeif_base_addr, IPIPEIF_ENABLE); - } while (val & 0x1); - - ipipeif_write(ENABLE_IPIPEIF, ipipeif_base_addr, IPIPEIF_ENABLE); -} - -/* - * ipipeif_set_stream() - Enable/Disable streaming on ipipeif subdev - * @sd: pointer to v4l2 subdev structure - * @enable: 1 == Enable, 0 == Disable - */ -static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif); - int ret = 0; - - if (!enable) - return ret; - - ret = ipipeif_hw_setup(sd); - if (!ret) - vpfe_ipipeif_enable(vpfe_dev); - - return ret; -} - -/* - * ipipeif_enum_mbus_code() - Handle pixel format enumeration - * @sd: pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - * return -EINVAL or zero on success - */ -static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - switch (code->pad) { - case IPIPEIF_PAD_SINK: - if (code->index >= ARRAY_SIZE(ipipeif_input_fmts)) - return -EINVAL; - - code->code = ipipeif_input_fmts[code->index]; - break; - - case IPIPEIF_PAD_SOURCE: - if (code->index >= ARRAY_SIZE(ipipeif_output_fmts)) - return -EINVAL; - - code->code = ipipeif_output_fmts[code->index]; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * ipipeif_get_format() - Handle get format by pads subdev method - * @sd: pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - */ -static int -ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - fmt->format = ipipeif->formats[fmt->pad]; - else - fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad)); - - return 0; -} - -#define MIN_OUT_WIDTH 32 -#define MIN_OUT_HEIGHT 32 - -/* - * ipipeif_try_format() - Handle try format by pad subdev method - * @ipipeif: VPFE ipipeif device. - * @cfg: V4L2 subdev pad config - * @pad: pad num. - * @fmt: pointer to v4l2 format structure. - * @which : wanted subdev format - */ -static void -ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, - struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - unsigned int max_out_height; - unsigned int max_out_width; - unsigned int i; - - max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A; - max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A; - - if (pad == IPIPEIF_PAD_SINK) { - for (i = 0; i < ARRAY_SIZE(ipipeif_input_fmts); i++) - if (fmt->code == ipipeif_input_fmts[i]) - break; - - /* If not found, use SBGGR10 as default */ - if (i >= ARRAY_SIZE(ipipeif_input_fmts)) - fmt->code = MEDIA_BUS_FMT_SGRBG12_1X12; - } else if (pad == IPIPEIF_PAD_SOURCE) { - for (i = 0; i < ARRAY_SIZE(ipipeif_output_fmts); i++) - if (fmt->code == ipipeif_output_fmts[i]) - break; - - /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(ipipeif_output_fmts)) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; - } - - fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width); - fmt->height = clamp_t(u32, fmt->height, MIN_OUT_WIDTH, max_out_height); -} - -static int -ipipeif_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * __ipipeif_get_format() - helper function for getting ipipeif format - * @ipipeif: pointer to ipipeif private structure. - * @cfg: V4L2 subdev pad config - * @pad: pad number. - * @which: wanted subdev format. - * - */ -static struct v4l2_mbus_framefmt * -__ipipeif_get_format(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad); - - return &ipipeif->formats[pad]; -} - -/* - * ipipeif_set_format() - Handle set format by pads subdev method - * @sd: pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int -ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - return 0; - - if (fmt->pad == IPIPEIF_PAD_SINK && - ipipeif->input != IPIPEIF_INPUT_NONE) - ipipeif->formats[fmt->pad] = fmt->format; - else if (fmt->pad == IPIPEIF_PAD_SOURCE && - ipipeif->output != IPIPEIF_OUTPUT_NONE) - ipipeif->formats[fmt->pad] = fmt->format; - else - return -EINVAL; - - return 0; -} - -static void ipipeif_set_default_config(struct vpfe_ipipeif_device *ipipeif) -{ -#define WIDTH_I 640 -#define HEIGHT_I 480 - - const struct ipipeif_params ipipeif_defaults = { - .clock_select = IPIPEIF_SDRAM_CLK, - .ppln = WIDTH_I + 8, - .lpfr = HEIGHT_I + 10, - .rsz = 16, /* resize ratio 16/rsz */ - .decimation = IPIPEIF_DECIMATION_OFF, - .avg_filter = IPIPEIF_AVG_OFF, - .if_5_1 = { - .clk_div = { - .m = 1, /* clock = sdram clock * (m/n) */ - .n = 6 - }, - .clip = 4095, - }, - }; - memcpy(&ipipeif->config, &ipipeif_defaults, - sizeof(struct ipipeif_params)); -} - -/* - * ipipeif_init_formats() - Initialize formats on all pads - * @sd: VPFE ipipeif V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. Try formats are initialized - * on the file handle. - */ -static int -ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = IPIPEIF_PAD_SINK; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipeif_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = IPIPEIF_PAD_SOURCE; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipeif_set_format(sd, fh->pad, &format); - - ipipeif_set_default_config(ipipeif); - - return 0; -} - -/* - * ipipeif_video_in_queue() - ipipeif video in queue - * @vpfe_dev: vpfe device pointer - * @addr: buffer address - */ -static int -ipipeif_video_in_queue(struct vpfe_device *vpfe_dev, unsigned long addr) -{ - struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif; - void __iomem *ipipeif_base_addr = ipipeif->ipipeif_base_addr; - unsigned int adofs; - u32 val; - - if (ipipeif->input != IPIPEIF_INPUT_MEMORY) - return -EINVAL; - - switch (ipipeif->formats[IPIPEIF_PAD_SINK].code) { - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_UV8_1X8: - case MEDIA_BUS_FMT_YDYUYDYV8_1X16: - adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width; - break; - - default: - adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width << 1; - break; - } - - /* adjust the line len to be a multiple of 32 */ - adofs += 31; - adofs &= ~0x1f; - val = (adofs >> 5) & IPIPEIF_ADOFS_LSB_MASK; - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADOFS); - - /* lower sixteen bit */ - val = (addr >> IPIPEIF_ADDRL_SHIFT) & IPIPEIF_ADDRL_MASK; - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRL); - - /* upper next seven bit */ - val = (addr >> IPIPEIF_ADDRU_SHIFT) & IPIPEIF_ADDRU_MASK; - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRU); - - return 0; -} - -/* subdev core operations */ -static const struct v4l2_subdev_core_ops ipipeif_v4l2_core_ops = { - .ioctl = ipipeif_ioctl, -}; - -static const struct v4l2_ctrl_ops ipipeif_ctrl_ops = { - .s_ctrl = ipipeif_s_ctrl, -}; - -static const struct v4l2_ctrl_config vpfe_ipipeif_dpcm_pred = { - .ops = &ipipeif_ctrl_ops, - .id = VPFE_CID_DPCM_PREDICTOR, - .name = "DPCM Predictor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 1, - .step = 1, - .def = 0, -}; - -/* subdev file operations */ -static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = { - .open = ipipeif_init_formats, -}; - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = { - .s_stream = ipipeif_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = { - .enum_mbus_code = ipipeif_enum_mbus_code, - .enum_frame_size = ipipeif_enum_frame_size, - .get_fmt = ipipeif_get_format, - .set_fmt = ipipeif_set_format, -}; - -/* subdev operations */ -static const struct v4l2_subdev_ops ipipeif_v4l2_ops = { - .core = &ipipeif_v4l2_core_ops, - .video = &ipipeif_v4l2_video_ops, - .pad = &ipipeif_v4l2_pad_ops, -}; - -static const struct vpfe_video_operations video_in_ops = { - .queue = ipipeif_video_in_queue, -}; - -static int -ipipeif_link_setup(struct media_entity *entity, const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe = to_vpfe_device(ipipeif); - unsigned int index = local->index; - - /* FIXME: this is actually a hack! */ - if (is_media_entity_v4l2_subdev(remote->entity)) - index |= 2 << 16; - - switch (index) { - case IPIPEIF_PAD_SINK: - /* Single shot mode */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ipipeif->input = IPIPEIF_INPUT_NONE; - break; - } - ipipeif->input = IPIPEIF_INPUT_MEMORY; - break; - - case IPIPEIF_PAD_SINK | 2 << 16: - /* read from isif */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ipipeif->input = IPIPEIF_INPUT_NONE; - break; - } - if (ipipeif->input != IPIPEIF_INPUT_NONE) - return -EBUSY; - - ipipeif->input = IPIPEIF_INPUT_ISIF; - break; - - case IPIPEIF_PAD_SOURCE | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ipipeif->output = IPIPEIF_OUTPUT_NONE; - break; - } - if (remote->entity == &vpfe->vpfe_ipipe.subdev.entity) - /* connencted to ipipe */ - ipipeif->output = IPIPEIF_OUTPUT_IPIPE; - else if (remote->entity == &vpfe->vpfe_resizer.crop_resizer.subdev.entity) - /* connected to resizer */ - ipipeif->output = IPIPEIF_OUTPUT_RESIZER; - else - return -EINVAL; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static const struct media_entity_operations ipipeif_media_ops = { - .link_setup = ipipeif_link_setup, -}; - -/* - * vpfe_ipipeif_unregister_entities() - Unregister entity - * @ipipeif - pointer to ipipeif subdevice structure. - */ -void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device *ipipeif) -{ - /* unregister video device */ - vpfe_video_unregister(&ipipeif->video_in); - - /* unregister subdev */ - v4l2_device_unregister_subdev(&ipipeif->subdev); - /* cleanup entity */ - media_entity_cleanup(&ipipeif->subdev.entity); -} - -int -vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_device *vdev) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif); - unsigned int flags; - int ret; - - /* Register the subdev */ - ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev); - if (ret < 0) - return ret; - - ret = vpfe_video_register(&ipipeif->video_in, vdev); - if (ret) { - pr_err("Failed to register ipipeif video-in device\n"); - goto fail; - } - ipipeif->video_in.vpfe_dev = vpfe_dev; - - flags = 0; - ret = media_create_pad_link(&ipipeif->video_in.video_dev.entity, 0, - &ipipeif->subdev.entity, 0, flags); - if (ret < 0) - goto fail; - - return 0; -fail: - v4l2_device_unregister_subdev(&ipipeif->subdev); - - return ret; -} - -#define IPIPEIF_GAIN_HIGH 0x3ff -#define IPIPEIF_DEFAULT_GAIN 0x200 - -int vpfe_ipipeif_init(struct vpfe_ipipeif_device *ipipeif, - struct platform_device *pdev) -{ - struct v4l2_subdev *sd = &ipipeif->subdev; - struct media_pad *pads = &ipipeif->pads[0]; - struct media_entity *me = &sd->entity; - static resource_size_t res_len; - struct resource *res; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 3); - if (!res) - return -ENOENT; - - res_len = resource_size(res); - res = request_mem_region(res->start, res_len, res->name); - if (!res) - return -EBUSY; - - ipipeif->ipipeif_base_addr = ioremap_nocache(res->start, res_len); - if (!ipipeif->ipipeif_base_addr) { - ret = -EBUSY; - goto fail; - } - - v4l2_subdev_init(sd, &ipipeif_v4l2_ops); - - sd->internal_ops = &ipipeif_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI IPIPEIF", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - - v4l2_set_subdevdata(sd, ipipeif); - - sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; - pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[IPIPEIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - ipipeif->input = IPIPEIF_INPUT_NONE; - ipipeif->output = IPIPEIF_OUTPUT_NONE; - me->ops = &ipipeif_media_ops; - - ret = media_entity_pads_init(me, IPIPEIF_NUM_PADS, pads); - if (ret) - goto fail; - - v4l2_ctrl_handler_init(&ipipeif->ctrls, 2); - v4l2_ctrl_new_std(&ipipeif->ctrls, &ipipeif_ctrl_ops, - V4L2_CID_GAIN, 0, - IPIPEIF_GAIN_HIGH, 1, IPIPEIF_DEFAULT_GAIN); - v4l2_ctrl_new_custom(&ipipeif->ctrls, &vpfe_ipipeif_dpcm_pred, NULL); - v4l2_ctrl_handler_setup(&ipipeif->ctrls); - sd->ctrl_handler = &ipipeif->ctrls; - - ipipeif->video_in.ops = &video_in_ops; - ipipeif->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - ret = vpfe_video_init(&ipipeif->video_in, "IPIPEIF"); - if (ret) { - pr_err("Failed to init IPIPEIF video-in device\n"); - goto fail; - } - ipipeif_set_default_config(ipipeif); - return 0; -fail: - release_mem_region(res->start, res_len); - return ret; -} - -void -vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device *ipipeif, - struct platform_device *pdev) -{ - struct resource *res; - - v4l2_ctrl_handler_free(&ipipeif->ctrls); - iounmap(ipipeif->ipipeif_base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 3); - if (res) - release_mem_region(res->start, resource_size(res)); - -} diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.h b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.h deleted file mode 100644 index 4d126fc871f3..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.h +++ /dev/null @@ -1,228 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#ifndef _DAVINCI_VPFE_DM365_IPIPEIF_H -#define _DAVINCI_VPFE_DM365_IPIPEIF_H - -#include <linux/platform_device.h> - -#include <media/davinci/vpss.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-subdev.h> - -#include "dm365_ipipeif_user.h" -#include "vpfe_video.h" - -/* IPIPE base specific types */ -enum ipipeif_data_shift { - IPIPEIF_BITS15_2 = 0, - IPIPEIF_BITS14_1 = 1, - IPIPEIF_BITS13_0 = 2, - IPIPEIF_BITS12_0 = 3, - IPIPEIF_BITS11_0 = 4, - IPIPEIF_BITS10_0 = 5, - IPIPEIF_BITS9_0 = 6, -}; - -enum ipipeif_clkdiv { - IPIPEIF_DIVIDE_HALF = 0, - IPIPEIF_DIVIDE_THIRD = 1, - IPIPEIF_DIVIDE_FOURTH = 2, - IPIPEIF_DIVIDE_FIFTH = 3, - IPIPEIF_DIVIDE_SIXTH = 4, - IPIPEIF_DIVIDE_EIGHTH = 5, - IPIPEIF_DIVIDE_SIXTEENTH = 6, - IPIPEIF_DIVIDE_THIRTY = 7, -}; - -enum ipipeif_pack_mode { - IPIPEIF_PACK_16_BIT = 0, - IPIPEIF_PACK_8_BIT = 1, -}; - -enum ipipeif_5_1_pack_mode { - IPIPEIF_5_1_PACK_16_BIT = 0, - IPIPEIF_5_1_PACK_8_BIT = 1, - IPIPEIF_5_1_PACK_8_BIT_A_LAW = 2, - IPIPEIF_5_1_PACK_12_BIT = 3 -}; - -enum ipipeif_input_source { - IPIPEIF_CCDC = 0, - IPIPEIF_SDRAM_RAW = 1, - IPIPEIF_CCDC_DARKFM = 2, - IPIPEIF_SDRAM_YUV = 3, -}; - -enum ipipeif_ialaw { - IPIPEIF_ALAW_OFF = 0, - IPIPEIF_ALAW_ON = 1, -}; - -enum ipipeif_input_src1 { - IPIPEIF_SRC1_PARALLEL_PORT = 0, - IPIPEIF_SRC1_SDRAM_RAW = 1, - IPIPEIF_SRC1_ISIF_DARKFM = 2, - IPIPEIF_SRC1_SDRAM_YUV = 3, -}; - -enum ipipeif_dfs_dir { - IPIPEIF_PORT_MINUS_SDRAM = 0, - IPIPEIF_SDRAM_MINUS_PORT = 1, -}; - -enum ipipeif_chroma_phase { - IPIPEIF_CBCR_Y = 0, - IPIPEIF_Y_CBCR = 1, -}; - -enum ipipeif_dpcm_type { - IPIPEIF_DPCM_8BIT_10BIT = 0, - IPIPEIF_DPCM_8BIT_12BIT = 1, -}; - -/* data shift for IPIPE 5.1 */ -enum ipipeif_5_1_data_shift { - IPIPEIF_5_1_BITS11_0 = 0, - IPIPEIF_5_1_BITS10_0 = 1, - IPIPEIF_5_1_BITS9_0 = 2, - IPIPEIF_5_1_BITS8_0 = 3, - IPIPEIF_5_1_BITS7_0 = 4, - IPIPEIF_5_1_BITS15_4 = 5, -}; - -#define IPIPEIF_PAD_SINK 0 -#define IPIPEIF_PAD_SOURCE 1 - -#define IPIPEIF_NUM_PADS 2 - -enum ipipeif_input_entity { - IPIPEIF_INPUT_NONE = 0, - IPIPEIF_INPUT_ISIF = 1, - IPIPEIF_INPUT_MEMORY = 2, -}; - -enum ipipeif_output_entity { - IPIPEIF_OUTPUT_NONE = 0, - IPIPEIF_OUTPUT_IPIPE = 1, - IPIPEIF_OUTPUT_RESIZER = 2, -}; - -struct vpfe_ipipeif_device { - struct v4l2_subdev subdev; - struct media_pad pads[IPIPEIF_NUM_PADS]; - struct v4l2_mbus_framefmt formats[IPIPEIF_NUM_PADS]; - enum ipipeif_input_entity input; - unsigned int output; - struct vpfe_video_device video_in; - struct v4l2_ctrl_handler ctrls; - void __iomem *ipipeif_base_addr; - struct ipipeif_params config; - int dpcm_predictor; - int gain; -}; - -/* IPIPEIF Register Offsets from the base address */ -#define IPIPEIF_ENABLE 0x00 -#define IPIPEIF_CFG1 0x04 -#define IPIPEIF_PPLN 0x08 -#define IPIPEIF_LPFR 0x0c -#define IPIPEIF_HNUM 0x10 -#define IPIPEIF_VNUM 0x14 -#define IPIPEIF_ADDRU 0x18 -#define IPIPEIF_ADDRL 0x1c -#define IPIPEIF_ADOFS 0x20 -#define IPIPEIF_RSZ 0x24 -#define IPIPEIF_GAIN 0x28 - -/* Below registers are available only on IPIPE 5.1 */ -#define IPIPEIF_DPCM 0x2c -#define IPIPEIF_CFG2 0x30 -#define IPIPEIF_INIRSZ 0x34 -#define IPIPEIF_OCLIP 0x38 -#define IPIPEIF_DTUDF 0x3c -#define IPIPEIF_CLKDIV 0x40 -#define IPIPEIF_DPC1 0x44 -#define IPIPEIF_DPC2 0x48 -#define IPIPEIF_DFSGVL 0x4c -#define IPIPEIF_DFSGTH 0x50 -#define IPIPEIF_RSZ3A 0x54 -#define IPIPEIF_INIRSZ3A 0x58 -#define IPIPEIF_RSZ_MIN 16 -#define IPIPEIF_RSZ_MAX 112 -#define IPIPEIF_RSZ_CONST 16 - -#define IPIPEIF_ADOFS_LSB_MASK 0x1ff -#define IPIPEIF_ADOFS_LSB_SHIFT 5 -#define IPIPEIF_ADOFS_MSB_MASK 0x200 -#define IPIPEIF_ADDRU_MASK 0x7ff -#define IPIPEIF_ADDRL_SHIFT 5 -#define IPIPEIF_ADDRL_MASK 0xffff -#define IPIPEIF_ADDRU_SHIFT 21 -#define IPIPEIF_ADDRMSB_SHIFT 31 -#define IPIPEIF_ADDRMSB_LEFT_SHIFT 10 - -/* CFG1 Masks and shifts */ -#define ONESHOT_SHIFT 0 -#define DECIM_SHIFT 1 -#define INPSRC_SHIFT 2 -#define CLKDIV_SHIFT 4 -#define AVGFILT_SHIFT 7 -#define PACK8IN_SHIFT 8 -#define IALAW_SHIFT 9 -#define CLKSEL_SHIFT 10 -#define DATASFT_SHIFT 11 -#define INPSRC1_SHIFT 14 - -/* DPC2 */ -#define IPIPEIF_DPC2_EN_SHIFT 12 -#define IPIPEIF_DPC2_THR_MASK 0xfff -/* Applicable for IPIPE 5.1 */ -#define IPIPEIF_DF_GAIN_EN_SHIFT 10 -#define IPIPEIF_DF_GAIN_MASK 0x3ff -#define IPIPEIF_DF_GAIN_THR_MASK 0xfff -/* DPCM */ -#define IPIPEIF_DPCM_BITS_SHIFT 2 -#define IPIPEIF_DPCM_PRED_SHIFT 1 -/* CFG2 */ -#define IPIPEIF_CFG2_HDPOL_SHIFT 1 -#define IPIPEIF_CFG2_VDPOL_SHIFT 2 -#define IPIPEIF_CFG2_YUV8_SHIFT 6 -#define IPIPEIF_CFG2_YUV16_SHIFT 3 -#define IPIPEIF_CFG2_YUV8P_SHIFT 7 - -/* INIRSZ */ -#define IPIPEIF_INIRSZ_ALNSYNC_SHIFT 13 -#define IPIPEIF_INIRSZ_MASK 0x1fff - -/* CLKDIV */ -#define IPIPEIF_CLKDIV_M_SHIFT 8 - -void vpfe_ipipeif_enable(struct vpfe_device *vpfe_dev); -void vpfe_ipipeif_ss_buffer_isr(struct vpfe_ipipeif_device *ipipeif); -int vpfe_ipipeif_decimation_enabled(struct vpfe_device *vpfe_dev); -int vpfe_ipipeif_get_rsz(struct vpfe_device *vpfe_dev); -void vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device *ipipeif, - struct platform_device *pdev); -int vpfe_ipipeif_init(struct vpfe_ipipeif_device *ipipeif, - struct platform_device *pdev); -int vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_device *vdev); -void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device *ipipeif); - -#endif /* _DAVINCI_VPFE_DM365_IPIPEIF_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h b/drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h deleted file mode 100644 index 046dbdec67d8..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#ifndef _DAVINCI_VPFE_DM365_IPIPEIF_USER_H -#define _DAVINCI_VPFE_DM365_IPIPEIF_USER_H - -/* clockdiv for IPIPE 5.1 */ -struct ipipeif_5_1_clkdiv { - unsigned char m; - unsigned char n; -}; - -enum ipipeif_decimation { - IPIPEIF_DECIMATION_OFF, - IPIPEIF_DECIMATION_ON -}; - -/* DPC at the if for IPIPE 5.1 */ -struct ipipeif_dpc { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* threshold */ - unsigned short thr; -}; - -enum ipipeif_clock { - IPIPEIF_PIXCEL_CLK, - IPIPEIF_SDRAM_CLK -}; - -enum ipipeif_avg_filter { - IPIPEIF_AVG_OFF, - IPIPEIF_AVG_ON -}; - -struct ipipeif_5_1 { - struct ipipeif_5_1_clkdiv clk_div; - /* Defect pixel correction */ - struct ipipeif_dpc dpc; - /* clipped to this value */ - unsigned short clip; - /* Align HSync and VSync to rsz_start */ - unsigned char align_sync; - /* resizer start position */ - unsigned int rsz_start; - /* DF gain enable */ - unsigned char df_gain_en; - /* DF gain value */ - unsigned short df_gain; - /* DF gain threshold value */ - unsigned short df_gain_thr; -}; - -struct ipipeif_params { - enum ipipeif_clock clock_select; - unsigned int ppln; - unsigned int lpfr; - unsigned char rsz; - enum ipipeif_decimation decimation; - enum ipipeif_avg_filter avg_filter; - /* IPIPE 5.1 */ - struct ipipeif_5_1 if_5_1; -}; - -/* - * Private IOCTL - * VIDIOC_VPFE_IPIPEIF_S_CONFIG: Set IPIEIF configuration - * VIDIOC_VPFE_IPIPEIF_G_CONFIG: Get IPIEIF configuration - */ -#define VIDIOC_VPFE_IPIPEIF_S_CONFIG \ - _IOWR('I', BASE_VIDIOC_PRIVATE + 1, struct ipipeif_params) -#define VIDIOC_VPFE_IPIPEIF_G_CONFIG \ - _IOWR('I', BASE_VIDIOC_PRIVATE + 2, struct ipipeif_params) - -#endif /* _DAVINCI_VPFE_DM365_IPIPEIF_USER_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c deleted file mode 100644 index 05a997f7aa5d..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.c +++ /dev/null @@ -1,2097 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#include <linux/delay.h> -#include "dm365_isif.h" -#include "vpfe_mc_capture.h" - -#define MAX_WIDTH 4096 -#define MAX_HEIGHT 4096 - -static const unsigned int isif_fmts[] = { - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_YUYV8_1X16, - MEDIA_BUS_FMT_YUYV10_1X20, - MEDIA_BUS_FMT_SGRBG12_1X12, - MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, - MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, -}; - -#define ISIF_COLPTN_R_Ye 0x0 -#define ISIF_COLPTN_Gr_Cy 0x1 -#define ISIF_COLPTN_Gb_G 0x2 -#define ISIF_COLPTN_B_Mg 0x3 - -#define ISIF_CCOLP_CP01_0 0 -#define ISIF_CCOLP_CP03_2 2 -#define ISIF_CCOLP_CP05_4 4 -#define ISIF_CCOLP_CP07_6 6 -#define ISIF_CCOLP_CP11_0 8 -#define ISIF_CCOLP_CP13_2 10 -#define ISIF_CCOLP_CP15_4 12 -#define ISIF_CCOLP_CP17_6 14 - -static const u32 isif_sgrbg_pattern = - ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP01_0 | - ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP03_2 | - ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP05_4 | - ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP07_6 | - ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP11_0 | - ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP13_2 | - ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP15_4 | - ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP17_6; - -static const u32 isif_srggb_pattern = - ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP01_0 | - ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP03_2 | - ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP05_4 | - ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP07_6 | - ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP11_0 | - ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP13_2 | - ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP15_4 | - ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP17_6; - -static inline u32 isif_read(void __iomem *base_addr, u32 offset) -{ - return readl(base_addr + offset); -} - -static inline void isif_write(void __iomem *base_addr, u32 val, u32 offset) -{ - writel(val, base_addr + offset); -} - -static inline u32 isif_merge(void __iomem *base_addr, u32 mask, u32 val, - u32 offset) -{ - u32 new_val = (isif_read(base_addr, offset) & ~mask) | (val & mask); - - isif_write(base_addr, new_val, offset); - - return new_val; -} - -static void isif_enable_output_to_sdram(struct vpfe_isif_device *isif, int en) -{ - isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_WEN_MASK, - en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN); -} - -static inline void -isif_regw_lin_tbl(struct vpfe_isif_device *isif, u32 val, u32 offset, int i) -{ - if (!i) - writel(val, isif->isif_cfg.linear_tbl0_addr + offset); - else - writel(val, isif->isif_cfg.linear_tbl1_addr + offset); -} - -static void isif_disable_all_modules(struct vpfe_isif_device *isif) -{ - /* disable BC */ - isif_write(isif->isif_cfg.base_addr, 0, CLAMPCFG); - /* disable vdfc */ - isif_write(isif->isif_cfg.base_addr, 0, DFCCTL); - /* disable CSC */ - isif_write(isif->isif_cfg.base_addr, 0, CSCCTL); - /* disable linearization */ - isif_write(isif->isif_cfg.base_addr, 0, LINCFG0); -} - -static void isif_enable(struct vpfe_isif_device *isif, int en) -{ - if (!en) - /* Before disable isif, disable all ISIF modules */ - isif_disable_all_modules(isif); - - /* - * wait for next VD. Assume lowest scan rate is 12 Hz. So - * 100 msec delay is good enough - */ - msleep(100); - isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_VDHDEN_MASK, - en, SYNCEN); -} - -/* - * ISIF helper functions - */ - -#define DM365_ISIF_MDFS_OFFSET 15 -#define DM365_ISIF_MDFS_MASK 0x1 - -/* get field id in isif hardware */ -enum v4l2_field vpfe_isif_get_fid(struct vpfe_device *vpfe_dev) -{ - struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif; - u32 field_status; - - field_status = isif_read(isif->isif_cfg.base_addr, MODESET); - return (field_status >> DM365_ISIF_MDFS_OFFSET) & - DM365_ISIF_MDFS_MASK; -} - -static int -isif_set_pixel_format(struct vpfe_isif_device *isif, unsigned int pixfmt) -{ - if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) { - if (pixfmt == V4L2_PIX_FMT_SBGGR16) - isif->isif_cfg.data_pack = ISIF_PACK_16BIT; - else if ((pixfmt == V4L2_PIX_FMT_SGRBG10DPCM8) || - (pixfmt == V4L2_PIX_FMT_SGRBG10ALAW8)) - isif->isif_cfg.data_pack = ISIF_PACK_8BIT; - else - return -EINVAL; - - isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW; - isif->isif_cfg.bayer.v4l2_pix_fmt = pixfmt; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY; - else - return -EINVAL; - - isif->isif_cfg.data_pack = ISIF_PACK_8BIT; - isif->isif_cfg.ycbcr.v4l2_pix_fmt = pixfmt; - } - - return 0; -} - -static int -isif_set_frame_format(struct vpfe_isif_device *isif, - enum isif_frmfmt frm_fmt) -{ - if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) - isif->isif_cfg.bayer.frm_fmt = frm_fmt; - else - isif->isif_cfg.ycbcr.frm_fmt = frm_fmt; - - return 0; -} - -static int isif_set_image_window(struct vpfe_isif_device *isif) -{ - struct v4l2_rect *win = &isif->crop; - - if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) { - isif->isif_cfg.bayer.win.top = win->top; - isif->isif_cfg.bayer.win.left = win->left; - isif->isif_cfg.bayer.win.width = win->width; - isif->isif_cfg.bayer.win.height = win->height; - return 0; - } - isif->isif_cfg.ycbcr.win.top = win->top; - isif->isif_cfg.ycbcr.win.left = win->left; - isif->isif_cfg.ycbcr.win.width = win->width; - isif->isif_cfg.ycbcr.win.height = win->height; - - return 0; -} - -static int -isif_set_buftype(struct vpfe_isif_device *isif, enum isif_buftype buf_type) -{ - if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) - isif->isif_cfg.bayer.buf_type = buf_type; - else - isif->isif_cfg.ycbcr.buf_type = buf_type; - - return 0; -} - -/* configure format in isif hardware */ -static int -isif_config_format(struct vpfe_device *vpfe_dev, unsigned int pad) -{ - struct vpfe_isif_device *vpfe_isif = &vpfe_dev->vpfe_isif; - enum isif_frmfmt frm_fmt = ISIF_FRMFMT_INTERLACED; - struct v4l2_pix_format format; - int ret = 0; - - v4l2_fill_pix_format(&format, &vpfe_dev->vpfe_isif.formats[pad]); - mbus_to_pix(&vpfe_dev->vpfe_isif.formats[pad], &format); - - if (isif_set_pixel_format(vpfe_isif, format.pixelformat) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Failed to set pixel format in isif\n"); - return -EINVAL; - } - - /* call for s_crop will override these values */ - vpfe_isif->crop.left = 0; - vpfe_isif->crop.top = 0; - vpfe_isif->crop.width = format.width; - vpfe_isif->crop.height = format.height; - - /* configure the image window */ - isif_set_image_window(vpfe_isif); - - switch (vpfe_dev->vpfe_isif.formats[pad].field) { - case V4L2_FIELD_INTERLACED: - /* do nothing, since it is default */ - ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_INTERLEAVED); - break; - - case V4L2_FIELD_NONE: - frm_fmt = ISIF_FRMFMT_PROGRESSIVE; - /* buffer type only applicable for interlaced scan */ - break; - - case V4L2_FIELD_SEQ_TB: - ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_SEPARATED); - break; - - default: - return -EINVAL; - } - - /* set the frame format */ - if (!ret) - ret = isif_set_frame_format(vpfe_isif, frm_fmt); - - return ret; -} - -/* - * isif_try_format() - Try video format on a pad - * @isif: VPFE isif device - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - */ -static void -isif_try_format(struct vpfe_isif_device *isif, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - unsigned int width = fmt->format.width; - unsigned int height = fmt->format.height; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(isif_fmts); i++) { - if (fmt->format.code == isif_fmts[i]) - break; - } - - /* If not found, use YUYV8_2x8 as default */ - if (i >= ARRAY_SIZE(isif_fmts)) - fmt->format.code = MEDIA_BUS_FMT_YUYV8_2X8; - - /* Clamp the size. */ - fmt->format.width = clamp_t(u32, width, 32, MAX_WIDTH); - fmt->format.height = clamp_t(u32, height, 32, MAX_HEIGHT); - - /* The data formatter truncates the number of horizontal output - * pixels to a multiple of 16. To avoid clipping data, allow - * callers to request an output size bigger than the input size - * up to the nearest multiple of 16. - */ - if (fmt->pad == ISIF_PAD_SOURCE) - fmt->format.width &= ~15; -} - -/* - * vpfe_isif_buffer_isr() - isif module non-progressive buffer scheduling isr - * @isif: Pointer to isif subdevice. - */ -void vpfe_isif_buffer_isr(struct vpfe_isif_device *isif) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(isif); - struct vpfe_video_device *video = &isif->video_out; - enum v4l2_field field; - int fid; - - if (!video->started) - return; - - field = video->fmt.fmt.pix.field; - - if (field == V4L2_FIELD_NONE) { - /* handle progressive frame capture */ - if (video->cur_frm != video->next_frm) - vpfe_video_process_buffer_complete(video); - return; - } - - /* interlaced or TB capture check which field we - * are in hardware - */ - fid = vpfe_isif_get_fid(vpfe_dev); - - /* switch the software maintained field id */ - video->field_id ^= 1; - if (fid == video->field_id) { - /* we are in-sync here,continue */ - if (fid == 0) { - /* - * One frame is just being captured. If the - * next frame is available, release the current - * frame and move on - */ - if (video->cur_frm != video->next_frm) - vpfe_video_process_buffer_complete(video); - /* - * based on whether the two fields are stored - * interleavely or separately in memory, - * reconfigure the ISIF memory address - */ - if (field == V4L2_FIELD_SEQ_TB) - vpfe_video_schedule_bottom_field(video); - return; - } - /* - * if one field is just being captured configure - * the next frame get the next frame from the - * empty queue if no frame is available hold on - * to the current buffer - */ - spin_lock(&video->dma_queue_lock); - if (!list_empty(&video->dma_queue) && - video->cur_frm == video->next_frm) - vpfe_video_schedule_next_buffer(video); - spin_unlock(&video->dma_queue_lock); - } else if (fid == 0) { - /* - * out of sync. Recover from any hardware out-of-sync. - * May loose one frame - */ - video->field_id = fid; - } -} - -/* - * vpfe_isif_vidint1_isr() - ISIF module progressive buffer scheduling isr - * @isif: Pointer to isif subdevice. - */ -void vpfe_isif_vidint1_isr(struct vpfe_isif_device *isif) -{ - struct vpfe_video_device *video = &isif->video_out; - - if (!video->started) - return; - - spin_lock(&video->dma_queue_lock); - if (video->fmt.fmt.pix.field == V4L2_FIELD_NONE && - !list_empty(&video->dma_queue) && video->cur_frm == video->next_frm) - vpfe_video_schedule_next_buffer(video); - - spin_unlock(&video->dma_queue_lock); -} - -/* - * VPFE video operations - */ - -static int isif_video_queue(struct vpfe_device *vpfe_dev, unsigned long addr) -{ - struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif; - - isif_write(isif->isif_cfg.base_addr, (addr >> 21) & - ISIF_CADU_BITS, CADU); - isif_write(isif->isif_cfg.base_addr, (addr >> 5) & - ISIF_CADL_BITS, CADL); - - return 0; -} - -static const struct vpfe_video_operations isif_video_ops = { - .queue = isif_video_queue, -}; - -/* - * V4L2 subdev operations - */ - -/* Parameter operations */ -static int isif_get_params(struct v4l2_subdev *sd, void *params) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - - /* only raw module parameters can be set through the IOCTL */ - if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12) - return -EINVAL; - memcpy(params, &isif->isif_cfg.bayer.config_params, - sizeof(isif->isif_cfg.bayer.config_params)); - return 0; -} - -static int isif_validate_df_csc_params(const struct vpfe_isif_df_csc *df_csc) -{ - const struct vpfe_isif_color_space_conv *csc; - int err = -EINVAL; - int i; - - if (!df_csc->df_or_csc) { - /* csc configuration */ - csc = &df_csc->csc; - if (csc->en) { - for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++) - if (csc->coeff[i].integer > - ISIF_CSC_COEF_INTEG_MASK || - csc->coeff[i].decimal > - ISIF_CSC_COEF_DECIMAL_MASK) { - pr_err("Invalid CSC coefficients\n"); - return err; - } - } - } - if (df_csc->start_pix > ISIF_DF_CSC_SPH_MASK) { - pr_err("Invalid df_csc start pix value\n"); - return err; - } - - if (df_csc->num_pixels > ISIF_DF_NUMPIX) { - pr_err("Invalid df_csc num pixels value\n"); - return err; - } - - if (df_csc->start_line > ISIF_DF_CSC_LNH_MASK) { - pr_err("Invalid df_csc start_line value\n"); - return err; - } - - if (df_csc->num_lines > ISIF_DF_NUMLINES) { - pr_err("Invalid df_csc num_lines value\n"); - return err; - } - - return 0; -} - -#define DM365_ISIF_MAX_VDFLSFT 4 -#define DM365_ISIF_MAX_VDFSLV 4095 -#define DM365_ISIF_MAX_DFCMEM0 0x1fff -#define DM365_ISIF_MAX_DFCMEM1 0x1fff - -static int isif_validate_dfc_params(const struct vpfe_isif_dfc *dfc) -{ - int err = -EINVAL; - int i; - - if (!dfc->en) - return 0; - - if (dfc->corr_whole_line > 1) { - pr_err("Invalid corr_whole_line value\n"); - return err; - } - - if (dfc->def_level_shift > DM365_ISIF_MAX_VDFLSFT) { - pr_err("Invalid def_level_shift value\n"); - return err; - } - - if (dfc->def_sat_level > DM365_ISIF_MAX_VDFSLV) { - pr_err("Invalid def_sat_level value\n"); - return err; - } - - if (!dfc->num_vdefects || - dfc->num_vdefects > VPFE_ISIF_VDFC_TABLE_SIZE) { - pr_err("Invalid num_vdefects value\n"); - return err; - } - - for (i = 0; i < VPFE_ISIF_VDFC_TABLE_SIZE; i++) { - if (dfc->table[i].pos_vert > DM365_ISIF_MAX_DFCMEM0) { - pr_err("Invalid pos_vert value\n"); - return err; - } - if (dfc->table[i].pos_horz > DM365_ISIF_MAX_DFCMEM1) { - pr_err("Invalid pos_horz value\n"); - return err; - } - } - - return 0; -} - -#define DM365_ISIF_MAX_CLVRV 0xfff -#define DM365_ISIF_MAX_CLDC 0x1fff -#define DM365_ISIF_MAX_CLHSH 0x1fff -#define DM365_ISIF_MAX_CLHSV 0x1fff -#define DM365_ISIF_MAX_CLVSH 0x1fff -#define DM365_ISIF_MAX_CLVSV 0x1fff -#define DM365_ISIF_MAX_HEIGHT_BLACK_REGION 0x1fff - -static int isif_validate_bclamp_params(const struct vpfe_isif_black_clamp *bclamp) -{ - int err = -EINVAL; - - if (bclamp->dc_offset > DM365_ISIF_MAX_CLDC) { - pr_err("Invalid bclamp dc_offset value\n"); - return err; - } - if (!bclamp->en) - return 0; - if (bclamp->horz.clamp_pix_limit > 1) { - pr_err("Invalid bclamp horz clamp_pix_limit value\n"); - return err; - } - if (bclamp->horz.win_count_calc < 1 || - bclamp->horz.win_count_calc > 32) { - pr_err("Invalid bclamp horz win_count_calc value\n"); - return err; - } - if (bclamp->horz.win_start_h_calc > DM365_ISIF_MAX_CLHSH) { - pr_err("Invalid bclamp win_start_v_calc value\n"); - return err; - } - - if (bclamp->horz.win_start_v_calc > DM365_ISIF_MAX_CLHSV) { - pr_err("Invalid bclamp win_start_v_calc value\n"); - return err; - } - if (bclamp->vert.reset_clamp_val > DM365_ISIF_MAX_CLVRV) { - pr_err("Invalid bclamp reset_clamp_val value\n"); - return err; - } - if (bclamp->vert.ob_v_sz_calc > DM365_ISIF_MAX_HEIGHT_BLACK_REGION) { - pr_err("Invalid bclamp ob_v_sz_calc value\n"); - return err; - } - if (bclamp->vert.ob_start_h > DM365_ISIF_MAX_CLVSH) { - pr_err("Invalid bclamp ob_start_h value\n"); - return err; - } - if (bclamp->vert.ob_start_v > DM365_ISIF_MAX_CLVSV) { - pr_err("Invalid bclamp ob_start_h value\n"); - return err; - } - return 0; -} - -static int -isif_validate_raw_params(const struct vpfe_isif_raw_config *params) -{ - int ret; - - ret = isif_validate_df_csc_params(¶ms->df_csc); - if (ret) - return ret; - ret = isif_validate_dfc_params(¶ms->dfc); - if (ret) - return ret; - return isif_validate_bclamp_params(¶ms->bclamp); -} - -static int isif_set_params(struct v4l2_subdev *sd, const struct vpfe_isif_raw_config *params) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - int ret = -EINVAL; - - /* only raw module parameters can be set through the IOCTL */ - if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12) - return ret; - - if (!isif_validate_raw_params(params)) { - memcpy(&isif->isif_cfg.bayer.config_params, params, - sizeof(*params)); - ret = 0; - } - return ret; -} -/* - * isif_ioctl() - isif module private ioctl's - * @sd: VPFE isif V4L2 subdevice - * @cmd: ioctl command - * @arg: ioctl argument - * - * Return 0 on success or a negative error code otherwise. - */ -static long isif_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - switch (cmd) { - case VIDIOC_VPFE_ISIF_S_RAW_PARAMS: - return isif_set_params(sd, arg); - - case VIDIOC_VPFE_ISIF_G_RAW_PARAMS: - return isif_get_params(sd, arg); - - default: - return -ENOIOCTLCMD; - } -} - -static void isif_config_gain_offset(struct vpfe_isif_device *isif) -{ - struct vpfe_isif_gain_offsets_adj *gain_off_ptr = - &isif->isif_cfg.bayer.config_params.gain_offset; - void __iomem *base = isif->isif_cfg.base_addr; - u32 val; - - val = ((gain_off_ptr->gain_sdram_en & 1) << GAIN_SDRAM_EN_SHIFT) | - ((gain_off_ptr->gain_ipipe_en & 1) << GAIN_IPIPE_EN_SHIFT) | - ((gain_off_ptr->gain_h3a_en & 1) << GAIN_H3A_EN_SHIFT) | - ((gain_off_ptr->offset_sdram_en & 1) << OFST_SDRAM_EN_SHIFT) | - ((gain_off_ptr->offset_ipipe_en & 1) << OFST_IPIPE_EN_SHIFT) | - ((gain_off_ptr->offset_h3a_en & 1) << OFST_H3A_EN_SHIFT); - isif_merge(base, GAIN_OFFSET_EN_MASK, val, CGAMMAWD); - - isif_write(base, isif->isif_cfg.isif_gain_params.cr_gain, CRGAIN); - isif_write(base, isif->isif_cfg.isif_gain_params.cgr_gain, CGRGAIN); - isif_write(base, isif->isif_cfg.isif_gain_params.cgb_gain, CGBGAIN); - isif_write(base, isif->isif_cfg.isif_gain_params.cb_gain, CBGAIN); - isif_write(base, isif->isif_cfg.isif_gain_params.offset & OFFSET_MASK, - COFSTA); - -} - -static void isif_config_bclamp(struct vpfe_isif_device *isif, - struct vpfe_isif_black_clamp *bc) -{ - u32 val; - - /** - * DC Offset is always added to image data irrespective of bc enable - * status - */ - val = bc->dc_offset & ISIF_BC_DCOFFSET_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLDCOFST); - - if (!bc->en) - return; - - val = (bc->bc_mode_color & ISIF_BC_MODE_COLOR_MASK) << - ISIF_BC_MODE_COLOR_SHIFT; - - /* Enable BC and horizontal clamp calculation parameters */ - val = val | 1 | ((bc->horz.mode & ISIF_HORZ_BC_MODE_MASK) << - ISIF_HORZ_BC_MODE_SHIFT); - - isif_write(isif->isif_cfg.base_addr, val, CLAMPCFG); - - if (bc->horz.mode != VPFE_ISIF_HORZ_BC_DISABLE) { - /* - * Window count for calculation - * Base window selection - * pixel limit - * Horizontal size of window - * vertical size of the window - * Horizontal start position of the window - * Vertical start position of the window - */ - val = (bc->horz.win_count_calc & ISIF_HORZ_BC_WIN_COUNT_MASK) | - ((bc->horz.base_win_sel_calc & 1) << - ISIF_HORZ_BC_WIN_SEL_SHIFT) | - ((bc->horz.clamp_pix_limit & 1) << - ISIF_HORZ_BC_PIX_LIMIT_SHIFT) | - ((bc->horz.win_h_sz_calc & - ISIF_HORZ_BC_WIN_H_SIZE_MASK) << - ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) | - ((bc->horz.win_v_sz_calc & - ISIF_HORZ_BC_WIN_V_SIZE_MASK) << - ISIF_HORZ_BC_WIN_V_SIZE_SHIFT); - - isif_write(isif->isif_cfg.base_addr, val, CLHWIN0); - - val = bc->horz.win_start_h_calc & ISIF_HORZ_BC_WIN_START_H_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLHWIN1); - - val = bc->horz.win_start_v_calc & ISIF_HORZ_BC_WIN_START_V_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLHWIN2); - } - - /* vertical clamp calculation parameters */ - /* OB H Valid */ - val = bc->vert.ob_h_sz_calc & ISIF_VERT_BC_OB_H_SZ_MASK; - - /* Reset clamp value sel for previous line */ - val |= (bc->vert.reset_val_sel & ISIF_VERT_BC_RST_VAL_SEL_MASK) << - ISIF_VERT_BC_RST_VAL_SEL_SHIFT; - - /* Line average coefficient */ - val |= bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT; - isif_write(isif->isif_cfg.base_addr, val, CLVWIN0); - - /* Configured reset value */ - if (bc->vert.reset_val_sel == VPFE_ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL) { - val = bc->vert.reset_clamp_val & ISIF_VERT_BC_RST_VAL_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLVRV); - } - - /* Optical Black horizontal start position */ - val = bc->vert.ob_start_h & ISIF_VERT_BC_OB_START_HORZ_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLVWIN1); - - /* Optical Black vertical start position */ - val = bc->vert.ob_start_v & ISIF_VERT_BC_OB_START_VERT_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLVWIN2); - - val = bc->vert.ob_v_sz_calc & ISIF_VERT_BC_OB_VERT_SZ_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLVWIN3); - - /* Vertical start position for BC subtraction */ - val = bc->vert_start_sub & ISIF_BC_VERT_START_SUB_V_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLSV); -} - -/* This function will configure the window size to be capture in ISIF reg */ -static void -isif_setwin(struct vpfe_isif_device *isif, struct v4l2_rect *image_win, - enum isif_frmfmt frm_fmt, int ppc, int mode) -{ - int horz_nr_pixels; - int vert_nr_lines; - int horz_start; - int vert_start; - int mid_img; - - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - horz_start = image_win->left << (ppc - 1); - horz_nr_pixels = (image_win->width << (ppc - 1)) - 1; - - /* Writing the horizontal info into the registers */ - isif_write(isif->isif_cfg.base_addr, - horz_start & START_PX_HOR_MASK, SPH); - isif_write(isif->isif_cfg.base_addr, - horz_nr_pixels & NUM_PX_HOR_MASK, LNH); - vert_start = image_win->top; - - if (frm_fmt == ISIF_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - } else { - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* configure VDINT0 and VDINT1 */ - mid_img = vert_start + (image_win->height / 2); - isif_write(isif->isif_cfg.base_addr, mid_img, VDINT1); - } - - if (!mode) - isif_write(isif->isif_cfg.base_addr, 0, VDINT0); - else - isif_write(isif->isif_cfg.base_addr, vert_nr_lines, VDINT0); - isif_write(isif->isif_cfg.base_addr, - vert_start & START_VER_ONE_MASK, SLV0); - isif_write(isif->isif_cfg.base_addr, - vert_start & START_VER_TWO_MASK, SLV1); - isif_write(isif->isif_cfg.base_addr, - vert_nr_lines & NUM_LINES_VER, LNV); -} - -#define DM365_ISIF_DFCMWR_MEMORY_WRITE 1 -#define DM365_ISIF_DFCMRD_MEMORY_READ 0x2 - -static void -isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc) -{ -#define DFC_WRITE_WAIT_COUNT 1000 - u32 count = DFC_WRITE_WAIT_COUNT; - u32 val; - int i; - - if (!vdfc->en) - return; - - /* Correction mode */ - val = (vdfc->corr_mode & ISIF_VDFC_CORR_MOD_MASK) << - ISIF_VDFC_CORR_MOD_SHIFT; - - /* Correct whole line or partial */ - if (vdfc->corr_whole_line) - val |= BIT(ISIF_VDFC_CORR_WHOLE_LN_SHIFT); - - /* level shift value */ - val |= (vdfc->def_level_shift & ISIF_VDFC_LEVEL_SHFT_MASK) << - ISIF_VDFC_LEVEL_SHFT_SHIFT; - - isif_write(isif->isif_cfg.base_addr, val, DFCCTL); - - /* Defect saturation level */ - val = vdfc->def_sat_level & ISIF_VDFC_SAT_LEVEL_MASK; - isif_write(isif->isif_cfg.base_addr, val, VDFSATLV); - - isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_vert & - ISIF_VDFC_POS_MASK, DFCMEM0); - isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_horz & - ISIF_VDFC_POS_MASK, DFCMEM1); - if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL || - vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - isif_write(isif->isif_cfg.base_addr, - vdfc->table[0].level_at_pos, DFCMEM2); - isif_write(isif->isif_cfg.base_addr, - vdfc->table[0].level_up_pixels, DFCMEM3); - isif_write(isif->isif_cfg.base_addr, - vdfc->table[0].level_low_pixels, DFCMEM4); - } - - val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); - /* set DFCMARST and set DFCMWR */ - val |= BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); - val |= 1; - isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL); - - while (count && (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x01)) - count--; - - val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); - if (!count) { - pr_debug("defect table write timeout !!\n"); - return; - } - - for (i = 1; i < vdfc->num_vdefects; i++) { - isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_vert & - ISIF_VDFC_POS_MASK, DFCMEM0); - - isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_horz & - ISIF_VDFC_POS_MASK, DFCMEM1); - - if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL || - vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - isif_write(isif->isif_cfg.base_addr, - vdfc->table[i].level_at_pos, DFCMEM2); - isif_write(isif->isif_cfg.base_addr, - vdfc->table[i].level_up_pixels, DFCMEM3); - isif_write(isif->isif_cfg.base_addr, - vdfc->table[i].level_low_pixels, DFCMEM4); - } - val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); - /* clear DFCMARST and set DFCMWR */ - val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); - val |= 1; - isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL); - - count = DFC_WRITE_WAIT_COUNT; - while (count && (isif_read(isif->isif_cfg.base_addr, - DFCMEMCTL) & 0x01)) - count--; - - val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); - if (!count) { - pr_debug("defect table write timeout !!\n"); - return; - } - } - if (vdfc->num_vdefects < VPFE_ISIF_VDFC_TABLE_SIZE) { - /* Extra cycle needed */ - isif_write(isif->isif_cfg.base_addr, 0, DFCMEM0); - isif_write(isif->isif_cfg.base_addr, - DM365_ISIF_MAX_DFCMEM1, DFCMEM1); - isif_write(isif->isif_cfg.base_addr, - DM365_ISIF_DFCMWR_MEMORY_WRITE, DFCMEMCTL); - } - /* enable VDFC */ - isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT), - (1 << ISIF_VDFC_EN_SHIFT), DFCCTL); - - isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT), - (0 << ISIF_VDFC_EN_SHIFT), DFCCTL); - - isif_write(isif->isif_cfg.base_addr, 0x6, DFCMEMCTL); - for (i = 0; i < vdfc->num_vdefects; i++) { - count = DFC_WRITE_WAIT_COUNT; - while (count && - (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x2)) - count--; - val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); - if (!count) { - pr_debug("defect table write timeout !!\n"); - return; - } - isif_write(isif->isif_cfg.base_addr, - DM365_ISIF_DFCMRD_MEMORY_READ, DFCMEMCTL); - } -} - -static void -isif_config_csc(struct vpfe_isif_device *isif, struct vpfe_isif_df_csc *df_csc) -{ - u32 val1; - u32 val2; - u32 i; - - if (!df_csc->csc.en) { - isif_write(isif->isif_cfg.base_addr, 0, CSCCTL); - return; - } - /* initialize all bits to 0 */ - val1 = 0; - for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++) { - if ((i % 2) == 0) { - /* CSCM - LSB */ - val1 = ((df_csc->csc.coeff[i].integer & - ISIF_CSC_COEF_INTEG_MASK) << - ISIF_CSC_COEF_INTEG_SHIFT) | - ((df_csc->csc.coeff[i].decimal & - ISIF_CSC_COEF_DECIMAL_MASK)); - } else { - - /* CSCM - MSB */ - val2 = ((df_csc->csc.coeff[i].integer & - ISIF_CSC_COEF_INTEG_MASK) << - ISIF_CSC_COEF_INTEG_SHIFT) | - ((df_csc->csc.coeff[i].decimal & - ISIF_CSC_COEF_DECIMAL_MASK)); - val2 <<= ISIF_CSCM_MSB_SHIFT; - val2 |= val1; - isif_write(isif->isif_cfg.base_addr, val2, - (CSCM0 + ((i-1) << 1))); - } - } - /* program the active area */ - isif_write(isif->isif_cfg.base_addr, df_csc->start_pix & - ISIF_DF_CSC_SPH_MASK, FMTSPH); - /* - * one extra pixel as required for CSC. Actually number of - * pixel - 1 should be configured in this register. So we - * need to subtract 1 before writing to FMTSPH, but we will - * not do this since csc requires one extra pixel - */ - isif_write(isif->isif_cfg.base_addr, df_csc->num_pixels & - ISIF_DF_CSC_SPH_MASK, FMTLNH); - isif_write(isif->isif_cfg.base_addr, df_csc->start_line & - ISIF_DF_CSC_SPH_MASK, FMTSLV); - /* - * one extra line as required for CSC. See reason documented for - * num_pixels - */ - isif_write(isif->isif_cfg.base_addr, df_csc->num_lines & - ISIF_DF_CSC_SPH_MASK, FMTLNV); - /* Enable CSC */ - isif_write(isif->isif_cfg.base_addr, 1, CSCCTL); -} - -static void -isif_config_linearization(struct vpfe_isif_device *isif, - struct vpfe_isif_linearize *linearize) -{ - u32 val; - u32 i; - - if (!linearize->en) { - isif_write(isif->isif_cfg.base_addr, 0, LINCFG0); - return; - } - /* shift value for correction */ - val = (linearize->corr_shft & ISIF_LIN_CORRSFT_MASK) << - ISIF_LIN_CORRSFT_SHIFT; - /* enable */ - val |= 1; - isif_write(isif->isif_cfg.base_addr, val, LINCFG0); - /* Scale factor */ - val = (linearize->scale_fact.integer & 1) << - ISIF_LIN_SCALE_FACT_INTEG_SHIFT; - val |= linearize->scale_fact.decimal & ISIF_LIN_SCALE_FACT_DECIMAL_MASK; - isif_write(isif->isif_cfg.base_addr, val, LINCFG1); - - for (i = 0; i < VPFE_ISIF_LINEAR_TAB_SIZE; i++) { - val = linearize->table[i] & ISIF_LIN_ENTRY_MASK; - if (i%2) - isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 1); - else - isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 0); - } -} - -static void -isif_config_culling(struct vpfe_isif_device *isif, struct vpfe_isif_cul *cul) -{ - u32 val; - - /* Horizontal pattern */ - val = cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT; - val |= cul->hcpat_odd; - isif_write(isif->isif_cfg.base_addr, val, CULH); - /* vertical pattern */ - isif_write(isif->isif_cfg.base_addr, cul->vcpat, CULV); - /* LPF */ - isif_merge(isif->isif_cfg.base_addr, ISIF_LPF_MASK << ISIF_LPF_SHIFT, - cul->en_lpf << ISIF_LPF_SHIFT, MODESET); -} - -static int isif_get_pix_fmt(u32 mbus_code) -{ - switch (mbus_code) { - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - case MEDIA_BUS_FMT_SGRBG12_1X12: - return ISIF_PIXFMT_RAW; - - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_YUYV10_2X10: - case MEDIA_BUS_FMT_Y8_1X8: - return ISIF_PIXFMT_YCBCR_8BIT; - - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_YUYV10_1X20: - return ISIF_PIXFMT_YCBCR_16BIT; - - default: - break; - } - return -EINVAL; -} - -#define ISIF_INTERLACE_INVERSE_MODE 0x4b6d -#define ISIF_INTERLACE_NON_INVERSE_MODE 0x0b6d -#define ISIF_PROGRESSIVE_INVERSE_MODE 0x4000 -#define ISIF_PROGRESSIVE_NON_INVERSE_MODE 0x0000 - -static int isif_config_raw(struct v4l2_subdev *sd, int mode) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - struct isif_params_raw *params = &isif->isif_cfg.bayer; - struct vpfe_isif_raw_config *module_params = - &isif->isif_cfg.bayer.config_params; - struct v4l2_mbus_framefmt *format; - int pix_fmt; - u32 val; - - format = &isif->formats[ISIF_PAD_SINK]; - - /* In case of user has set BT656IF earlier, it should be reset - * when configuring for raw input. - */ - isif_write(isif->isif_cfg.base_addr, 0, REC656IF); - /* Configure CCDCFG register - * Set CCD Not to swap input since input is RAW data - * Set FID detection function to Latch at V-Sync - * Set WENLOG - isif valid area - * Set TRGSEL - * Set EXTRG - * Packed to 8 or 16 bits - */ - val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC | - ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN | - ISIF_CCDCFG_EXTRG_DISABLE | (isif->isif_cfg.data_pack & - ISIF_DATA_PACK_MASK); - isif_write(isif->isif_cfg.base_addr, val, CCDCFG); - - pix_fmt = isif_get_pix_fmt(format->code); - if (pix_fmt < 0) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - /* - * Configure the vertical sync polarity(MODESET.VDPOL) - * Configure the horizontal sync polarity (MODESET.HDPOL) - * Configure frame id polarity (MODESET.FLDPOL) - * Configure data polarity - * Configure External WEN Selection - * Configure frame format(progressive or interlace) - * Configure pixel format (Input mode) - * Configure the data shift - */ - val = ISIF_VDHDOUT_INPUT | ((params->vd_pol & ISIF_VD_POL_MASK) << - ISIF_VD_POL_SHIFT) | ((params->hd_pol & ISIF_HD_POL_MASK) << - ISIF_HD_POL_SHIFT) | ((params->fid_pol & ISIF_FID_POL_MASK) << - ISIF_FID_POL_SHIFT) | ((ISIF_DATAPOL_NORMAL & - ISIF_DATAPOL_MASK) << ISIF_DATAPOL_SHIFT) | ((ISIF_EXWEN_DISABLE & - ISIF_EXWEN_MASK) << ISIF_EXWEN_SHIFT) | ((params->frm_fmt & - ISIF_FRM_FMT_MASK) << ISIF_FRM_FMT_SHIFT) | ((pix_fmt & - ISIF_INPUT_MASK) << ISIF_INPUT_SHIFT); - - /* currently only MEDIA_BUS_FMT_SGRBG12_1X12 is - * supported. shift appropriately depending on - * different MBUS fmt's added - */ - if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12) - val |= ((VPFE_ISIF_NO_SHIFT & - ISIF_DATASFT_MASK) << ISIF_DATASFT_SHIFT); - - isif_write(isif->isif_cfg.base_addr, val, MODESET); - /* - * Configure GAMMAWD register - * CFA pattern setting - */ - val = (params->cfa_pat & ISIF_GAMMAWD_CFA_MASK) << - ISIF_GAMMAWD_CFA_SHIFT; - /* Gamma msb */ - if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10ALAW8) - val = val | ISIF_ALAW_ENABLE; - - val = val | ((params->data_msb & ISIF_ALAW_GAMA_WD_MASK) << - ISIF_ALAW_GAMA_WD_SHIFT); - - isif_write(isif->isif_cfg.base_addr, val, CGAMMAWD); - /* Configure DPCM compression settings */ - if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10DPCM8) { - val = BIT(ISIF_DPCM_EN_SHIFT); - val |= (params->dpcm_predictor & - ISIF_DPCM_PREDICTOR_MASK) << ISIF_DPCM_PREDICTOR_SHIFT; - } - isif_write(isif->isif_cfg.base_addr, val, MISC); - /* Configure Gain & Offset */ - isif_config_gain_offset(isif); - /* Configure Color pattern */ - if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12) - val = isif_sgrbg_pattern; - else - /* default set to rggb */ - val = isif_srggb_pattern; - - isif_write(isif->isif_cfg.base_addr, val, CCOLP); - - /* Configure HSIZE register */ - val = (params->horz_flip_en & ISIF_HSIZE_FLIP_MASK) << - ISIF_HSIZE_FLIP_SHIFT; - - /* calculate line offset in 32 bytes based on pack value */ - if (isif->isif_cfg.data_pack == ISIF_PACK_8BIT) - val |= ((params->win.width + 31) >> 5) & ISIF_LINEOFST_MASK; - else if (isif->isif_cfg.data_pack == ISIF_PACK_12BIT) - val |= ((((params->win.width + (params->win.width >> 2)) + - 31) >> 5) & ISIF_LINEOFST_MASK); - else - val |= (((params->win.width * 2) + 31) >> 5) & - ISIF_LINEOFST_MASK; - isif_write(isif->isif_cfg.base_addr, val, HSIZE); - /* Configure SDOFST register */ - if (params->frm_fmt == ISIF_FRMFMT_INTERLACED) { - if (params->image_invert_en) - /* For interlace inverse mode */ - isif_write(isif->isif_cfg.base_addr, - ISIF_INTERLACE_INVERSE_MODE, SDOFST); - else - /* For interlace non inverse mode */ - isif_write(isif->isif_cfg.base_addr, - ISIF_INTERLACE_NON_INVERSE_MODE, SDOFST); - } else if (params->frm_fmt == ISIF_FRMFMT_PROGRESSIVE) { - if (params->image_invert_en) - isif_write(isif->isif_cfg.base_addr, - ISIF_PROGRESSIVE_INVERSE_MODE, SDOFST); - else - /* For progessive non inverse mode */ - isif_write(isif->isif_cfg.base_addr, - ISIF_PROGRESSIVE_NON_INVERSE_MODE, SDOFST); - } - /* Configure video window */ - isif_setwin(isif, ¶ms->win, params->frm_fmt, 1, mode); - /* Configure Black Clamp */ - isif_config_bclamp(isif, &module_params->bclamp); - /* Configure Vertical Defection Pixel Correction */ - isif_config_dfc(isif, &module_params->dfc); - if (!module_params->df_csc.df_or_csc) - /* Configure Color Space Conversion */ - isif_config_csc(isif, &module_params->df_csc); - - isif_config_linearization(isif, &module_params->linearize); - /* Configure Culling */ - isif_config_culling(isif, &module_params->culling); - /* Configure Horizontal and vertical offsets(DFC,LSC,Gain) */ - val = module_params->horz_offset & ISIF_DATA_H_OFFSET_MASK; - isif_write(isif->isif_cfg.base_addr, val, DATAHOFST); - - val = module_params->vert_offset & ISIF_DATA_V_OFFSET_MASK; - isif_write(isif->isif_cfg.base_addr, val, DATAVOFST); - - return 0; -} - -#define DM365_ISIF_HSIZE_MASK 0xffffffe0 -#define DM365_ISIF_SDOFST_2_LINES 0x00000249 - -/* This function will configure ISIF for YCbCr parameters. */ -static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - struct isif_ycbcr_config *params = &isif->isif_cfg.ycbcr; - struct v4l2_mbus_framefmt *format; - int pix_fmt; - u32 modeset; - u32 ccdcfg; - - format = &isif->formats[ISIF_PAD_SINK]; - /* - * first reset the ISIF - * all registers have default values after reset - * This is important since we assume default values to be set in - * a lot of registers that we didn't touch - */ - /* start with all bits zero */ - ccdcfg = 0; - modeset = 0; - pix_fmt = isif_get_pix_fmt(format->code); - if (pix_fmt < 0) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - /* configure pixel format or input mode */ - modeset = modeset | ((pix_fmt & ISIF_INPUT_MASK) << - ISIF_INPUT_SHIFT) | ((params->frm_fmt & ISIF_FRM_FMT_MASK) << - ISIF_FRM_FMT_SHIFT) | (((params->fid_pol & - ISIF_FID_POL_MASK) << ISIF_FID_POL_SHIFT)) | - (((params->hd_pol & ISIF_HD_POL_MASK) << ISIF_HD_POL_SHIFT)) | - (((params->vd_pol & ISIF_VD_POL_MASK) << ISIF_VD_POL_SHIFT)); - /* pack the data to 8-bit CCDCCFG */ - switch (format->code) { - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - modeset |= ((VPFE_PINPOL_NEGATIVE & ISIF_VD_POL_MASK) << - ISIF_VD_POL_SHIFT); - isif_write(isif->isif_cfg.base_addr, 3, REC656IF); - ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR; - break; - - case MEDIA_BUS_FMT_YUYV10_2X10: - if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - /* setup BT.656, embedded sync */ - isif_write(isif->isif_cfg.base_addr, 3, REC656IF); - /* enable 10 bit mode in ccdcfg */ - ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR | - ISIF_BW656_ENABLE; - break; - - case MEDIA_BUS_FMT_YUYV10_1X20: - if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - isif_write(isif->isif_cfg.base_addr, 3, REC656IF); - break; - - case MEDIA_BUS_FMT_Y8_1X8: - ccdcfg |= ISIF_PACK_8BIT; - ccdcfg |= ISIF_YCINSWP_YCBCR; - if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - - case MEDIA_BUS_FMT_YUYV8_1X16: - if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - - default: - /* should never come here */ - pr_debug("Invalid interface type\n"); - return -EINVAL; - } - isif_write(isif->isif_cfg.base_addr, modeset, MODESET); - /* Set up pix order */ - ccdcfg |= (params->pix_order & ISIF_PIX_ORDER_MASK) << - ISIF_PIX_ORDER_SHIFT; - isif_write(isif->isif_cfg.base_addr, ccdcfg, CCDCFG); - /* configure video window */ - if (format->code == MEDIA_BUS_FMT_YUYV10_1X20 || - format->code == MEDIA_BUS_FMT_YUYV8_1X16) - isif_setwin(isif, ¶ms->win, params->frm_fmt, 1, mode); - else - isif_setwin(isif, ¶ms->win, params->frm_fmt, 2, mode); - - /* - * configure the horizontal line offset - * this is done by rounding up width to a multiple of 16 pixels - * and multiply by two to account for y:cb:cr 4:2:2 data - */ - isif_write(isif->isif_cfg.base_addr, - ((((params->win.width * 2) + 31) & - DM365_ISIF_HSIZE_MASK) >> 5), HSIZE); - - /* configure the memory line offset */ - if (params->frm_fmt == ISIF_FRMFMT_INTERLACED && - params->buf_type == ISIF_BUFTYPE_FLD_INTERLEAVED) - /* two fields are interleaved in memory */ - isif_write(isif->isif_cfg.base_addr, - DM365_ISIF_SDOFST_2_LINES, SDOFST); - return 0; -} - -static int isif_configure(struct v4l2_subdev *sd, int mode) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = &isif->formats[ISIF_PAD_SINK]; - - switch (format->code) { - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - case MEDIA_BUS_FMT_SGRBG12_1X12: - return isif_config_raw(sd, mode); - - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_YUYV10_2X10: - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_YUYV10_1X20: - return isif_config_ycbcr(sd, mode); - - default: - break; - } - return -EINVAL; -} - -/* - * isif_set_stream() - Enable/Disable streaming on the ISIF module - * @sd: VPFE ISIF V4L2 subdevice - * @enable: Enable/disable stream - */ -static int isif_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - int ret; - - if (enable) { - ret = isif_configure(sd, - (isif->output == ISIF_OUTPUT_MEMORY) ? 0 : 1); - if (ret) - return ret; - if (isif->output == ISIF_OUTPUT_MEMORY) - isif_enable_output_to_sdram(isif, 1); - isif_enable(isif, 1); - } else { - isif_enable(isif, 0); - isif_enable_output_to_sdram(isif, 0); - } - - return 0; -} - -/* - * __isif_get_format() - helper function for getting isif format - * @isif: pointer to isif private structure. - * @pad: pad number. - * @cfg: V4L2 subdev pad config - * @which: wanted subdev format. - */ -static struct v4l2_mbus_framefmt * -__isif_get_format(struct vpfe_isif_device *isif, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&isif->subdev, cfg, pad); - - return &isif->formats[pad]; -} - -/* - * isif_set_format() - set format on pad - * @sd : VPFE ISIF device - * @cfg : V4L2 subdev pad config - * @fmt : pointer to v4l2 subdev format structure - * - * Return 0 on success or -EINVAL if format or pad is invalid - */ -static int -isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe_dev = to_vpfe_device(isif); - struct v4l2_mbus_framefmt *format; - - format = __isif_get_format(isif, cfg, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - isif_try_format(isif, cfg, fmt); - memcpy(format, &fmt->format, sizeof(*format)); - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - return 0; - - if (fmt->pad == ISIF_PAD_SOURCE) - return isif_config_format(vpfe_dev, fmt->pad); - - return 0; -} - -/* - * isif_get_format() - Retrieve the video format on a pad - * @sd: VPFE ISIF V4L2 subdevice - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * - * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond - * to the format type. - */ -static int -isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __isif_get_format(vpfe_isif, cfg, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - memcpy(&fmt->format, format, sizeof(fmt->format)); - - return 0; -} - -/* - * isif_enum_frame_size() - enum frame sizes on pads - * @sd: VPFE isif V4L2 subdevice - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_frame_size_enum structure - */ -static int -isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - struct v4l2_subdev_format format; - - if (fse->index != 0) - return -EINVAL; - - format.pad = fse->pad; - format.format.code = fse->code; - format.format.width = 1; - format.format.height = 1; - format.which = fse->which; - isif_try_format(isif, cfg, &format); - fse->min_width = format.format.width; - fse->min_height = format.format.height; - - if (format.format.code != fse->code) - return -EINVAL; - - format.pad = fse->pad; - format.format.code = fse->code; - format.format.width = -1; - format.format.height = -1; - format.which = fse->which; - isif_try_format(isif, cfg, &format); - fse->max_width = format.format.width; - fse->max_height = format.format.height; - - return 0; -} - -/* - * isif_enum_mbus_code() - enum mbus codes for pads - * @sd: VPFE isif V4L2 subdevice - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - */ -static int -isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - switch (code->pad) { - case ISIF_PAD_SINK: - case ISIF_PAD_SOURCE: - if (code->index >= ARRAY_SIZE(isif_fmts)) - return -EINVAL; - code->code = isif_fmts[code->index]; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * isif_pad_set_selection() - set crop rectangle on pad - * @sd: VPFE isif V4L2 subdevice - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - * - * Return 0 on success, -EINVAL if pad is invalid - */ -static int -isif_pad_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - /* check whether it's a valid pad and target */ - if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - format = __isif_get_format(vpfe_isif, cfg, sel->pad, sel->which); - if (format == NULL) - return -EINVAL; - - /* check wether crop rect is within limits */ - if (sel->r.top < 0 || sel->r.left < 0 || - (sel->r.left + sel->r.width > - vpfe_isif->formats[ISIF_PAD_SINK].width) || - (sel->r.top + sel->r.height > - vpfe_isif->formats[ISIF_PAD_SINK].height)) { - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = format->width; - sel->r.height = format->height; - } - /* adjust the width to 16 pixel boundary */ - sel->r.width = (sel->r.width + 15) & ~0xf; - vpfe_isif->crop = sel->r; - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - isif_set_image_window(vpfe_isif); - } else { - struct v4l2_rect *rect; - - rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK); - memcpy(rect, &vpfe_isif->crop, sizeof(*rect)); - } - return 0; -} - -/* - * isif_pad_get_selection() - get crop rectangle on pad - * @sd: VPFE isif V4L2 subdevice - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - * - * Return 0 on success, -EINVAL if pad is invalid - */ -static int -isif_pad_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); - - /* check whether it's a valid pad and target */ - if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_rect *rect; - - rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK); - memcpy(&sel->r, rect, sizeof(*rect)); - } else { - sel->r = vpfe_isif->crop; - } - - return 0; -} - -/* - * isif_init_formats() - Initialize formats on all pads - * @sd: VPFE isif V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. Try formats are initialized - * on the file handle. - */ -static int -isif_init_formats(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - struct v4l2_subdev_selection sel; - - memset(&format, 0, sizeof(format)); - format.pad = ISIF_PAD_SINK; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; - format.format.width = MAX_WIDTH; - format.format.height = MAX_HEIGHT; - isif_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = ISIF_PAD_SOURCE; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; - format.format.width = MAX_WIDTH; - format.format.height = MAX_HEIGHT; - isif_set_format(sd, fh->pad, &format); - - memset(&sel, 0, sizeof(sel)); - sel.pad = ISIF_PAD_SINK; - sel.which = V4L2_SUBDEV_FORMAT_TRY; - sel.target = V4L2_SEL_TGT_CROP; - sel.r.width = MAX_WIDTH; - sel.r.height = MAX_HEIGHT; - isif_pad_set_selection(sd, fh->pad, &sel); - - return 0; -} - -/* subdev core operations */ -static const struct v4l2_subdev_core_ops isif_v4l2_core_ops = { - .ioctl = isif_ioctl, -}; - -/* subdev file operations */ -static const struct v4l2_subdev_internal_ops isif_v4l2_internal_ops = { - .open = isif_init_formats, -}; - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops isif_v4l2_video_ops = { - .s_stream = isif_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops isif_v4l2_pad_ops = { - .enum_mbus_code = isif_enum_mbus_code, - .enum_frame_size = isif_enum_frame_size, - .get_fmt = isif_get_format, - .set_fmt = isif_set_format, - .set_selection = isif_pad_set_selection, - .get_selection = isif_pad_get_selection, -}; - -/* subdev operations */ -static const struct v4l2_subdev_ops isif_v4l2_ops = { - .core = &isif_v4l2_core_ops, - .video = &isif_v4l2_video_ops, - .pad = &isif_v4l2_pad_ops, -}; - -/* - * Media entity operations - */ - -/* - * isif_link_setup() - Setup isif connections - * @entity: isif media entity - * @local: Pad at the local end of the link - * @remote: Pad at the remote end of the link - * @flags: Link flags - * - * return -EINVAL or zero on success - */ -static int -isif_link_setup(struct media_entity *entity, const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - unsigned int index = local->index; - - /* FIXME: this is actually a hack! */ - if (is_media_entity_v4l2_subdev(remote->entity)) - index |= 2 << 16; - - switch (index) { - case ISIF_PAD_SINK | 2 << 16: - /* read from decoder/sensor */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - isif->input = ISIF_INPUT_NONE; - break; - } - if (isif->input != ISIF_INPUT_NONE) - return -EBUSY; - isif->input = ISIF_INPUT_PARALLEL; - break; - - case ISIF_PAD_SOURCE: - /* write to memory */ - if (flags & MEDIA_LNK_FL_ENABLED) - isif->output = ISIF_OUTPUT_MEMORY; - else - isif->output = ISIF_OUTPUT_NONE; - break; - - case ISIF_PAD_SOURCE | 2 << 16: - if (flags & MEDIA_LNK_FL_ENABLED) - isif->output = ISIF_OUTPUT_IPIPEIF; - else - isif->output = ISIF_OUTPUT_NONE; - break; - - default: - return -EINVAL; - } - - return 0; -} -static const struct media_entity_operations isif_media_ops = { - .link_setup = isif_link_setup, -}; - -/* - * vpfe_isif_unregister_entities() - isif unregister entity - * @isif - pointer to isif subdevice structure. - */ -void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif) -{ - vpfe_video_unregister(&isif->video_out); - /* unregister subdev */ - v4l2_device_unregister_subdev(&isif->subdev); - /* cleanup entity */ - media_entity_cleanup(&isif->subdev.entity); -} - -static void isif_restore_defaults(struct vpfe_isif_device *isif) -{ - enum vpss_ccdc_source_sel source = VPSS_CCDCIN; - int i; - - memset(&isif->isif_cfg.bayer.config_params, 0, - sizeof(struct vpfe_isif_raw_config)); - - isif->isif_cfg.bayer.config_params.linearize.corr_shft = - VPFE_ISIF_NO_SHIFT; - isif->isif_cfg.bayer.config_params.linearize.scale_fact.integer = 1; - isif->isif_cfg.bayer.config_params.culling.hcpat_odd = - ISIF_CULLING_HCAPT_ODD; - isif->isif_cfg.bayer.config_params.culling.hcpat_even = - ISIF_CULLING_HCAPT_EVEN; - isif->isif_cfg.bayer.config_params.culling.vcpat = ISIF_CULLING_VCAPT; - /* Enable clock to ISIF, IPIPEIF and BL */ - vpss_enable_clock(VPSS_CCDC_CLOCK, 1); - vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); - vpss_enable_clock(VPSS_BL_CLOCK, 1); - - /* set all registers to default value */ - for (i = 0; i <= 0x1f8; i += 4) - isif_write(isif->isif_cfg.base_addr, 0, i); - /* no culling support */ - isif_write(isif->isif_cfg.base_addr, 0xffff, CULH); - isif_write(isif->isif_cfg.base_addr, 0xff, CULV); - - /* Set default offset and gain */ - isif_config_gain_offset(isif); - vpss_select_ccdc_source(source); -} - -/* - * vpfe_isif_register_entities() - isif register entity - * @isif - pointer to isif subdevice structure. - * @vdev: pointer to v4l2 device structure. - */ -int vpfe_isif_register_entities(struct vpfe_isif_device *isif, - struct v4l2_device *vdev) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(isif); - unsigned int flags; - int ret; - - /* Register the subdev */ - ret = v4l2_device_register_subdev(vdev, &isif->subdev); - if (ret < 0) - return ret; - - isif_restore_defaults(isif); - ret = vpfe_video_register(&isif->video_out, vdev); - if (ret) { - pr_err("Failed to register isif video out device\n"); - goto out_video_register; - } - isif->video_out.vpfe_dev = vpfe_dev; - flags = 0; - /* connect isif to video node */ - ret = media_create_pad_link(&isif->subdev.entity, 1, - &isif->video_out.video_dev.entity, - 0, flags); - if (ret < 0) - goto out_create_link; - return 0; -out_create_link: - vpfe_video_unregister(&isif->video_out); -out_video_register: - v4l2_device_unregister_subdev(&isif->subdev); - return ret; -} - -/* ------------------------------------------------------------------- - * V4L2 subdev control operations - */ - -static int vpfe_isif_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vpfe_isif_device *isif = - container_of(ctrl->handler, struct vpfe_isif_device, ctrls); - struct isif_oper_config *config = &isif->isif_cfg; - - switch (ctrl->id) { - case VPFE_CID_DPCM_PREDICTOR: - config->bayer.dpcm_predictor = ctrl->val; - break; - - case VPFE_ISIF_CID_CRGAIN: - config->isif_gain_params.cr_gain = ctrl->val; - break; - - case VPFE_ISIF_CID_CGRGAIN: - config->isif_gain_params.cgr_gain = ctrl->val; - break; - - case VPFE_ISIF_CID_CGBGAIN: - config->isif_gain_params.cgb_gain = ctrl->val; - break; - - case VPFE_ISIF_CID_CBGAIN: - config->isif_gain_params.cb_gain = ctrl->val; - break; - - case VPFE_ISIF_CID_GAIN_OFFSET: - config->isif_gain_params.offset = ctrl->val; - break; - - default: - return -EINVAL; - } - return 0; -} - -static const struct v4l2_ctrl_ops vpfe_isif_ctrl_ops = { - .s_ctrl = vpfe_isif_s_ctrl, -}; - -static const struct v4l2_ctrl_config vpfe_isif_dpcm_pred = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_CID_DPCM_PREDICTOR, - .name = "DPCM Predictor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 1, - .step = 1, - .def = 0, -}; - -static const struct v4l2_ctrl_config vpfe_isif_crgain = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_ISIF_CID_CRGAIN, - .name = "CRGAIN", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = (1 << 12) - 1, - .step = 1, - .def = 0, -}; - -static const struct v4l2_ctrl_config vpfe_isif_cgrgain = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_ISIF_CID_CGRGAIN, - .name = "CGRGAIN", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = (1 << 12) - 1, - .step = 1, - .def = 0, -}; - -static const struct v4l2_ctrl_config vpfe_isif_cgbgain = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_ISIF_CID_CGBGAIN, - .name = "CGBGAIN", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = (1 << 12) - 1, - .step = 1, - .def = 0, -}; - -static const struct v4l2_ctrl_config vpfe_isif_cbgain = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_ISIF_CID_CBGAIN, - .name = "CBGAIN", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = (1 << 12) - 1, - .step = 1, - .def = 0, -}; - -static const struct v4l2_ctrl_config vpfe_isif_gain_offset = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_ISIF_CID_GAIN_OFFSET, - .name = "Gain Offset", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = (1 << 12) - 1, - .step = 1, - .def = 0, -}; - -static void isif_remove(struct vpfe_isif_device *isif, - struct platform_device *pdev) -{ - struct resource *res; - int i = 0; - - iounmap(isif->isif_cfg.base_addr); - iounmap(isif->isif_cfg.linear_tbl0_addr); - iounmap(isif->isif_cfg.linear_tbl1_addr); - - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (res) - release_mem_region(res->start, - resource_size(res)); - i++; - } -} - -static void isif_config_defaults(struct vpfe_isif_device *isif) -{ - isif->isif_cfg.ycbcr.v4l2_pix_fmt = V4L2_PIX_FMT_UYVY; - isif->isif_cfg.ycbcr.pix_fmt = ISIF_PIXFMT_YCBCR_8BIT; - isif->isif_cfg.ycbcr.frm_fmt = ISIF_FRMFMT_INTERLACED; - isif->isif_cfg.ycbcr.fid_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.ycbcr.vd_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.ycbcr.hd_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY; - isif->isif_cfg.ycbcr.buf_type = ISIF_BUFTYPE_FLD_INTERLEAVED; - - isif->isif_cfg.bayer.v4l2_pix_fmt = V4L2_PIX_FMT_SGRBG10ALAW8; - isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW; - isif->isif_cfg.bayer.frm_fmt = ISIF_FRMFMT_PROGRESSIVE; - isif->isif_cfg.bayer.fid_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.bayer.vd_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.bayer.hd_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.bayer.cfa_pat = ISIF_CFA_PAT_MOSAIC; - isif->isif_cfg.bayer.data_msb = ISIF_BIT_MSB_11; - isif->isif_cfg.data_pack = ISIF_PACK_8BIT; -} -/* - * vpfe_isif_init() - Initialize V4L2 subdev and media entity - * @isif: VPFE isif module - * @pdev: Pointer to platform device structure. - * Return 0 on success and a negative error code on failure. - */ -int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev) -{ - struct v4l2_subdev *sd = &isif->subdev; - struct media_pad *pads = &isif->pads[0]; - struct media_entity *me = &sd->entity; - static resource_size_t res_len; - struct resource *res; - void __iomem *addr; - int status; - int i = 0; - - /* Get the ISIF base address, linearization table0 and table1 addr. */ - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (!res) { - status = -ENOENT; - goto fail_nobase_res; - } - res_len = resource_size(res); - res = request_mem_region(res->start, res_len, res->name); - if (!res) { - status = -EBUSY; - goto fail_nobase_res; - } - addr = ioremap_nocache(res->start, res_len); - if (!addr) { - status = -EBUSY; - goto fail_base_iomap; - } - switch (i) { - case 0: - /* ISIF base address */ - isif->isif_cfg.base_addr = addr; - break; - case 1: - /* ISIF linear tbl0 address */ - isif->isif_cfg.linear_tbl0_addr = addr; - break; - default: - /* ISIF linear tbl0 address */ - isif->isif_cfg.linear_tbl1_addr = addr; - break; - } - i++; - } - davinci_cfg_reg(DM365_VIN_CAM_WEN); - davinci_cfg_reg(DM365_VIN_CAM_VD); - davinci_cfg_reg(DM365_VIN_CAM_HD); - davinci_cfg_reg(DM365_VIN_YIN4_7_EN); - davinci_cfg_reg(DM365_VIN_YIN0_3_EN); - - /* queue ops */ - isif->video_out.ops = &isif_video_ops; - v4l2_subdev_init(sd, &isif_v4l2_ops); - sd->internal_ops = &isif_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI ISIF", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - v4l2_set_subdevdata(sd, isif); - sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; - pads[ISIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[ISIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - isif->input = ISIF_INPUT_NONE; - isif->output = ISIF_OUTPUT_NONE; - me->ops = &isif_media_ops; - status = media_entity_pads_init(me, ISIF_PADS_NUM, pads); - if (status) - goto isif_fail; - isif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - status = vpfe_video_init(&isif->video_out, "ISIF"); - if (status) { - pr_err("Failed to init isif-out video device\n"); - goto isif_fail; - } - v4l2_ctrl_handler_init(&isif->ctrls, 6); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_crgain, NULL); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgrgain, NULL); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgbgain, NULL); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cbgain, NULL); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_gain_offset, NULL); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_dpcm_pred, NULL); - - v4l2_ctrl_handler_setup(&isif->ctrls); - sd->ctrl_handler = &isif->ctrls; - isif_config_defaults(isif); - return 0; -fail_base_iomap: - release_mem_region(res->start, res_len); - i--; -fail_nobase_res: - if (isif->isif_cfg.base_addr) - iounmap(isif->isif_cfg.base_addr); - if (isif->isif_cfg.linear_tbl0_addr) - iounmap(isif->isif_cfg.linear_tbl0_addr); - - while (i >= 0) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - release_mem_region(res->start, res_len); - i--; - } - return status; -isif_fail: - v4l2_ctrl_handler_free(&isif->ctrls); - isif_remove(isif, pdev); - return status; -} - -/* - * vpfe_isif_cleanup - isif module cleanup - * @isif: pointer to isif subdevice - * @dev: pointer to platform device structure - */ -void -vpfe_isif_cleanup(struct vpfe_isif_device *isif, struct platform_device *pdev) -{ - isif_remove(isif, pdev); -} diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.h b/drivers/staging/media/davinci_vpfe/dm365_isif.h deleted file mode 100644 index 0e1fe472fb2b..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.h +++ /dev/null @@ -1,200 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#ifndef _DAVINCI_VPFE_DM365_ISIF_H -#define _DAVINCI_VPFE_DM365_ISIF_H - -#include <linux/platform_device.h> - -#include <mach/mux.h> - -#include <media/davinci/vpfe_types.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-device.h> - -#include "davinci_vpfe_user.h" -#include "dm365_isif_regs.h" -#include "vpfe_video.h" - -#define ISIF_CULLING_HCAPT_ODD 0xff -#define ISIF_CULLING_HCAPT_EVEN 0xff -#define ISIF_CULLING_VCAPT 0xff - -#define ISIF_CADU_BITS 0x07ff -#define ISIF_CADL_BITS 0x0ffff - -enum isif_pixfmt { - ISIF_PIXFMT_RAW = 0, - ISIF_PIXFMT_YCBCR_16BIT = 1, - ISIF_PIXFMT_YCBCR_8BIT = 2, -}; - -enum isif_frmfmt { - ISIF_FRMFMT_PROGRESSIVE = 0, - ISIF_FRMFMT_INTERLACED = 1, -}; - -/* PIXEL ORDER IN MEMORY from LSB to MSB */ -/* only applicable for 8-bit input mode */ -enum isif_pixorder { - ISIF_PIXORDER_YCBYCR = 0, - ISIF_PIXORDER_CBYCRY = 1, -}; - -enum isif_buftype { - ISIF_BUFTYPE_FLD_INTERLEAVED = 0, - ISIF_BUFTYPE_FLD_SEPARATED = 1, -}; - -struct isif_ycbcr_config { - /* v4l2 pixel format */ - unsigned long v4l2_pix_fmt; - /* isif pixel format */ - enum isif_pixfmt pix_fmt; - /* isif frame format */ - enum isif_frmfmt frm_fmt; - /* isif crop window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* isif pix order. Only used for ycbcr capture */ - enum isif_pixorder pix_order; - /* isif buffer type. Only used for ycbcr capture */ - enum isif_buftype buf_type; -}; - -enum isif_cfa_pattern { - ISIF_CFA_PAT_MOSAIC = 0, - ISIF_CFA_PAT_STRIPE = 1, -}; - -enum isif_data_msb { - /* MSB b15 */ - ISIF_BIT_MSB_15 = 0, - /* MSB b14 */ - ISIF_BIT_MSB_14 = 1, - /* MSB b13 */ - ISIF_BIT_MSB_13 = 2, - /* MSB b12 */ - ISIF_BIT_MSB_12 = 3, - /* MSB b11 */ - ISIF_BIT_MSB_11 = 4, - /* MSB b10 */ - ISIF_BIT_MSB_10 = 5, - /* MSB b9 */ - ISIF_BIT_MSB_9 = 6, - /* MSB b8 */ - ISIF_BIT_MSB_8 = 7, - /* MSB b7 */ - ISIF_BIT_MSB_7 = 8, -}; - -struct isif_params_raw { - /* v4l2 pixel format */ - unsigned long v4l2_pix_fmt; - /* isif pixel format */ - enum isif_pixfmt pix_fmt; - /* isif frame format */ - enum isif_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* buffer type. Applicable for interlaced mode */ - enum isif_buftype buf_type; - /* cfa pattern */ - enum isif_cfa_pattern cfa_pat; - /* Data MSB position */ - enum isif_data_msb data_msb; - /* Enable horizontal flip */ - unsigned char horz_flip_en; - /* Enable image invert vertically */ - unsigned char image_invert_en; - unsigned char dpcm_predictor; - struct vpfe_isif_raw_config config_params; -}; - -enum isif_data_pack { - ISIF_PACK_16BIT = 0, - ISIF_PACK_12BIT = 1, - ISIF_PACK_8BIT = 2, -}; - -struct isif_gain_values { - unsigned int cr_gain; - unsigned int cgr_gain; - unsigned int cgb_gain; - unsigned int cb_gain; - unsigned int offset; -}; - -struct isif_oper_config { - struct isif_ycbcr_config ycbcr; - struct isif_params_raw bayer; - enum isif_data_pack data_pack; - struct isif_gain_values isif_gain_params; - void __iomem *base_addr; - void __iomem *linear_tbl0_addr; - void __iomem *linear_tbl1_addr; -}; - -#define ISIF_PAD_SINK 0 -#define ISIF_PAD_SOURCE 1 - -#define ISIF_PADS_NUM 2 - -enum isif_input_entity { - ISIF_INPUT_NONE = 0, - ISIF_INPUT_PARALLEL = 1, -}; - -#define ISIF_OUTPUT_NONE (0) -#define ISIF_OUTPUT_MEMORY (1 << 0) -#define ISIF_OUTPUT_IPIPEIF (1 << 1) - -struct vpfe_isif_device { - struct v4l2_subdev subdev; - struct media_pad pads[ISIF_PADS_NUM]; - struct v4l2_mbus_framefmt formats[ISIF_PADS_NUM]; - enum isif_input_entity input; - unsigned int output; - struct v4l2_ctrl_handler ctrls; - struct v4l2_rect crop; - struct isif_oper_config isif_cfg; - struct vpfe_video_device video_out; -}; - -enum v4l2_field vpfe_isif_get_fid(struct vpfe_device *vpfe_dev); -void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif); -int vpfe_isif_register_entities(struct vpfe_isif_device *isif, - struct v4l2_device *dev); -int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev); -void vpfe_isif_cleanup(struct vpfe_isif_device *vpfe_isif, - struct platform_device *pdev); -void vpfe_isif_vidint1_isr(struct vpfe_isif_device *isif); -void vpfe_isif_buffer_isr(struct vpfe_isif_device *isif); - -#endif /* _DAVINCI_VPFE_DM365_ISIF_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif_regs.h b/drivers/staging/media/davinci_vpfe/dm365_isif_regs.h deleted file mode 100644 index 6695680817b9..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_isif_regs.h +++ /dev/null @@ -1,291 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#ifndef _DAVINCI_VPFE_DM365_ISIF_REGS_H -#define _DAVINCI_VPFE_DM365_ISIF_REGS_H - -/* ISIF registers relative offsets */ -#define SYNCEN 0x00 -#define MODESET 0x04 -#define HDW 0x08 -#define VDW 0x0c -#define PPLN 0x10 -#define LPFR 0x14 -#define SPH 0x18 -#define LNH 0x1c -#define SLV0 0x20 -#define SLV1 0x24 -#define LNV 0x28 -#define CULH 0x2c -#define CULV 0x30 -#define HSIZE 0x34 -#define SDOFST 0x38 -#define CADU 0x3c -#define CADL 0x40 -#define LINCFG0 0x44 -#define LINCFG1 0x48 -#define CCOLP 0x4c -#define CRGAIN 0x50 -#define CGRGAIN 0x54 -#define CGBGAIN 0x58 -#define CBGAIN 0x5c -#define COFSTA 0x60 -#define FLSHCFG0 0x64 -#define FLSHCFG1 0x68 -#define FLSHCFG2 0x6c -#define VDINT0 0x70 -#define VDINT1 0x74 -#define VDINT2 0x78 -#define MISC 0x7c -#define CGAMMAWD 0x80 -#define REC656IF 0x84 -#define CCDCFG 0x88 -/***************************************************** - * Defect Correction registers - *****************************************************/ -#define DFCCTL 0x8c -#define VDFSATLV 0x90 -#define DFCMEMCTL 0x94 -#define DFCMEM0 0x98 -#define DFCMEM1 0x9c -#define DFCMEM2 0xa0 -#define DFCMEM3 0xa4 -#define DFCMEM4 0xa8 -/**************************************************** - * Black Clamp registers - ****************************************************/ -#define CLAMPCFG 0xac -#define CLDCOFST 0xb0 -#define CLSV 0xb4 -#define CLHWIN0 0xb8 -#define CLHWIN1 0xbc -#define CLHWIN2 0xc0 -#define CLVRV 0xc4 -#define CLVWIN0 0xc8 -#define CLVWIN1 0xcc -#define CLVWIN2 0xd0 -#define CLVWIN3 0xd4 -/**************************************************** - * Lense Shading Correction - ****************************************************/ -#define DATAHOFST 0xd8 -#define DATAVOFST 0xdc -#define LSCHVAL 0xe0 -#define LSCVVAL 0xe4 -#define TWODLSCCFG 0xe8 -#define TWODLSCOFST 0xec -#define TWODLSCINI 0xf0 -#define TWODLSCGRBU 0xf4 -#define TWODLSCGRBL 0xf8 -#define TWODLSCGROF 0xfc -#define TWODLSCORBU 0x100 -#define TWODLSCORBL 0x104 -#define TWODLSCOROF 0x108 -#define TWODLSCIRQEN 0x10c -#define TWODLSCIRQST 0x110 -/**************************************************** - * Data formatter - ****************************************************/ -#define FMTCFG 0x114 -#define FMTPLEN 0x118 -#define FMTSPH 0x11c -#define FMTLNH 0x120 -#define FMTSLV 0x124 -#define FMTLNV 0x128 -#define FMTRLEN 0x12c -#define FMTHCNT 0x130 -#define FMTAPTR_BASE 0x134 -/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */ -#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4)) -#define FMTPGMVF0 0x174 -#define FMTPGMVF1 0x178 -#define FMTPGMAPU0 0x17c -#define FMTPGMAPU1 0x180 -#define FMTPGMAPS0 0x184 -#define FMTPGMAPS1 0x188 -#define FMTPGMAPS2 0x18c -#define FMTPGMAPS3 0x190 -#define FMTPGMAPS4 0x194 -#define FMTPGMAPS5 0x198 -#define FMTPGMAPS6 0x19c -#define FMTPGMAPS7 0x1a0 -/************************************************ - * Color Space Converter - ************************************************/ -#define CSCCTL 0x1a4 -#define CSCM0 0x1a8 -#define CSCM1 0x1ac -#define CSCM2 0x1b0 -#define CSCM3 0x1b4 -#define CSCM4 0x1b8 -#define CSCM5 0x1bc -#define CSCM6 0x1c0 -#define CSCM7 0x1c4 -#define OBWIN0 0x1c8 -#define OBWIN1 0x1cc -#define OBWIN2 0x1d0 -#define OBWIN3 0x1d4 -#define OBVAL0 0x1d8 -#define OBVAL1 0x1dc -#define OBVAL2 0x1e0 -#define OBVAL3 0x1e4 -#define OBVAL4 0x1e8 -#define OBVAL5 0x1ec -#define OBVAL6 0x1f0 -#define OBVAL7 0x1f4 -#define CLKCTL 0x1f8 - -/* Masks & Shifts below */ -#define START_PX_HOR_MASK 0x7fff -#define NUM_PX_HOR_MASK 0x7fff -#define START_VER_ONE_MASK 0x7fff -#define START_VER_TWO_MASK 0x7fff -#define NUM_LINES_VER 0x7fff - -/* gain - offset masks */ -#define OFFSET_MASK 0xfff -#define GAIN_SDRAM_EN_SHIFT 12 -#define GAIN_IPIPE_EN_SHIFT 13 -#define GAIN_H3A_EN_SHIFT 14 -#define OFST_SDRAM_EN_SHIFT 8 -#define OFST_IPIPE_EN_SHIFT 9 -#define OFST_H3A_EN_SHIFT 10 -#define GAIN_OFFSET_EN_MASK 0x7700 - -/* Culling */ -#define CULL_PAT_EVEN_LINE_SHIFT 8 - -/* CCDCFG register */ -#define ISIF_YCINSWP_RAW (0x00 << 4) -#define ISIF_YCINSWP_YCBCR (0x01 << 4) -#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6) -#define ISIF_CCDCFG_WENLOG_AND (0x00 << 8) -#define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9) -#define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10) -#define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15) -#define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15) -#define ISIF_DATA_PACK_MASK 0x03 -#define ISIF_PIX_ORDER_SHIFT 11 -#define ISIF_PIX_ORDER_MASK 0x01 -#define ISIF_BW656_ENABLE (0x01 << 5) - -/* MODESET registers */ -#define ISIF_VDHDOUT_INPUT (0x00 << 0) -#define ISIF_INPUT_MASK 0x03 -#define ISIF_INPUT_SHIFT 12 -#define ISIF_FID_POL_MASK 0x01 -#define ISIF_FID_POL_SHIFT 4 -#define ISIF_HD_POL_MASK 0x01 -#define ISIF_HD_POL_SHIFT 3 -#define ISIF_VD_POL_MASK 0x01 -#define ISIF_VD_POL_SHIFT 2 -#define ISIF_DATAPOL_NORMAL 0x00 -#define ISIF_DATAPOL_MASK 0x01 -#define ISIF_DATAPOL_SHIFT 6 -#define ISIF_EXWEN_DISABLE 0x00 -#define ISIF_EXWEN_MASK 0x01 -#define ISIF_EXWEN_SHIFT 5 -#define ISIF_FRM_FMT_MASK 0x01 -#define ISIF_FRM_FMT_SHIFT 7 -#define ISIF_DATASFT_MASK 0x07 -#define ISIF_DATASFT_SHIFT 8 -#define ISIF_LPF_SHIFT 14 -#define ISIF_LPF_MASK 0x1 - -/* GAMMAWD registers */ -#define ISIF_ALAW_GAMA_WD_MASK 0xf -#define ISIF_ALAW_GAMA_WD_SHIFT 1 -#define ISIF_ALAW_ENABLE 0x01 -#define ISIF_GAMMAWD_CFA_MASK 0x01 -#define ISIF_GAMMAWD_CFA_SHIFT 5 - -/* HSIZE registers */ -#define ISIF_HSIZE_FLIP_MASK 0x01 -#define ISIF_HSIZE_FLIP_SHIFT 12 -#define ISIF_LINEOFST_MASK 0xfff - -/* MISC registers */ -#define ISIF_DPCM_EN_SHIFT 12 -#define ISIF_DPCM_PREDICTOR_SHIFT 13 -#define ISIF_DPCM_PREDICTOR_MASK 1 - -/* Black clamp related */ -#define ISIF_BC_DCOFFSET_MASK 0x1fff -#define ISIF_BC_MODE_COLOR_MASK 1 -#define ISIF_BC_MODE_COLOR_SHIFT 4 -#define ISIF_HORZ_BC_MODE_MASK 3 -#define ISIF_HORZ_BC_MODE_SHIFT 1 -#define ISIF_HORZ_BC_WIN_COUNT_MASK 0x1f -#define ISIF_HORZ_BC_WIN_SEL_SHIFT 5 -#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6 -#define ISIF_HORZ_BC_WIN_H_SIZE_MASK 3 -#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8 -#define ISIF_HORZ_BC_WIN_V_SIZE_MASK 3 -#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12 -#define ISIF_HORZ_BC_WIN_START_H_MASK 0x1fff -#define ISIF_HORZ_BC_WIN_START_V_MASK 0x1fff -#define ISIF_VERT_BC_OB_H_SZ_MASK 7 -#define ISIF_VERT_BC_RST_VAL_SEL_MASK 3 -#define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4 -#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8 -#define ISIF_VERT_BC_OB_START_HORZ_MASK 0x1fff -#define ISIF_VERT_BC_OB_START_VERT_MASK 0x1fff -#define ISIF_VERT_BC_OB_VERT_SZ_MASK 0x1fff -#define ISIF_VERT_BC_RST_VAL_MASK 0xfff -#define ISIF_BC_VERT_START_SUB_V_MASK 0x1fff - -/* VDFC registers */ -#define ISIF_VDFC_EN_SHIFT 4 -#define ISIF_VDFC_CORR_MOD_MASK 3 -#define ISIF_VDFC_CORR_MOD_SHIFT 5 -#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7 -#define ISIF_VDFC_LEVEL_SHFT_MASK 7 -#define ISIF_VDFC_LEVEL_SHFT_SHIFT 8 -#define ISIF_VDFC_SAT_LEVEL_MASK 0xfff -#define ISIF_VDFC_POS_MASK 0x1fff -#define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2 - -/* CSC registers */ -#define ISIF_CSC_COEF_INTEG_MASK 7 -#define ISIF_CSC_COEF_DECIMAL_MASK 0x1f -#define ISIF_CSC_COEF_INTEG_SHIFT 5 -#define ISIF_CSCM_MSB_SHIFT 8 -#define ISIF_DF_CSC_SPH_MASK 0x1fff -#define ISIF_DF_CSC_LNH_MASK 0x1fff -#define ISIF_DF_CSC_SLV_MASK 0x1fff -#define ISIF_DF_CSC_LNV_MASK 0x1fff -#define ISIF_DF_NUMLINES 0x7fff -#define ISIF_DF_NUMPIX 0x1fff - -/* Offsets for LSC/DFC/Gain */ -#define ISIF_DATA_H_OFFSET_MASK 0x1fff -#define ISIF_DATA_V_OFFSET_MASK 0x1fff - -/* Linearization */ -#define ISIF_LIN_CORRSFT_MASK 7 -#define ISIF_LIN_CORRSFT_SHIFT 4 -#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10 -#define ISIF_LIN_SCALE_FACT_DECIMAL_MASK 0x3ff -#define ISIF_LIN_ENTRY_MASK 0x3ff - -/* masks and shifts*/ -#define ISIF_SYNCEN_VDHDEN_MASK (1 << 0) -#define ISIF_SYNCEN_WEN_MASK (1 << 1) -#define ISIF_SYNCEN_WEN_SHIFT 1 - -#endif /* _DAVINCI_VPFE_DM365_ISIF_REGS_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c deleted file mode 100644 index 7adf1fae43f6..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c +++ /dev/null @@ -1,1995 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - * - * - * Resizer allows upscaling or downscaling a image to a desired - * resolution. There are 2 resizer modules. both operating on the - * same input image, but can have different output resolution. - */ - -#include "dm365_ipipe_hw.h" -#include "dm365_resizer.h" - -#define MIN_IN_WIDTH 32 -#define MIN_IN_HEIGHT 32 -#define MAX_IN_WIDTH 4095 -#define MAX_IN_HEIGHT 4095 -#define MIN_OUT_WIDTH 16 -#define MIN_OUT_HEIGHT 2 - -static const unsigned int resizer_input_formats[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_Y8_1X8, - MEDIA_BUS_FMT_UV8_1X8, - MEDIA_BUS_FMT_SGRBG12_1X12, -}; - -static const unsigned int resizer_output_formats[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_Y8_1X8, - MEDIA_BUS_FMT_UV8_1X8, - MEDIA_BUS_FMT_YDYUYDYV8_1X16, - MEDIA_BUS_FMT_SGRBG12_1X12, -}; - -/* resizer_calculate_line_length() - This function calculates the line length of - * various image planes at the input and - * output. - */ -static void -resizer_calculate_line_length(u32 pix, int width, int height, - int *line_len, int *line_len_c) -{ - *line_len = 0; - *line_len_c = 0; - - if (pix == MEDIA_BUS_FMT_UYVY8_2X8 || - pix == MEDIA_BUS_FMT_SGRBG12_1X12) { - *line_len = width << 1; - } else { - *line_len = width; - *line_len_c = width; - } - - /* adjust the line len to be a multiple of 32 */ - *line_len += 31; - *line_len &= ~0x1f; - *line_len_c += 31; - *line_len_c &= ~0x1f; -} - -static inline int -resizer_validate_output_image_format(struct device *dev, - struct v4l2_mbus_framefmt *format, - int *in_line_len, int *in_line_len_c) -{ - if (format->code != MEDIA_BUS_FMT_UYVY8_2X8 && - format->code != MEDIA_BUS_FMT_Y8_1X8 && - format->code != MEDIA_BUS_FMT_UV8_1X8 && - format->code != MEDIA_BUS_FMT_YDYUYDYV8_1X16 && - format->code != MEDIA_BUS_FMT_SGRBG12_1X12) { - dev_err(dev, "Invalid Mbus format, %d\n", format->code); - return -EINVAL; - } - if (!format->width || !format->height) { - dev_err(dev, "invalid width or height\n"); - return -EINVAL; - } - resizer_calculate_line_length(format->code, format->width, - format->height, in_line_len, in_line_len_c); - return 0; -} - -static void -resizer_configure_passthru(struct vpfe_resizer_device *resizer, int bypass) -{ - struct resizer_params *param = &resizer->config; - - param->rsz_rsc_param[RSZ_A].cen = DISABLE; - param->rsz_rsc_param[RSZ_A].yen = DISABLE; - param->rsz_rsc_param[RSZ_A].v_phs_y = 0; - param->rsz_rsc_param[RSZ_A].v_phs_c = 0; - param->rsz_rsc_param[RSZ_A].v_dif = 256; - param->rsz_rsc_param[RSZ_A].v_lpf_int_y = 0; - param->rsz_rsc_param[RSZ_A].v_lpf_int_c = 0; - param->rsz_rsc_param[RSZ_A].h_phs = 0; - param->rsz_rsc_param[RSZ_A].h_dif = 256; - param->rsz_rsc_param[RSZ_A].h_lpf_int_y = 0; - param->rsz_rsc_param[RSZ_A].h_lpf_int_c = 0; - param->rsz_rsc_param[RSZ_A].dscale_en = DISABLE; - param->rsz2rgb[RSZ_A].rgb_en = DISABLE; - param->rsz_en[RSZ_A] = ENABLE; - param->rsz_en[RSZ_B] = DISABLE; - if (bypass) { - param->rsz_rsc_param[RSZ_A].i_vps = 0; - param->rsz_rsc_param[RSZ_A].i_hps = 0; - /* Raw Bypass */ - param->rsz_common.passthrough = BYPASS_ON; - } -} - -static void -configure_resizer_out_params(struct vpfe_resizer_device *resizer, int index, - void *output_spec, unsigned char partial, - unsigned int flag) -{ - struct resizer_params *param = &resizer->config; - struct v4l2_mbus_framefmt *outformat; - struct vpfe_rsz_output_spec *output; - - if (index == RSZ_A && - resizer->resizer_a.output == RESIZER_OUTPUT_NONE) { - param->rsz_en[index] = DISABLE; - return; - } - if (index == RSZ_B && - resizer->resizer_b.output == RESIZER_OUTPUT_NONE) { - param->rsz_en[index] = DISABLE; - return; - } - output = output_spec; - param->rsz_en[index] = ENABLE; - if (partial) { - param->rsz_rsc_param[index].h_flip = output->h_flip; - param->rsz_rsc_param[index].v_flip = output->v_flip; - param->rsz_rsc_param[index].v_typ_y = output->v_typ_y; - param->rsz_rsc_param[index].v_typ_c = output->v_typ_c; - param->rsz_rsc_param[index].v_lpf_int_y = - output->v_lpf_int_y; - param->rsz_rsc_param[index].v_lpf_int_c = - output->v_lpf_int_c; - param->rsz_rsc_param[index].h_typ_y = output->h_typ_y; - param->rsz_rsc_param[index].h_typ_c = output->h_typ_c; - param->rsz_rsc_param[index].h_lpf_int_y = - output->h_lpf_int_y; - param->rsz_rsc_param[index].h_lpf_int_c = - output->h_lpf_int_c; - param->rsz_rsc_param[index].dscale_en = - output->en_down_scale; - param->rsz_rsc_param[index].h_dscale_ave_sz = - output->h_dscale_ave_sz; - param->rsz_rsc_param[index].v_dscale_ave_sz = - output->v_dscale_ave_sz; - param->ext_mem_param[index].user_y_ofst = - (output->user_y_ofst + 31) & ~0x1f; - param->ext_mem_param[index].user_c_ofst = - (output->user_c_ofst + 31) & ~0x1f; - return; - } - - if (index == RSZ_A) - outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; - else - outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; - param->rsz_rsc_param[index].o_vsz = outformat->height - 1; - param->rsz_rsc_param[index].o_hsz = outformat->width - 1; - param->ext_mem_param[index].rsz_sdr_ptr_s_y = output->vst_y; - param->ext_mem_param[index].rsz_sdr_ptr_e_y = outformat->height; - param->ext_mem_param[index].rsz_sdr_ptr_s_c = output->vst_c; - param->ext_mem_param[index].rsz_sdr_ptr_e_c = outformat->height; - - if (!flag) - return; - /* update common parameters */ - param->rsz_rsc_param[index].h_flip = output->h_flip; - param->rsz_rsc_param[index].v_flip = output->v_flip; - param->rsz_rsc_param[index].v_typ_y = output->v_typ_y; - param->rsz_rsc_param[index].v_typ_c = output->v_typ_c; - param->rsz_rsc_param[index].v_lpf_int_y = output->v_lpf_int_y; - param->rsz_rsc_param[index].v_lpf_int_c = output->v_lpf_int_c; - param->rsz_rsc_param[index].h_typ_y = output->h_typ_y; - param->rsz_rsc_param[index].h_typ_c = output->h_typ_c; - param->rsz_rsc_param[index].h_lpf_int_y = output->h_lpf_int_y; - param->rsz_rsc_param[index].h_lpf_int_c = output->h_lpf_int_c; - param->rsz_rsc_param[index].dscale_en = output->en_down_scale; - param->rsz_rsc_param[index].h_dscale_ave_sz = output->h_dscale_ave_sz; - param->rsz_rsc_param[index].v_dscale_ave_sz = output->h_dscale_ave_sz; - param->ext_mem_param[index].user_y_ofst = - (output->user_y_ofst + 31) & ~0x1f; - param->ext_mem_param[index].user_c_ofst = - (output->user_c_ofst + 31) & ~0x1f; -} - -/* - * resizer_calculate_resize_ratios() - Calculates resize ratio for resizer - * A or B. This is called after setting - * the input size or output size. - * @resizer: Pointer to VPFE resizer subdevice. - * @index: index RSZ_A-resizer-A RSZ_B-resizer-B. - */ -static void -resizer_calculate_resize_ratios(struct vpfe_resizer_device *resizer, int index) -{ - struct resizer_params *param = &resizer->config; - struct v4l2_mbus_framefmt *informat, *outformat; - - informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK]; - - if (index == RSZ_A) - outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; - else - outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; - - if (outformat->field != V4L2_FIELD_INTERLACED) - param->rsz_rsc_param[index].v_dif = - ((informat->height) * 256) / (outformat->height); - else - param->rsz_rsc_param[index].v_dif = - ((informat->height >> 1) * 256) / (outformat->height); - param->rsz_rsc_param[index].h_dif = - ((informat->width) * 256) / (outformat->width); -} - -static void resizer_enable_422_420_conversion(struct resizer_params *param, - int index, bool en) -{ - param->rsz_rsc_param[index].cen = en; - param->rsz_rsc_param[index].yen = en; -} - -/* resizer_calculate_sdram_offsets() - This function calculates the offsets from - * start of buffer for the C plane when - * output format is YUV420SP. It also - * calculates the offsets from the start of - * the buffer when the image is flipped - * vertically or horizontally for ycbcr/y/c - * planes. - * @resizer: Pointer to resizer subdevice. - * @index: index RSZ_A-resizer-A RSZ_B-resizer-B. - */ -static int -resizer_calculate_sdram_offsets(struct vpfe_resizer_device *resizer, int index) -{ - struct resizer_params *param = &resizer->config; - struct v4l2_mbus_framefmt *outformat; - int bytesperpixel = 2; - int image_height; - int image_width; - int yuv_420 = 0; - int offset = 0; - - if (index == RSZ_A) - outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; - else - outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; - - image_height = outformat->height + 1; - image_width = outformat->width + 1; - param->ext_mem_param[index].c_offset = 0; - param->ext_mem_param[index].flip_ofst_y = 0; - param->ext_mem_param[index].flip_ofst_c = 0; - if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) { - /* YUV 420 */ - yuv_420 = 1; - bytesperpixel = 1; - } - - if (param->rsz_rsc_param[index].h_flip) - /* width * bytesperpixel - 1 */ - offset = (image_width * bytesperpixel) - 1; - if (param->rsz_rsc_param[index].v_flip) - offset += (image_height - 1) * - param->ext_mem_param[index].rsz_sdr_oft_y; - param->ext_mem_param[index].flip_ofst_y = offset; - if (!yuv_420) - return 0; - offset = 0; - /* half height for c-plane */ - if (param->rsz_rsc_param[index].h_flip) - /* width * bytesperpixel - 1 */ - offset = image_width - 1; - if (param->rsz_rsc_param[index].v_flip) - offset += (((image_height >> 1) - 1) * - param->ext_mem_param[index].rsz_sdr_oft_c); - param->ext_mem_param[index].flip_ofst_c = offset; - param->ext_mem_param[index].c_offset = - param->ext_mem_param[index].rsz_sdr_oft_y * image_height; - return 0; -} - -static int resizer_configure_output_win(struct vpfe_resizer_device *resizer) -{ - struct resizer_params *param = &resizer->config; - struct vpfe_rsz_output_spec output_specs; - struct v4l2_mbus_framefmt *outformat; - int line_len_c; - int line_len; - int ret; - - outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; - - memset(&output_specs, 0x0, sizeof(struct vpfe_rsz_output_spec)); - output_specs.vst_y = param->user_config.vst; - if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) - output_specs.vst_c = param->user_config.vst; - - configure_resizer_out_params(resizer, RSZ_A, &output_specs, 0, 0); - resizer_calculate_line_length(outformat->code, - param->rsz_rsc_param[0].o_hsz + 1, - param->rsz_rsc_param[0].o_vsz + 1, - &line_len, &line_len_c); - param->ext_mem_param[0].rsz_sdr_oft_y = line_len; - param->ext_mem_param[0].rsz_sdr_oft_c = line_len_c; - resizer_calculate_resize_ratios(resizer, RSZ_A); - if (param->rsz_en[RSZ_B]) - resizer_calculate_resize_ratios(resizer, RSZ_B); - - if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) - resizer_enable_422_420_conversion(param, RSZ_A, ENABLE); - else - resizer_enable_422_420_conversion(param, RSZ_A, DISABLE); - - ret = resizer_calculate_sdram_offsets(resizer, RSZ_A); - if (!ret && param->rsz_en[RSZ_B]) - ret = resizer_calculate_sdram_offsets(resizer, RSZ_B); - - if (ret) - pr_err("Error in calculating sdram offsets\n"); - return ret; -} - -static int -resizer_calculate_down_scale_f_div_param(struct device *dev, - int input_width, int output_width, - struct resizer_scale_param *param) -{ - /* rsz = R, input_width = H, output width = h in the equation */ - unsigned int two_power; - unsigned int upper_h1; - unsigned int upper_h2; - unsigned int val1; - unsigned int val; - unsigned int rsz; - unsigned int h1; - unsigned int h2; - unsigned int o; - unsigned int n; - - upper_h1 = input_width >> 1; - n = param->h_dscale_ave_sz; - /* 2 ^ (scale+1) */ - two_power = 1 << (n + 1); - upper_h1 = (upper_h1 >> (n + 1)) << (n + 1); - upper_h2 = input_width - upper_h1; - if (upper_h2 % two_power) { - dev_err(dev, "frame halves to be a multiple of 2 power n+1\n"); - return -EINVAL; - } - two_power = 1 << n; - rsz = (input_width << 8) / output_width; - val = rsz * two_power; - val = ((upper_h1 << 8) / val) + 1; - if (!(val % 2)) { - h1 = val; - } else { - val = upper_h1 << 8; - val >>= n + 1; - val -= rsz >> 1; - val /= rsz << 1; - val <<= 1; - val += 2; - h1 = val; - } - o = 10 + (two_power << 2); - if (((input_width << 7) / rsz) % 2) - o += ((DIV_ROUND_UP(rsz, 1024) << 1) << n); - h2 = output_width - h1; - /* phi */ - val = (h1 * rsz) - (((upper_h1 - (o - 10)) / two_power) << 8); - /* skip */ - val1 = ((val - 1024) >> 9) << 1; - param->f_div.num_passes = MAX_PASSES; - param->f_div.pass[0].o_hsz = h1 - 1; - param->f_div.pass[0].i_hps = 0; - param->f_div.pass[0].h_phs = 0; - param->f_div.pass[0].src_hps = 0; - param->f_div.pass[0].src_hsz = upper_h1 + o; - param->f_div.pass[1].o_hsz = h2 - 1; - param->f_div.pass[1].i_hps = 10 + (val1 * two_power); - param->f_div.pass[1].h_phs = val - (val1 << 8); - param->f_div.pass[1].src_hps = upper_h1 - o; - param->f_div.pass[1].src_hsz = upper_h2 + o; - - return 0; -} - -static int -resizer_configure_common_in_params(struct vpfe_resizer_device *resizer) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - struct resizer_params *param = &resizer->config; - struct vpfe_rsz_config_params *user_config; - struct v4l2_mbus_framefmt *informat; - - informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK]; - user_config = &resizer->config.user_config; - param->rsz_common.vps = param->user_config.vst; - param->rsz_common.hps = param->user_config.hst; - - if (vpfe_ipipeif_decimation_enabled(vpfe_dev)) - param->rsz_common.hsz = ((informat->width - 1) * - IPIPEIF_RSZ_CONST) / vpfe_ipipeif_get_rsz(vpfe_dev); - else - param->rsz_common.hsz = informat->width - 1; - - if (informat->field == V4L2_FIELD_INTERLACED) - param->rsz_common.vsz = (informat->height - 1) >> 1; - else - param->rsz_common.vsz = informat->height - 1; - - param->rsz_common.raw_flip = 0; - - if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF) - param->rsz_common.source = IPIPEIF_DATA; - else - param->rsz_common.source = IPIPE_DATA; - - switch (informat->code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - param->rsz_common.src_img_fmt = RSZ_IMG_422; - param->rsz_common.raw_flip = 0; - break; - - case MEDIA_BUS_FMT_Y8_1X8: - param->rsz_common.src_img_fmt = RSZ_IMG_420; - /* Select y */ - param->rsz_common.y_c = 0; - param->rsz_common.raw_flip = 0; - break; - - case MEDIA_BUS_FMT_UV8_1X8: - param->rsz_common.src_img_fmt = RSZ_IMG_420; - /* Select y */ - param->rsz_common.y_c = 1; - param->rsz_common.raw_flip = 0; - break; - - case MEDIA_BUS_FMT_SGRBG12_1X12: - param->rsz_common.raw_flip = 1; - break; - - default: - param->rsz_common.src_img_fmt = RSZ_IMG_422; - param->rsz_common.source = IPIPE_DATA; - } - - param->rsz_common.yuv_y_min = user_config->yuv_y_min; - param->rsz_common.yuv_y_max = user_config->yuv_y_max; - param->rsz_common.yuv_c_min = user_config->yuv_c_min; - param->rsz_common.yuv_c_max = user_config->yuv_c_max; - param->rsz_common.out_chr_pos = user_config->out_chr_pos; - param->rsz_common.rsz_seq_crv = user_config->chroma_sample_even; - - return 0; -} -static int -resizer_configure_in_continuous_mode(struct vpfe_resizer_device *resizer) -{ - struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; - struct resizer_params *param = &resizer->config; - struct vpfe_rsz_config_params *cont_config; - int line_len_c; - int line_len; - int ret; - - if (resizer->resizer_a.output != RESIZER_OUTPUT_MEMORY) { - dev_err(dev, "enable resizer - Resizer-A\n"); - return -EINVAL; - } - - cont_config = &resizer->config.user_config; - param->rsz_en[RSZ_A] = ENABLE; - configure_resizer_out_params(resizer, RSZ_A, - &cont_config->output1, 1, 0); - param->rsz_en[RSZ_B] = DISABLE; - param->oper_mode = RESIZER_MODE_CONTINUOUS; - - if (resizer->resizer_b.output == RESIZER_OUTPUT_MEMORY) { - struct v4l2_mbus_framefmt *outformat2; - - param->rsz_en[RSZ_B] = ENABLE; - outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; - ret = resizer_validate_output_image_format(dev, outformat2, - &line_len, &line_len_c); - if (ret) - return ret; - param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len; - param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c; - configure_resizer_out_params(resizer, RSZ_B, - &cont_config->output2, 0, 1); - if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) - resizer_enable_422_420_conversion(param, - RSZ_B, ENABLE); - else - resizer_enable_422_420_conversion(param, - RSZ_B, DISABLE); - } - resizer_configure_common_in_params(resizer); - ret = resizer_configure_output_win(resizer); - if (ret) - return ret; - - param->rsz_common.passthrough = cont_config->bypass; - if (cont_config->bypass) - resizer_configure_passthru(resizer, 1); - - return 0; -} - -static inline int -resizer_validate_input_image_format(struct device *dev, - u32 pix, - int width, int height, int *line_len) -{ - int val; - - if (pix != MEDIA_BUS_FMT_UYVY8_2X8 && - pix != MEDIA_BUS_FMT_Y8_1X8 && - pix != MEDIA_BUS_FMT_UV8_1X8 && - pix != MEDIA_BUS_FMT_SGRBG12_1X12) { - dev_err(dev, - "resizer validate output: pix format not supported, %d\n", pix); - return -EINVAL; - } - - if (!width || !height) { - dev_err(dev, - "resizer validate input: invalid width or height\n"); - return -EINVAL; - } - - if (pix == MEDIA_BUS_FMT_UV8_1X8) - resizer_calculate_line_length(pix, width, - height, &val, line_len); - else - resizer_calculate_line_length(pix, width, - height, line_len, &val); - - return 0; -} - -static int -resizer_validate_decimation(struct device *dev, enum ipipeif_decimation dec_en, - unsigned char rsz, unsigned char frame_div_mode_en, - int width) -{ - if (dec_en && frame_div_mode_en) { - dev_err(dev, - "dec_en & frame_div_mode_en can not enabled simultaneously\n"); - return -EINVAL; - } - - if (frame_div_mode_en) { - dev_err(dev, "frame_div_mode mode not supported\n"); - return -EINVAL; - } - - if (!dec_en) - return 0; - - if (width <= VPFE_IPIPE_MAX_INPUT_WIDTH) { - dev_err(dev, - "image width to be more than %d for decimation\n", - VPFE_IPIPE_MAX_INPUT_WIDTH); - return -EINVAL; - } - - if (rsz < IPIPEIF_RSZ_MIN || rsz > IPIPEIF_RSZ_MAX) { - dev_err(dev, "rsz range is %d to %d\n", - IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX); - return -EINVAL; - } - - return 0; -} - -/* resizer_calculate_normal_f_div_param() - Algorithm to calculate the frame - * division parameters for resizer. - * in normal mode. - */ -static int -resizer_calculate_normal_f_div_param(struct device *dev, int input_width, - int output_width, struct resizer_scale_param *param) -{ - /* rsz = R, input_width = H, output width = h in the equation */ - unsigned int val1; - unsigned int rsz; - unsigned int val; - unsigned int h1; - unsigned int h2; - unsigned int o; - - if (output_width > input_width) { - dev_err(dev, "frame div mode is used for scale down only\n"); - return -EINVAL; - } - - rsz = (input_width << 8) / output_width; - val = rsz << 1; - val = ((input_width << 8) / val) + 1; - o = 14; - if (!(val % 2)) { - h1 = val; - } else { - val = input_width << 7; - val -= rsz >> 1; - val /= rsz << 1; - val <<= 1; - val += 2; - o += (DIV_ROUND_UP(rsz, 1024) << 1); - h1 = val; - } - h2 = output_width - h1; - /* phi */ - val = (h1 * rsz) - (((input_width >> 1) - o) << 8); - /* skip */ - val1 = ((val - 1024) >> 9) << 1; - param->f_div.num_passes = MAX_PASSES; - param->f_div.pass[0].o_hsz = h1 - 1; - param->f_div.pass[0].i_hps = 0; - param->f_div.pass[0].h_phs = 0; - param->f_div.pass[0].src_hps = 0; - param->f_div.pass[0].src_hsz = (input_width >> 2) + o; - param->f_div.pass[1].o_hsz = h2 - 1; - param->f_div.pass[1].i_hps = val1; - param->f_div.pass[1].h_phs = val - (val1 << 8); - param->f_div.pass[1].src_hps = (input_width >> 2) - o; - param->f_div.pass[1].src_hsz = (input_width >> 2) + o; - - return 0; -} - -static int -resizer_configure_in_single_shot_mode(struct vpfe_resizer_device *resizer) -{ - struct vpfe_rsz_config_params *config = &resizer->config.user_config; - struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - struct v4l2_mbus_framefmt *outformat1, *outformat2; - struct resizer_params *param = &resizer->config; - struct v4l2_mbus_framefmt *informat; - int decimation; - int line_len_c; - int line_len; - int rsz; - int ret; - - informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK]; - outformat1 = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; - outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; - - decimation = vpfe_ipipeif_decimation_enabled(vpfe_dev); - rsz = vpfe_ipipeif_get_rsz(vpfe_dev); - if (decimation && param->user_config.frame_div_mode_en) { - dev_err(dev, - "dec_en & frame_div_mode_en cannot enabled simultaneously\n"); - return -EINVAL; - } - - ret = resizer_validate_decimation(dev, decimation, rsz, - param->user_config.frame_div_mode_en, informat->width); - if (ret) - return -EINVAL; - - ret = resizer_validate_input_image_format(dev, informat->code, - informat->width, informat->height, &line_len); - if (ret) - return -EINVAL; - - if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) { - param->rsz_en[RSZ_A] = ENABLE; - ret = resizer_validate_output_image_format(dev, outformat1, - &line_len, &line_len_c); - if (ret) - return ret; - param->ext_mem_param[RSZ_A].rsz_sdr_oft_y = line_len; - param->ext_mem_param[RSZ_A].rsz_sdr_oft_c = line_len_c; - configure_resizer_out_params(resizer, RSZ_A, - ¶m->user_config.output1, 0, 1); - - if (outformat1->code == MEDIA_BUS_FMT_SGRBG12_1X12) - param->rsz_common.raw_flip = 1; - else - param->rsz_common.raw_flip = 0; - - if (outformat1->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) - resizer_enable_422_420_conversion(param, - RSZ_A, ENABLE); - else - resizer_enable_422_420_conversion(param, - RSZ_A, DISABLE); - } - - if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) { - param->rsz_en[RSZ_B] = ENABLE; - ret = resizer_validate_output_image_format(dev, outformat2, - &line_len, &line_len_c); - if (ret) - return ret; - param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len; - param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c; - configure_resizer_out_params(resizer, RSZ_B, - ¶m->user_config.output2, 0, 1); - if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) - resizer_enable_422_420_conversion(param, - RSZ_B, ENABLE); - else - resizer_enable_422_420_conversion(param, - RSZ_B, DISABLE); - } - - resizer_configure_common_in_params(resizer); - if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) { - resizer_calculate_resize_ratios(resizer, RSZ_A); - resizer_calculate_sdram_offsets(resizer, RSZ_A); - /* Overriding resize ratio calculation */ - if (informat->code == MEDIA_BUS_FMT_UV8_1X8) { - param->rsz_rsc_param[RSZ_A].v_dif = - (((informat->height + 1) * 2) * 256) / - (param->rsz_rsc_param[RSZ_A].o_vsz + 1); - } - } - - if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) { - resizer_calculate_resize_ratios(resizer, RSZ_B); - resizer_calculate_sdram_offsets(resizer, RSZ_B); - /* Overriding resize ratio calculation */ - if (informat->code == MEDIA_BUS_FMT_UV8_1X8) { - param->rsz_rsc_param[RSZ_B].v_dif = - (((informat->height + 1) * 2) * 256) / - (param->rsz_rsc_param[RSZ_B].o_vsz + 1); - } - } - if (param->user_config.frame_div_mode_en && - param->rsz_en[RSZ_A]) { - if (!param->rsz_rsc_param[RSZ_A].dscale_en) - ret = resizer_calculate_normal_f_div_param(dev, - informat->width, - param->rsz_rsc_param[RSZ_A].o_vsz + 1, - ¶m->rsz_rsc_param[RSZ_A]); - else - ret = resizer_calculate_down_scale_f_div_param(dev, - informat->width, - param->rsz_rsc_param[RSZ_A].o_vsz + 1, - ¶m->rsz_rsc_param[RSZ_A]); - if (ret) - return -EINVAL; - } - if (param->user_config.frame_div_mode_en && - param->rsz_en[RSZ_B]) { - if (!param->rsz_rsc_param[RSZ_B].dscale_en) - ret = resizer_calculate_normal_f_div_param(dev, - informat->width, - param->rsz_rsc_param[RSZ_B].o_vsz + 1, - ¶m->rsz_rsc_param[RSZ_B]); - else - ret = resizer_calculate_down_scale_f_div_param(dev, - informat->width, - param->rsz_rsc_param[RSZ_B].o_vsz + 1, - ¶m->rsz_rsc_param[RSZ_B]); - if (ret) - return -EINVAL; - } - param->rsz_common.passthrough = config->bypass; - if (config->bypass) - resizer_configure_passthru(resizer, 1); - return 0; -} - -static void -resizer_set_default_configuration(struct vpfe_resizer_device *resizer) -{ -#define WIDTH_I 640 -#define HEIGHT_I 480 -#define WIDTH_O 640 -#define HEIGHT_O 480 - const struct resizer_params rsz_default_config = { - .oper_mode = RESIZER_MODE_ONE_SHOT, - .rsz_common = { - .vsz = HEIGHT_I - 1, - .hsz = WIDTH_I - 1, - .src_img_fmt = RSZ_IMG_422, - .raw_flip = 1, /* flip preserve Raw format */ - .source = IPIPE_DATA, - .passthrough = BYPASS_OFF, - .yuv_y_max = 255, - .yuv_c_max = 255, - .rsz_seq_crv = DISABLE, - .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE, - }, - .rsz_rsc_param = { - { - .h_flip = DISABLE, - .v_flip = DISABLE, - .cen = DISABLE, - .yen = DISABLE, - .o_vsz = HEIGHT_O - 1, - .o_hsz = WIDTH_O - 1, - .v_dif = 256, - .v_typ_y = VPFE_RSZ_INTP_CUBIC, - .v_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dif = 256, - .h_typ_y = VPFE_RSZ_INTP_CUBIC, - .h_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - .v_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - }, - { - .h_flip = DISABLE, - .v_flip = DISABLE, - .cen = DISABLE, - .yen = DISABLE, - .o_vsz = HEIGHT_O - 1, - .o_hsz = WIDTH_O - 1, - .v_dif = 256, - .v_typ_y = VPFE_RSZ_INTP_CUBIC, - .v_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dif = 256, - .h_typ_y = VPFE_RSZ_INTP_CUBIC, - .h_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - .v_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - }, - }, - .rsz2rgb = { - { - .rgb_en = DISABLE - }, - { - .rgb_en = DISABLE - } - }, - .ext_mem_param = { - { - .rsz_sdr_oft_y = WIDTH_O << 1, - .rsz_sdr_ptr_e_y = HEIGHT_O, - .rsz_sdr_oft_c = WIDTH_O, - .rsz_sdr_ptr_e_c = HEIGHT_O >> 1, - }, - { - .rsz_sdr_oft_y = WIDTH_O << 1, - .rsz_sdr_ptr_e_y = HEIGHT_O, - .rsz_sdr_oft_c = WIDTH_O, - .rsz_sdr_ptr_e_c = HEIGHT_O, - }, - }, - .rsz_en[0] = ENABLE, - .rsz_en[1] = DISABLE, - .user_config = { - .output1 = { - .v_typ_y = VPFE_RSZ_INTP_CUBIC, - .v_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_typ_y = VPFE_RSZ_INTP_CUBIC, - .h_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - .v_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - }, - .output2 = { - .v_typ_y = VPFE_RSZ_INTP_CUBIC, - .v_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_typ_y = VPFE_RSZ_INTP_CUBIC, - .h_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - .v_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - }, - .yuv_y_max = 255, - .yuv_c_max = 255, - .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE, - }, - }; - memcpy(&resizer->config, &rsz_default_config, - sizeof(struct resizer_params)); -} - -/* - * resizer_set_configuration() - set resizer config - * @resizer: vpfe resizer device pointer. - * @chan_config: resizer channel configuration. - */ -static int -resizer_set_configuration(struct vpfe_resizer_device *resizer, - struct vpfe_rsz_config *chan_config) -{ - if (!chan_config->config) - resizer_set_default_configuration(resizer); - else - if (copy_from_user(&resizer->config.user_config, - (void __user *)chan_config->config, - sizeof(struct vpfe_rsz_config_params))) - return -EFAULT; - - return 0; -} - -/* - * resizer_get_configuration() - get resizer config - * @resizer: vpfe resizer device pointer. - * @channel: image processor logical channel. - * @chan_config: resizer channel configuration. - */ -static int -resizer_get_configuration(struct vpfe_resizer_device *resizer, - struct vpfe_rsz_config *chan_config) -{ - struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; - - if (!chan_config->config) { - dev_err(dev, "Resizer channel invalid pointer\n"); - return -EINVAL; - } - - if (copy_to_user((void __user *)chan_config->config, - (void *)&resizer->config.user_config, - sizeof(struct vpfe_rsz_config_params))) { - dev_err(dev, "resizer_get_configuration: Error in copy to user\n"); - return -EFAULT; - } - - return 0; -} - -/* - * VPFE video operations - */ - -/* - * resizer_a_video_out_queue() - RESIZER-A video out queue - * @vpfe_dev: vpfe device pointer. - * @addr: buffer address. - */ -static int resizer_a_video_out_queue(struct vpfe_device *vpfe_dev, - unsigned long addr) -{ - struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer; - - return resizer_set_outaddr(resizer->base_addr, - &resizer->config, RSZ_A, addr); -} - -/* - * resizer_b_video_out_queue() - RESIZER-B video out queue - * @vpfe_dev: vpfe device pointer. - * @addr: buffer address. - */ -static int resizer_b_video_out_queue(struct vpfe_device *vpfe_dev, - unsigned long addr) -{ - struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer; - - return resizer_set_outaddr(resizer->base_addr, - &resizer->config, RSZ_B, addr); -} - -static const struct vpfe_video_operations resizer_a_video_ops = { - .queue = resizer_a_video_out_queue, -}; - -static const struct vpfe_video_operations resizer_b_video_ops = { - .queue = resizer_b_video_out_queue, -}; - -static void resizer_enable(struct vpfe_resizer_device *resizer, int en) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; - unsigned char val; - - if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE) - return; - - if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF && - ipipeif_sink == IPIPEIF_INPUT_MEMORY) { - do { - val = regr_rsz(resizer->base_addr, RSZ_SRC_EN); - } while (val); - - if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) { - do { - val = regr_rsz(resizer->base_addr, RSZ_A); - } while (val); - } - if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) { - do { - val = regr_rsz(resizer->base_addr, RSZ_B); - } while (val); - } - } - if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) - rsz_enable(resizer->base_addr, RSZ_A, en); - - if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) - rsz_enable(resizer->base_addr, RSZ_B, en); -} - - -/* - * resizer_ss_isr() - resizer module single-shot buffer scheduling isr - * @resizer: vpfe resizer device pointer. - */ -static void resizer_ss_isr(struct vpfe_resizer_device *resizer) -{ - struct vpfe_video_device *video_out = &resizer->resizer_a.video_out; - struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out; - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - struct vpfe_pipeline *pipe = &video_out->pipe; - u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; - u32 val; - - if (ipipeif_sink != IPIPEIF_INPUT_MEMORY) - return; - - if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) { - val = vpss_dma_complete_interrupt(); - if (val != 0 && val != 2) - return; - } - - if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) { - spin_lock(&video_out->dma_queue_lock); - vpfe_video_process_buffer_complete(video_out); - video_out->state = VPFE_VIDEO_BUFFER_NOT_QUEUED; - vpfe_video_schedule_next_buffer(video_out); - spin_unlock(&video_out->dma_queue_lock); - } - - /* If resizer B is enabled */ - if (pipe->output_num > 1 && resizer->resizer_b.output == - RESIZER_OUTPUT_MEMORY) { - spin_lock(&video_out2->dma_queue_lock); - vpfe_video_process_buffer_complete(video_out2); - video_out2->state = VPFE_VIDEO_BUFFER_NOT_QUEUED; - vpfe_video_schedule_next_buffer(video_out2); - spin_unlock(&video_out2->dma_queue_lock); - } - - /* start HW if buffers are queued */ - if (vpfe_video_is_pipe_ready(pipe) && - resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) { - resizer_enable(resizer, 1); - vpfe_ipipe_enable(vpfe_dev, 1); - vpfe_ipipeif_enable(vpfe_dev); - } -} - -/* - * vpfe_resizer_buffer_isr() - resizer module buffer scheduling isr - * @resizer: vpfe resizer device pointer. - */ -void vpfe_resizer_buffer_isr(struct vpfe_resizer_device *resizer) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - struct vpfe_video_device *video_out = &resizer->resizer_a.video_out; - struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out; - struct vpfe_pipeline *pipe = &resizer->resizer_a.video_out.pipe; - enum v4l2_field field; - int fid; - - if (!video_out->started) - return; - - if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE) - return; - - field = video_out->fmt.fmt.pix.field; - if (field == V4L2_FIELD_NONE) { - /* handle progressive frame capture */ - if (video_out->cur_frm != video_out->next_frm) { - vpfe_video_process_buffer_complete(video_out); - if (pipe->output_num > 1) - vpfe_video_process_buffer_complete(video_out2); - } - - video_out->skip_frame_count--; - if (!video_out->skip_frame_count) { - video_out->skip_frame_count = - video_out->skip_frame_count_init; - rsz_src_enable(resizer->base_addr, 1); - } else { - rsz_src_enable(resizer->base_addr, 0); - } - return; - } - - /* handle interlaced frame capture */ - fid = vpfe_isif_get_fid(vpfe_dev); - - /* switch the software maintained field id */ - video_out->field_id ^= 1; - if (fid == video_out->field_id) { - /* - * we are in-sync here,continue. - * One frame is just being captured. If the - * next frame is available, release the current - * frame and move on - */ - if (fid == 0 && video_out->cur_frm != video_out->next_frm) { - vpfe_video_process_buffer_complete(video_out); - if (pipe->output_num > 1) - vpfe_video_process_buffer_complete(video_out2); - } - } else if (fid == 0) { - /* - * out of sync. Recover from any hardware out-of-sync. - * May loose one frame - */ - video_out->field_id = fid; - } -} - -/* - * vpfe_resizer_dma_isr() - resizer module dma isr - * @resizer: vpfe resizer device pointer. - */ -void vpfe_resizer_dma_isr(struct vpfe_resizer_device *resizer) -{ - struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out; - struct vpfe_video_device *video_out = &resizer->resizer_a.video_out; - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - struct vpfe_pipeline *pipe = &video_out->pipe; - int schedule_capture = 0; - enum v4l2_field field; - int fid; - - if (!video_out->started) - return; - - if (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT) { - resizer_ss_isr(resizer); - return; - } - - field = video_out->fmt.fmt.pix.field; - if (field == V4L2_FIELD_NONE) { - if (!list_empty(&video_out->dma_queue) && - video_out->cur_frm == video_out->next_frm) - schedule_capture = 1; - } else { - fid = vpfe_isif_get_fid(vpfe_dev); - if (fid == video_out->field_id) { - /* we are in-sync here,continue */ - if (fid == 1 && !list_empty(&video_out->dma_queue) && - video_out->cur_frm == video_out->next_frm) - schedule_capture = 1; - } - } - - if (!schedule_capture) - return; - - spin_lock(&video_out->dma_queue_lock); - vpfe_video_schedule_next_buffer(video_out); - spin_unlock(&video_out->dma_queue_lock); - if (pipe->output_num > 1) { - spin_lock(&video_out2->dma_queue_lock); - vpfe_video_schedule_next_buffer(video_out2); - spin_unlock(&video_out2->dma_queue_lock); - } -} - -/* - * V4L2 subdev operations - */ - -/* - * resizer_ioctl() - Handle resizer module private ioctl's - * @sd: pointer to v4l2 subdev structure - * @cmd: configuration command - * @arg: configuration argument - */ -static long resizer_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; - struct vpfe_rsz_config *user_config; - int ret = -ENOIOCTLCMD; - - if (&resizer->crop_resizer.subdev != sd) - return ret; - - switch (cmd) { - case VIDIOC_VPFE_RSZ_S_CONFIG: - user_config = arg; - ret = resizer_set_configuration(resizer, user_config); - break; - - case VIDIOC_VPFE_RSZ_G_CONFIG: - user_config = arg; - if (!user_config->config) { - dev_err(dev, "error in VIDIOC_VPFE_RSZ_G_CONFIG\n"); - return -EINVAL; - } - ret = resizer_get_configuration(resizer, user_config); - break; - } - return ret; -} - -static int resizer_do_hw_setup(struct vpfe_resizer_device *resizer) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; - u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output; - struct resizer_params *param = &resizer->config; - int ret = 0; - - if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY || - resizer->resizer_b.output == RESIZER_OUTPUT_MEMORY) { - if (ipipeif_sink == IPIPEIF_INPUT_MEMORY && - ipipeif_source == IPIPEIF_OUTPUT_RESIZER) - ret = resizer_configure_in_single_shot_mode(resizer); - else - ret = resizer_configure_in_continuous_mode(resizer); - if (ret) - return ret; - ret = config_rsz_hw(resizer, param); - } - return ret; -} - -/* - * resizer_set_stream() - Enable/Disable streaming on resizer subdev - * @sd: pointer to v4l2 subdev structure - * @enable: 1 == Enable, 0 == Disable - */ -static int resizer_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - - if (&resizer->crop_resizer.subdev != sd) - return 0; - - if (resizer->resizer_a.output != RESIZER_OUTPUT_MEMORY) - return 0; - - switch (enable) { - case 1: - if (resizer_do_hw_setup(resizer) < 0) - return -EINVAL; - resizer_enable(resizer, enable); - break; - - case 0: - resizer_enable(resizer, enable); - break; - } - - return 0; -} - -/* - * __resizer_get_format() - helper function for getting resizer format - * @sd: pointer to subdev. - * @cfg: V4L2 subdev pad config - * @pad: pad number. - * @which: wanted subdev format. - * Return wanted mbus frame format. - */ -static struct v4l2_mbus_framefmt * -__resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(sd, cfg, pad); - if (&resizer->crop_resizer.subdev == sd) - return &resizer->crop_resizer.formats[pad]; - if (&resizer->resizer_a.subdev == sd) - return &resizer->resizer_a.formats[pad]; - if (&resizer->resizer_b.subdev == sd) - return &resizer->resizer_b.formats[pad]; - return NULL; -} - -/* - * resizer_try_format() - Handle try format by pad subdev method - * @sd: pointer to subdev. - * @cfg: V4L2 subdev pad config - * @pad: pad num. - * @fmt: pointer to v4l2 format structure. - * @which: wanted subdev format. - */ -static void -resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - unsigned int pad, struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - unsigned int max_out_height; - unsigned int max_out_width; - unsigned int i; - - if ((&resizer->resizer_a.subdev == sd && pad == RESIZER_PAD_SINK) || - (&resizer->resizer_b.subdev == sd && pad == RESIZER_PAD_SINK) || - (&resizer->crop_resizer.subdev == sd && - (pad == RESIZER_CROP_PAD_SOURCE || - pad == RESIZER_CROP_PAD_SOURCE2 || pad == RESIZER_CROP_PAD_SINK))) { - for (i = 0; i < ARRAY_SIZE(resizer_input_formats); i++) { - if (fmt->code == resizer_input_formats[i]) - break; - } - /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(resizer_input_formats)) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; - - fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH, - MAX_IN_WIDTH); - fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT, - MAX_IN_HEIGHT); - } else if (&resizer->resizer_a.subdev == sd && - pad == RESIZER_PAD_SOURCE) { - max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A; - max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A; - - for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) { - if (fmt->code == resizer_output_formats[i]) - break; - } - /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(resizer_output_formats)) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; - - fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH, - max_out_width); - fmt->width &= ~15; - fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT, - max_out_height); - } else if (&resizer->resizer_b.subdev == sd && - pad == RESIZER_PAD_SOURCE) { - max_out_width = IPIPE_MAX_OUTPUT_WIDTH_B; - max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_B; - - for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) { - if (fmt->code == resizer_output_formats[i]) - break; - } - /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(resizer_output_formats)) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; - - fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH, - max_out_width); - fmt->width &= ~15; - fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT, - max_out_height); - } -} - -/* - * resizer_set_format() - Handle set format by pads subdev method - * @sd: pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int resizer_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - resizer_try_format(sd, cfg, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - return 0; - - if (&resizer->crop_resizer.subdev == sd) { - if (fmt->pad == RESIZER_CROP_PAD_SINK) { - resizer->crop_resizer.formats[fmt->pad] = fmt->format; - } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE && - resizer->crop_resizer.output == RESIZER_A) { - resizer->crop_resizer.formats[fmt->pad] = fmt->format; - resizer->crop_resizer. - formats[RESIZER_CROP_PAD_SOURCE2] = fmt->format; - } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE2 && - resizer->crop_resizer.output2 == RESIZER_B) { - resizer->crop_resizer.formats[fmt->pad] = fmt->format; - resizer->crop_resizer. - formats[RESIZER_CROP_PAD_SOURCE] = fmt->format; - } else { - return -EINVAL; - } - } else if (&resizer->resizer_a.subdev == sd) { - if (fmt->pad == RESIZER_PAD_SINK) - resizer->resizer_a.formats[fmt->pad] = fmt->format; - else if (fmt->pad == RESIZER_PAD_SOURCE) - resizer->resizer_a.formats[fmt->pad] = fmt->format; - else - return -EINVAL; - } else if (&resizer->resizer_b.subdev == sd) { - if (fmt->pad == RESIZER_PAD_SINK) - resizer->resizer_b.formats[fmt->pad] = fmt->format; - else if (fmt->pad == RESIZER_PAD_SOURCE) - resizer->resizer_b.formats[fmt->pad] = fmt->format; - else - return -EINVAL; - } else { - return -EINVAL; - } - - return 0; -} - -/* - * resizer_get_format() - Retrieve the video format on a pad - * @sd: pointer to v4l2 subdev structure. - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int resizer_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct v4l2_mbus_framefmt *format; - - format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - fmt->format = *format; - - return 0; -} - -/* - * resizer_enum_frame_size() - enum frame sizes on pads - * @sd: Pointer to subdevice. - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_frame_size_enum structure. - */ -static int resizer_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - resizer_try_format(sd, cfg, fse->pad, &format, fse->which); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - resizer_try_format(sd, cfg, fse->pad, &format, fse->which); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * resizer_enum_mbus_code() - enum mbus codes for pads - * @sd: Pointer to subdevice. - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - */ -static int resizer_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad == RESIZER_PAD_SINK) { - if (code->index >= ARRAY_SIZE(resizer_input_formats)) - return -EINVAL; - - code->code = resizer_input_formats[code->index]; - } else if (code->pad == RESIZER_PAD_SOURCE) { - if (code->index >= ARRAY_SIZE(resizer_output_formats)) - return -EINVAL; - - code->code = resizer_output_formats[code->index]; - } - - return 0; -} - -/* - * resizer_init_formats() - Initialize formats on all pads - * @sd: Pointer to subdevice. - * @fh: V4L2 subdev file handle. - * - * Initialize all pad formats with default values. Try formats are - * initialized on the file handle. - */ -static int resizer_init_formats(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - __u32 which = V4L2_SUBDEV_FORMAT_TRY; - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct v4l2_subdev_format format; - - if (&resizer->crop_resizer.subdev == sd) { - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_CROP_PAD_SINK; - format.which = which; - format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; - format.format.width = MAX_IN_WIDTH; - format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_CROP_PAD_SOURCE; - format.which = which; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = MAX_IN_WIDTH; - format.format.height = MAX_IN_WIDTH; - resizer_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_CROP_PAD_SOURCE2; - format.which = which; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = MAX_IN_WIDTH; - format.format.height = MAX_IN_WIDTH; - resizer_set_format(sd, fh->pad, &format); - } else if (&resizer->resizer_a.subdev == sd) { - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_PAD_SINK; - format.which = which; - format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; - format.format.width = MAX_IN_WIDTH; - format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_PAD_SOURCE; - format.which = which; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - resizer_set_format(sd, fh->pad, &format); - } else if (&resizer->resizer_b.subdev == sd) { - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_PAD_SINK; - format.which = which; - format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; - format.format.width = MAX_IN_WIDTH; - format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_PAD_SOURCE; - format.which = which; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_B; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_B; - resizer_set_format(sd, fh->pad, &format); - } - - return 0; -} - -/* subdev core operations */ -static const struct v4l2_subdev_core_ops resizer_v4l2_core_ops = { - .ioctl = resizer_ioctl, -}; - -/* subdev internal operations */ -static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = { - .open = resizer_init_formats, -}; - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = { - .s_stream = resizer_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = { - .enum_mbus_code = resizer_enum_mbus_code, - .enum_frame_size = resizer_enum_frame_size, - .get_fmt = resizer_get_format, - .set_fmt = resizer_set_format, -}; - -/* subdev operations */ -static const struct v4l2_subdev_ops resizer_v4l2_ops = { - .core = &resizer_v4l2_core_ops, - .video = &resizer_v4l2_video_ops, - .pad = &resizer_v4l2_pad_ops, -}; - -/* - * Media entity operations - */ - -/* - * resizer_link_setup() - Setup resizer connections - * @entity: Pointer to media entity structure - * @local: Pointer to local pad array - * @remote: Pointer to remote pad array - * @flags: Link flags - * return -EINVAL or zero on success - */ -static int resizer_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output; - u16 ipipe_source = vpfe_dev->vpfe_ipipe.output; - unsigned int index = local->index; - - /* FIXME: this is actually a hack! */ - if (is_media_entity_v4l2_subdev(remote->entity)) - index |= 2 << 16; - - if (&resizer->crop_resizer.subdev == sd) { - switch (index) { - case RESIZER_CROP_PAD_SINK | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->crop_resizer.input = - RESIZER_CROP_INPUT_NONE; - break; - } - - if (resizer->crop_resizer.input != - RESIZER_CROP_INPUT_NONE) - return -EBUSY; - if (ipipeif_source == IPIPEIF_OUTPUT_RESIZER) - resizer->crop_resizer.input = - RESIZER_CROP_INPUT_IPIPEIF; - else if (ipipe_source == IPIPE_OUTPUT_RESIZER) - resizer->crop_resizer.input = - RESIZER_CROP_INPUT_IPIPE; - else - return -EINVAL; - break; - - case RESIZER_CROP_PAD_SOURCE | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->crop_resizer.output = - RESIZER_CROP_OUTPUT_NONE; - break; - } - if (resizer->crop_resizer.output != - RESIZER_CROP_OUTPUT_NONE) - return -EBUSY; - resizer->crop_resizer.output = RESIZER_A; - break; - - case RESIZER_CROP_PAD_SOURCE2 | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->crop_resizer.output2 = - RESIZER_CROP_OUTPUT_NONE; - break; - } - if (resizer->crop_resizer.output2 != - RESIZER_CROP_OUTPUT_NONE) - return -EBUSY; - resizer->crop_resizer.output2 = RESIZER_B; - break; - - default: - return -EINVAL; - } - } else if (&resizer->resizer_a.subdev == sd) { - switch (index) { - case RESIZER_PAD_SINK | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->resizer_a.input = RESIZER_INPUT_NONE; - break; - } - if (resizer->resizer_a.input != RESIZER_INPUT_NONE) - return -EBUSY; - resizer->resizer_a.input = RESIZER_INPUT_CROP_RESIZER; - break; - - case RESIZER_PAD_SOURCE: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->resizer_a.output = RESIZER_OUTPUT_NONE; - break; - } - if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) - return -EBUSY; - resizer->resizer_a.output = RESIZER_OUTPUT_MEMORY; - break; - - default: - return -EINVAL; - } - } else if (&resizer->resizer_b.subdev == sd) { - switch (index) { - case RESIZER_PAD_SINK | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->resizer_b.input = RESIZER_INPUT_NONE; - break; - } - if (resizer->resizer_b.input != RESIZER_INPUT_NONE) - return -EBUSY; - resizer->resizer_b.input = RESIZER_INPUT_CROP_RESIZER; - break; - - case RESIZER_PAD_SOURCE: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->resizer_b.output = RESIZER_OUTPUT_NONE; - break; - } - if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) - return -EBUSY; - resizer->resizer_b.output = RESIZER_OUTPUT_MEMORY; - break; - - default: - return -EINVAL; - } - } else { - return -EINVAL; - } - - return 0; -} - -static const struct media_entity_operations resizer_media_ops = { - .link_setup = resizer_link_setup, -}; - -/* - * vpfe_resizer_unregister_entities() - Unregister entity - * @vpfe_rsz - pointer to resizer subdevice structure. - */ -void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz) -{ - /* unregister video devices */ - vpfe_video_unregister(&vpfe_rsz->resizer_a.video_out); - vpfe_video_unregister(&vpfe_rsz->resizer_b.video_out); - - /* unregister subdev */ - v4l2_device_unregister_subdev(&vpfe_rsz->crop_resizer.subdev); - v4l2_device_unregister_subdev(&vpfe_rsz->resizer_a.subdev); - v4l2_device_unregister_subdev(&vpfe_rsz->resizer_b.subdev); - /* cleanup entity */ - media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity); - media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity); - media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity); -} - -/* - * vpfe_resizer_register_entities() - Register entity - * @resizer - pointer to resizer device. - * @vdev: pointer to v4l2 device structure. - */ -int vpfe_resizer_register_entities(struct vpfe_resizer_device *resizer, - struct v4l2_device *vdev) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - unsigned int flags = 0; - int ret; - - /* Register the crop resizer subdev */ - ret = v4l2_device_register_subdev(vdev, &resizer->crop_resizer.subdev); - if (ret < 0) { - pr_err("Failed to register crop resizer as v4l2-subdev\n"); - return ret; - } - /* Register Resizer-A subdev */ - ret = v4l2_device_register_subdev(vdev, &resizer->resizer_a.subdev); - if (ret < 0) { - pr_err("Failed to register resizer-a as v4l2-subdev\n"); - return ret; - } - /* Register Resizer-B subdev */ - ret = v4l2_device_register_subdev(vdev, &resizer->resizer_b.subdev); - if (ret < 0) { - pr_err("Failed to register resizer-b as v4l2-subdev\n"); - return ret; - } - /* Register video-out device for resizer-a */ - ret = vpfe_video_register(&resizer->resizer_a.video_out, vdev); - if (ret) { - pr_err("Failed to register RSZ-A video-out device\n"); - goto out_video_out2_register; - } - resizer->resizer_a.video_out.vpfe_dev = vpfe_dev; - - /* Register video-out device for resizer-b */ - ret = vpfe_video_register(&resizer->resizer_b.video_out, vdev); - if (ret) { - pr_err("Failed to register RSZ-B video-out device\n"); - goto out_video_out2_register; - } - resizer->resizer_b.video_out.vpfe_dev = vpfe_dev; - - /* create link between Resizer Crop----> Resizer A*/ - ret = media_create_pad_link(&resizer->crop_resizer.subdev.entity, 1, - &resizer->resizer_a.subdev.entity, - 0, flags); - if (ret < 0) - goto out_create_link; - - /* create link between Resizer Crop----> Resizer B*/ - ret = media_create_pad_link(&resizer->crop_resizer.subdev.entity, 2, - &resizer->resizer_b.subdev.entity, - 0, flags); - if (ret < 0) - goto out_create_link; - - /* create link between Resizer A ----> video out */ - ret = media_create_pad_link(&resizer->resizer_a.subdev.entity, 1, - &resizer->resizer_a.video_out.video_dev.entity, 0, flags); - if (ret < 0) - goto out_create_link; - - /* create link between Resizer B ----> video out */ - ret = media_create_pad_link(&resizer->resizer_b.subdev.entity, 1, - &resizer->resizer_b.video_out.video_dev.entity, 0, flags); - if (ret < 0) - goto out_create_link; - - return 0; - -out_create_link: - vpfe_video_unregister(&resizer->resizer_b.video_out); -out_video_out2_register: - vpfe_video_unregister(&resizer->resizer_a.video_out); - v4l2_device_unregister_subdev(&resizer->crop_resizer.subdev); - v4l2_device_unregister_subdev(&resizer->resizer_a.subdev); - v4l2_device_unregister_subdev(&resizer->resizer_b.subdev); - media_entity_cleanup(&resizer->crop_resizer.subdev.entity); - media_entity_cleanup(&resizer->resizer_a.subdev.entity); - media_entity_cleanup(&resizer->resizer_b.subdev.entity); - return ret; -} - -/* - * vpfe_resizer_init() - resizer device initialization. - * @vpfe_rsz - pointer to resizer device - * @pdev: platform device pointer. - */ -int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz, - struct platform_device *pdev) -{ - struct v4l2_subdev *sd = &vpfe_rsz->crop_resizer.subdev; - struct media_pad *pads = &vpfe_rsz->crop_resizer.pads[0]; - struct media_entity *me = &sd->entity; - resource_size_t res_len; - struct resource *res; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 5); - if (!res) - return -ENOENT; - - res_len = resource_size(res); - res = request_mem_region(res->start, res_len, res->name); - if (!res) - return -EBUSY; - - vpfe_rsz->base_addr = ioremap_nocache(res->start, res_len); - if (!vpfe_rsz->base_addr) - return -EBUSY; - - v4l2_subdev_init(sd, &resizer_v4l2_ops); - sd->internal_ops = &resizer_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI RESIZER CROP", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - v4l2_set_subdevdata(sd, vpfe_rsz); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[RESIZER_CROP_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[RESIZER_CROP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - pads[RESIZER_CROP_PAD_SOURCE2].flags = MEDIA_PAD_FL_SOURCE; - - vpfe_rsz->crop_resizer.input = RESIZER_CROP_INPUT_NONE; - vpfe_rsz->crop_resizer.output = RESIZER_CROP_OUTPUT_NONE; - vpfe_rsz->crop_resizer.output2 = RESIZER_CROP_OUTPUT_NONE; - vpfe_rsz->crop_resizer.rsz_device = vpfe_rsz; - me->ops = &resizer_media_ops; - ret = media_entity_pads_init(me, RESIZER_CROP_PADS_NUM, pads); - if (ret) - return ret; - - sd = &vpfe_rsz->resizer_a.subdev; - pads = &vpfe_rsz->resizer_a.pads[0]; - me = &sd->entity; - - v4l2_subdev_init(sd, &resizer_v4l2_ops); - sd->internal_ops = &resizer_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI RESIZER A", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - v4l2_set_subdevdata(sd, vpfe_rsz); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - vpfe_rsz->resizer_a.input = RESIZER_INPUT_NONE; - vpfe_rsz->resizer_a.output = RESIZER_OUTPUT_NONE; - vpfe_rsz->resizer_a.rsz_device = vpfe_rsz; - me->ops = &resizer_media_ops; - ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads); - if (ret) - return ret; - - sd = &vpfe_rsz->resizer_b.subdev; - pads = &vpfe_rsz->resizer_b.pads[0]; - me = &sd->entity; - - v4l2_subdev_init(sd, &resizer_v4l2_ops); - sd->internal_ops = &resizer_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI RESIZER B", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - v4l2_set_subdevdata(sd, vpfe_rsz); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - vpfe_rsz->resizer_b.input = RESIZER_INPUT_NONE; - vpfe_rsz->resizer_b.output = RESIZER_OUTPUT_NONE; - vpfe_rsz->resizer_b.rsz_device = vpfe_rsz; - me->ops = &resizer_media_ops; - ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads); - if (ret) - return ret; - - vpfe_rsz->resizer_a.video_out.ops = &resizer_a_video_ops; - vpfe_rsz->resizer_a.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = vpfe_video_init(&vpfe_rsz->resizer_a.video_out, "RSZ-A"); - if (ret) { - pr_err("Failed to init RSZ video-out device\n"); - return ret; - } - vpfe_rsz->resizer_b.video_out.ops = &resizer_b_video_ops; - vpfe_rsz->resizer_b.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = vpfe_video_init(&vpfe_rsz->resizer_b.video_out, "RSZ-B"); - if (ret) { - pr_err("Failed to init RSZ video-out2 device\n"); - return ret; - } - memset(&vpfe_rsz->config, 0, sizeof(struct resizer_params)); - - return 0; -} - -void -vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz, - struct platform_device *pdev) -{ - struct resource *res; - - iounmap(vpfe_rsz->base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 5); - if (res) - release_mem_region(res->start, - resource_size(res)); -} diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.h b/drivers/staging/media/davinci_vpfe/dm365_resizer.h deleted file mode 100644 index 5e31de96b2c9..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_resizer.h +++ /dev/null @@ -1,241 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#ifndef _DAVINCI_VPFE_DM365_RESIZER_H -#define _DAVINCI_VPFE_DM365_RESIZER_H - -enum resizer_oper_mode { - RESIZER_MODE_CONTINUOUS = 0, - RESIZER_MODE_ONE_SHOT = 1, -}; - -struct f_div_pass { - unsigned int o_hsz; - unsigned int i_hps; - unsigned int h_phs; - unsigned int src_hps; - unsigned int src_hsz; -}; - -#define MAX_PASSES 2 - -struct f_div_param { - unsigned char en; - unsigned int num_passes; - struct f_div_pass pass[MAX_PASSES]; -}; - -/* Resizer Rescale Parameters*/ -struct resizer_scale_param { - bool h_flip; - bool v_flip; - bool cen; - bool yen; - unsigned short i_vps; - unsigned short i_hps; - unsigned short o_vsz; - unsigned short o_hsz; - unsigned short v_phs_y; - unsigned short v_phs_c; - unsigned short v_dif; - /* resize method - Luminance */ - enum vpfe_rsz_intp_t v_typ_y; - /* resize method - Chrominance */ - enum vpfe_rsz_intp_t v_typ_c; - /* vertical lpf intensity - Luminance */ - unsigned char v_lpf_int_y; - /* vertical lpf intensity - Chrominance */ - unsigned char v_lpf_int_c; - unsigned short h_phs; - unsigned short h_dif; - /* resize method - Luminance */ - enum vpfe_rsz_intp_t h_typ_y; - /* resize method - Chrominance */ - enum vpfe_rsz_intp_t h_typ_c; - /* horizontal lpf intensity - Luminance */ - unsigned char h_lpf_int_y; - /* horizontal lpf intensity - Chrominance */ - unsigned char h_lpf_int_c; - bool dscale_en; - enum vpfe_rsz_down_scale_ave_sz h_dscale_ave_sz; - enum vpfe_rsz_down_scale_ave_sz v_dscale_ave_sz; - /* store the calculated frame division parameter */ - struct f_div_param f_div; -}; - -enum resizer_rgb_t { - OUTPUT_32BIT, - OUTPUT_16BIT -}; - -enum resizer_rgb_msk_t { - NOMASK = 0, - MASKLAST2 = 1, -}; - -/* Resizer RGB Conversion Parameters */ -struct resizer_rgb { - bool rgb_en; - enum resizer_rgb_t rgb_typ; - enum resizer_rgb_msk_t rgb_msk0; - enum resizer_rgb_msk_t rgb_msk1; - unsigned int rgb_alpha_val; -}; - -/* Resizer External Memory Parameters */ -struct rsz_ext_mem_param { - unsigned int rsz_sdr_oft_y; - unsigned int rsz_sdr_ptr_s_y; - unsigned int rsz_sdr_ptr_e_y; - unsigned int rsz_sdr_oft_c; - unsigned int rsz_sdr_ptr_s_c; - unsigned int rsz_sdr_ptr_e_c; - /* offset to be added to buffer start when flipping for y/ycbcr */ - unsigned int flip_ofst_y; - /* offset to be added to buffer start when flipping for c */ - unsigned int flip_ofst_c; - /* c offset for YUV 420SP */ - unsigned int c_offset; - /* User Defined Y offset for YUV 420SP or YUV420ILE data */ - unsigned int user_y_ofst; - /* User Defined C offset for YUV 420SP data */ - unsigned int user_c_ofst; -}; - -enum rsz_data_source { - IPIPE_DATA, - IPIPEIF_DATA -}; - -enum rsz_src_img_fmt { - RSZ_IMG_422, - RSZ_IMG_420 -}; - -enum rsz_dpaths_bypass_t { - BYPASS_OFF = 0, - BYPASS_ON = 1, -}; - -struct rsz_common_params { - unsigned int vps; - unsigned int vsz; - unsigned int hps; - unsigned int hsz; - /* 420 or 422 */ - enum rsz_src_img_fmt src_img_fmt; - /* Y or C when src_fmt is 420, 0 - y, 1 - c */ - unsigned char y_c; - /* flip raw or ycbcr */ - unsigned char raw_flip; - /* IPIPE or IPIPEIF data */ - enum rsz_data_source source; - enum rsz_dpaths_bypass_t passthrough; - unsigned char yuv_y_min; - unsigned char yuv_y_max; - unsigned char yuv_c_min; - unsigned char yuv_c_max; - bool rsz_seq_crv; - enum vpfe_chr_pos out_chr_pos; -}; - -struct resizer_params { - enum resizer_oper_mode oper_mode; - struct rsz_common_params rsz_common; - struct resizer_scale_param rsz_rsc_param[2]; - struct resizer_rgb rsz2rgb[2]; - struct rsz_ext_mem_param ext_mem_param[2]; - bool rsz_en[2]; - struct vpfe_rsz_config_params user_config; -}; - -#define ENABLE 1 -#define DISABLE (!ENABLE) - -#define RESIZER_CROP_PAD_SINK 0 -#define RESIZER_CROP_PAD_SOURCE 1 -#define RESIZER_CROP_PAD_SOURCE2 2 - -#define RESIZER_CROP_PADS_NUM 3 - -enum resizer_crop_input_entity { - RESIZER_CROP_INPUT_NONE = 0, - RESIZER_CROP_INPUT_IPIPEIF = 1, - RESIZER_CROP_INPUT_IPIPE = 2, -}; - -enum resizer_crop_output_entity { - RESIZER_CROP_OUTPUT_NONE, - RESIZER_A, - RESIZER_B, -}; - -struct dm365_crop_resizer_device { - struct v4l2_subdev subdev; - struct media_pad pads[RESIZER_CROP_PADS_NUM]; - struct v4l2_mbus_framefmt formats[RESIZER_CROP_PADS_NUM]; - enum resizer_crop_input_entity input; - enum resizer_crop_output_entity output; - enum resizer_crop_output_entity output2; - struct vpfe_resizer_device *rsz_device; -}; - -#define RESIZER_PAD_SINK 0 -#define RESIZER_PAD_SOURCE 1 - -#define RESIZER_PADS_NUM 2 - -enum resizer_input_entity { - RESIZER_INPUT_NONE = 0, - RESIZER_INPUT_CROP_RESIZER = 1, -}; - -enum resizer_output_entity { - RESIZER_OUTPUT_NONE = 0, - RESIZER_OUTPUT_MEMORY = 1, -}; - -struct dm365_resizer_device { - struct v4l2_subdev subdev; - struct media_pad pads[RESIZER_PADS_NUM]; - struct v4l2_mbus_framefmt formats[RESIZER_PADS_NUM]; - enum resizer_input_entity input; - enum resizer_output_entity output; - struct vpfe_video_device video_out; - struct vpfe_resizer_device *rsz_device; -}; - -struct vpfe_resizer_device { - struct dm365_crop_resizer_device crop_resizer; - struct dm365_resizer_device resizer_a; - struct dm365_resizer_device resizer_b; - struct resizer_params config; - void __iomem *base_addr; -}; - -int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz, - struct platform_device *pdev); -int vpfe_resizer_register_entities(struct vpfe_resizer_device *vpfe_rsz, - struct v4l2_device *v4l2_dev); -void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz); -void vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz, - struct platform_device *pdev); -void vpfe_resizer_buffer_isr(struct vpfe_resizer_device *resizer); -void vpfe_resizer_dma_isr(struct vpfe_resizer_device *resizer); - -#endif /* _DAVINCI_VPFE_DM365_RESIZER_H */ diff --git a/drivers/staging/media/davinci_vpfe/vpfe.h b/drivers/staging/media/davinci_vpfe/vpfe.h deleted file mode 100644 index 1f8e011fc162..000000000000 --- a/drivers/staging/media/davinci_vpfe/vpfe.h +++ /dev/null @@ -1,83 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#ifndef _VPFE_H -#define _VPFE_H - -#ifdef __KERNEL__ -#include <linux/v4l2-subdev.h> -#include <linux/clk.h> -#include <linux/i2c.h> - -#include <media/davinci/vpfe_types.h> - -#define CAPTURE_DRV_NAME "vpfe-capture" - -struct vpfe_route { - __u32 input; - __u32 output; -}; - -enum vpfe_subdev_id { - VPFE_SUBDEV_TVP5146 = 1, - VPFE_SUBDEV_MT9T031 = 2, - VPFE_SUBDEV_TVP7002 = 3, - VPFE_SUBDEV_MT9P031 = 4, -}; - -struct vpfe_ext_subdev_info { - /* v4l2 subdev */ - struct v4l2_subdev *subdev; - /* Sub device module name */ - char module_name[32]; - /* Sub device group id */ - int grp_id; - /* Number of inputs supported */ - int num_inputs; - /* inputs available at the sub device */ - struct v4l2_input *inputs; - /* Sub dev routing information for each input */ - struct vpfe_route *routes; - /* ccdc bus/interface configuration */ - struct vpfe_hw_if_param ccdc_if_params; - /* i2c subdevice board info */ - struct i2c_board_info board_info; - /* Is this a camera sub device ? */ - unsigned is_camera:1; - /* check if sub dev supports routing */ - unsigned can_route:1; - /* registered ? */ - unsigned registered:1; -}; - -struct vpfe_config { - /* Number of sub devices connected to vpfe */ - int num_subdevs; - /* information about each subdev */ - struct vpfe_ext_subdev_info *sub_devs; - /* evm card info */ - char *card_name; - /* setup function for the input path */ - int (*setup_input)(enum vpfe_subdev_id id); - /* number of clocks */ - int num_clocks; - /* clocks used for vpfe capture */ - char *clocks[]; -}; -#endif -#endif diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c deleted file mode 100644 index 9dc28ffe38d5..000000000000 --- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c +++ /dev/null @@ -1,716 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - * - * - * Driver name : VPFE Capture driver - * VPFE Capture driver allows applications to capture and stream video - * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as - * TVP5146 or Raw Bayer RGB image data from an image sensor - * such as Microns' MT9T001, MT9T031 etc. - * - * These SoCs have, in common, a Video Processing Subsystem (VPSS) that - * consists of a Video Processing Front End (VPFE) for capturing - * video/raw image data and Video Processing Back End (VPBE) for displaying - * YUV data through an in-built analog encoder or Digital LCD port. This - * driver is for capture through VPFE. A typical EVM using these SoCs have - * following high level configuration. - * - * decoder(TVP5146/ YUV/ - * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF) - * data input | | - * V | - * SDRAM | - * V - * Image Processor - * | - * V - * SDRAM - * The data flow happens from a decoder connected to the VPFE over a - * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface - * and to the input of VPFE through an optional MUX (if more inputs are - * to be interfaced on the EVM). The input data is first passed through - * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC - * does very little or no processing on YUV data and does pre-process Raw - * Bayer RGB data through modules such as Defect Pixel Correction (DFC) - * Color Space Conversion (CSC), data gain/offset etc. After this, data - * can be written to SDRAM or can be connected to the image processing - * block such as IPIPE (on DM355/DM365 only). - * - * Features supported - * - MMAP IO - * - USERPTR IO - * - Capture using TVP5146 over BT.656 - * - Support for interfacing decoders using sub device model - * - Work with DM365 or DM355 or DM6446 CCDC to do Raw Bayer - * RGB/YUV data capture to SDRAM. - * - Chaining of Image Processor - * - SINGLE-SHOT mode - */ - -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/slab.h> - -#include "vpfe.h" -#include "vpfe_mc_capture.h" - -static bool debug; -static bool interface; - -module_param(interface, bool, 0444); -module_param(debug, bool, 0644); - -/* - * VPFE capture can be used for capturing video such as from TVP5146 or TVP7002 - * and for capture raw bayer data from camera sensors such as mt9p031. At this - * point there is problem in co-existence of mt9p031 and tvp5146 due to i2c - * address collision. So set the variable below from bootargs to do either video - * capture or camera capture. - * interface = 0 - video capture (from TVP514x or such), - * interface = 1 - Camera capture (from mt9p031 or such) - * Re-visit this when we fix the co-existence issue - */ -MODULE_PARM_DESC(interface, "interface 0-1 (default:0)"); -MODULE_PARM_DESC(debug, "Debug level 0-1"); - -MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Texas Instruments"); - -/* map mbus_fmt to pixelformat */ -void mbus_to_pix(const struct v4l2_mbus_framefmt *mbus, - struct v4l2_pix_format *pix) -{ - switch (mbus->code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - pix->pixelformat = V4L2_PIX_FMT_UYVY; - pix->bytesperline = pix->width * 2; - break; - - case MEDIA_BUS_FMT_YUYV8_2X8: - pix->pixelformat = V4L2_PIX_FMT_YUYV; - pix->bytesperline = pix->width * 2; - break; - - case MEDIA_BUS_FMT_YUYV10_1X20: - pix->pixelformat = V4L2_PIX_FMT_UYVY; - pix->bytesperline = pix->width * 2; - break; - - case MEDIA_BUS_FMT_SGRBG12_1X12: - pix->pixelformat = V4L2_PIX_FMT_SBGGR16; - pix->bytesperline = pix->width * 2; - break; - - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - pix->pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8; - pix->bytesperline = pix->width; - break; - - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - pix->pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8; - pix->bytesperline = pix->width; - break; - - case MEDIA_BUS_FMT_YDYUYDYV8_1X16: - pix->pixelformat = V4L2_PIX_FMT_NV12; - pix->bytesperline = pix->width; - break; - - case MEDIA_BUS_FMT_Y8_1X8: - pix->pixelformat = V4L2_PIX_FMT_GREY; - pix->bytesperline = pix->width; - break; - - case MEDIA_BUS_FMT_UV8_1X8: - pix->pixelformat = V4L2_PIX_FMT_UV8; - pix->bytesperline = pix->width; - break; - - default: - pr_err("Invalid mbus code set\n"); - } - /* pitch should be 32 bytes aligned */ - pix->bytesperline = ALIGN(pix->bytesperline, 32); - if (pix->pixelformat == V4L2_PIX_FMT_NV12) - pix->sizeimage = pix->bytesperline * pix->height + - ((pix->bytesperline * pix->height) >> 1); - else - pix->sizeimage = pix->bytesperline * pix->height; -} - -/* ISR for VINT0*/ -static irqreturn_t vpfe_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__); - vpfe_isif_buffer_isr(&vpfe_dev->vpfe_isif); - vpfe_resizer_buffer_isr(&vpfe_dev->vpfe_resizer); - return IRQ_HANDLED; -} - -/* vpfe_vdint1_isr() - isr handler for VINT1 interrupt */ -static irqreturn_t vpfe_vdint1_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__); - vpfe_isif_vidint1_isr(&vpfe_dev->vpfe_isif); - return IRQ_HANDLED; -} - -/* vpfe_imp_dma_isr() - ISR for ipipe dma completion */ -static irqreturn_t vpfe_imp_dma_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__); - vpfe_ipipeif_ss_buffer_isr(&vpfe_dev->vpfe_ipipeif); - vpfe_resizer_dma_isr(&vpfe_dev->vpfe_resizer); - return IRQ_HANDLED; -} - -/* - * vpfe_disable_clock() - Disable clocks for vpfe capture driver - * @vpfe_dev - ptr to vpfe capture device - * - * Disables clocks defined in vpfe configuration. The function - * assumes that at least one clock is to be defined which is - * true as of now. - */ -static void vpfe_disable_clock(struct vpfe_device *vpfe_dev) -{ - struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; - int i; - - for (i = 0; i < vpfe_cfg->num_clocks; i++) { - clk_disable_unprepare(vpfe_dev->clks[i]); - clk_put(vpfe_dev->clks[i]); - } - kzfree(vpfe_dev->clks); - v4l2_info(vpfe_dev->pdev->driver, "vpfe capture clocks disabled\n"); -} - -/* - * vpfe_enable_clock() - Enable clocks for vpfe capture driver - * @vpfe_dev - ptr to vpfe capture device - * - * Enables clocks defined in vpfe configuration. The function - * assumes that at least one clock is to be defined which is - * true as of now. - */ -static int vpfe_enable_clock(struct vpfe_device *vpfe_dev) -{ - struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; - int ret = -EFAULT; - int i; - - if (!vpfe_cfg->num_clocks) - return 0; - - vpfe_dev->clks = kcalloc(vpfe_cfg->num_clocks, - sizeof(*vpfe_dev->clks), GFP_KERNEL); - if (!vpfe_dev->clks) - return -ENOMEM; - - for (i = 0; i < vpfe_cfg->num_clocks; i++) { - if (vpfe_cfg->clocks[i] == NULL) { - v4l2_err(vpfe_dev->pdev->driver, - "clock %s is not defined in vpfe config\n", - vpfe_cfg->clocks[i]); - goto out; - } - - vpfe_dev->clks[i] = - clk_get(vpfe_dev->pdev, vpfe_cfg->clocks[i]); - if (IS_ERR(vpfe_dev->clks[i])) { - v4l2_err(vpfe_dev->pdev->driver, - "Failed to get clock %s\n", - vpfe_cfg->clocks[i]); - goto out; - } - - if (clk_prepare_enable(vpfe_dev->clks[i])) { - v4l2_err(vpfe_dev->pdev->driver, - "vpfe clock %s not enabled\n", - vpfe_cfg->clocks[i]); - goto out; - } - - v4l2_info(vpfe_dev->pdev->driver, "vpss clock %s enabled", - vpfe_cfg->clocks[i]); - } - - return 0; -out: - for (i = 0; i < vpfe_cfg->num_clocks; i++) - if (!IS_ERR(vpfe_dev->clks[i])) { - clk_disable_unprepare(vpfe_dev->clks[i]); - clk_put(vpfe_dev->clks[i]); - } - - v4l2_err(vpfe_dev->pdev->driver, "Failed to enable clocks\n"); - kzfree(vpfe_dev->clks); - - return ret; -} - -/* - * vpfe_detach_irq() - Detach IRQs for vpfe capture driver - * @vpfe_dev - ptr to vpfe capture device - * - * Detach all IRQs defined in vpfe configuration. - */ -static void vpfe_detach_irq(struct vpfe_device *vpfe_dev) -{ - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); - free_irq(vpfe_dev->ccdc_irq1, vpfe_dev); - free_irq(vpfe_dev->imp_dma_irq, vpfe_dev); -} - -/* - * vpfe_attach_irq() - Attach IRQs for vpfe capture driver - * @vpfe_dev - ptr to vpfe capture device - * - * Attach all IRQs defined in vpfe configuration. - */ -static int vpfe_attach_irq(struct vpfe_device *vpfe_dev) -{ - int ret; - - ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, 0, - "vpfe_capture0", vpfe_dev); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error: requesting VINT0 interrupt\n"); - return ret; - } - - ret = request_irq(vpfe_dev->ccdc_irq1, vpfe_vdint1_isr, 0, - "vpfe_capture1", vpfe_dev); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error: requesting VINT1 interrupt\n"); - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); - return ret; - } - - ret = request_irq(vpfe_dev->imp_dma_irq, vpfe_imp_dma_isr, - 0, "Imp_Sdram_Irq", vpfe_dev); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error: requesting IMP IRQ interrupt\n"); - free_irq(vpfe_dev->ccdc_irq1, vpfe_dev); - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); - return ret; - } - - return 0; -} - -/* - * register_i2c_devices() - register all i2c v4l2 subdevs - * @vpfe_dev - ptr to vpfe capture device - * - * register all i2c v4l2 subdevs - */ -static int register_i2c_devices(struct vpfe_device *vpfe_dev) -{ - struct vpfe_ext_subdev_info *sdinfo; - struct vpfe_config *vpfe_cfg; - struct i2c_adapter *i2c_adap; - unsigned int num_subdevs; - int ret; - int i; - int k; - - vpfe_cfg = vpfe_dev->cfg; - i2c_adap = i2c_get_adapter(1); - num_subdevs = vpfe_cfg->num_subdevs; - vpfe_dev->sd = - kcalloc(num_subdevs, sizeof(struct v4l2_subdev *), - GFP_KERNEL); - if (!vpfe_dev->sd) - return -ENOMEM; - - for (i = 0, k = 0; i < num_subdevs; i++) { - sdinfo = &vpfe_cfg->sub_devs[i]; - /* - * register subdevices based on interface setting. Currently - * tvp5146 and mt9p031 cannot co-exists due to i2c address - * conflicts. So only one of them is registered. Re-visit this - * once we have support for i2c switch handling in i2c driver - * framework - */ - if (interface == sdinfo->is_camera) { - /* setup input path */ - if (vpfe_cfg->setup_input && - vpfe_cfg->setup_input(sdinfo->grp_id) < 0) { - ret = -EFAULT; - v4l2_info(&vpfe_dev->v4l2_dev, - "could not setup input for %s\n", - sdinfo->module_name); - goto probe_sd_out; - } - /* Load up the subdevice */ - vpfe_dev->sd[k] = - v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, - i2c_adap, &sdinfo->board_info, - NULL); - if (vpfe_dev->sd[k]) { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s registered\n", - sdinfo->module_name); - - vpfe_dev->sd[k]->grp_id = sdinfo->grp_id; - k++; - - sdinfo->registered = 1; - } - } else { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s is not registered\n", - sdinfo->module_name); - } - } - vpfe_dev->num_ext_subdevs = k; - - return 0; - -probe_sd_out: - kzfree(vpfe_dev->sd); - - return ret; -} - -/* - * vpfe_register_entities() - register all v4l2 subdevs and media entities - * @vpfe_dev - ptr to vpfe capture device - * - * register all v4l2 subdevs, media entities, and creates links - * between entities - */ -static int vpfe_register_entities(struct vpfe_device *vpfe_dev) -{ - unsigned int flags = 0; - int ret; - int i; - - /* register i2c devices first */ - ret = register_i2c_devices(vpfe_dev); - if (ret) - return ret; - - /* register rest of the sub-devs */ - ret = vpfe_isif_register_entities(&vpfe_dev->vpfe_isif, - &vpfe_dev->v4l2_dev); - if (ret) - return ret; - - ret = vpfe_ipipeif_register_entities(&vpfe_dev->vpfe_ipipeif, - &vpfe_dev->v4l2_dev); - if (ret) - goto out_isif_register; - - ret = vpfe_ipipe_register_entities(&vpfe_dev->vpfe_ipipe, - &vpfe_dev->v4l2_dev); - if (ret) - goto out_ipipeif_register; - - ret = vpfe_resizer_register_entities(&vpfe_dev->vpfe_resizer, - &vpfe_dev->v4l2_dev); - if (ret) - goto out_ipipe_register; - - /* create links now, starting with external(i2c) entities */ - for (i = 0; i < vpfe_dev->num_ext_subdevs; i++) - /* - * if entity has no pads (ex: amplifier), - * can't establish link - */ - if (vpfe_dev->sd[i]->entity.num_pads) { - ret = media_create_pad_link(&vpfe_dev->sd[i]->entity, - 0, &vpfe_dev->vpfe_isif.subdev.entity, - 0, flags); - if (ret < 0) - goto out_resizer_register; - } - - ret = media_create_pad_link(&vpfe_dev->vpfe_isif.subdev.entity, 1, - &vpfe_dev->vpfe_ipipeif.subdev.entity, - 0, flags); - if (ret < 0) - goto out_resizer_register; - - ret = media_create_pad_link(&vpfe_dev->vpfe_ipipeif.subdev.entity, 1, - &vpfe_dev->vpfe_ipipe.subdev.entity, - 0, flags); - if (ret < 0) - goto out_resizer_register; - - ret = media_create_pad_link(&vpfe_dev->vpfe_ipipe.subdev.entity, - 1, &vpfe_dev->vpfe_resizer.crop_resizer.subdev.entity, - 0, flags); - if (ret < 0) - goto out_resizer_register; - - ret = media_create_pad_link(&vpfe_dev->vpfe_ipipeif.subdev.entity, 1, - &vpfe_dev->vpfe_resizer.crop_resizer.subdev.entity, - 0, flags); - if (ret < 0) - goto out_resizer_register; - - ret = v4l2_device_register_subdev_nodes(&vpfe_dev->v4l2_dev); - if (ret < 0) - goto out_resizer_register; - - return 0; - -out_resizer_register: - vpfe_resizer_unregister_entities(&vpfe_dev->vpfe_resizer); -out_ipipe_register: - vpfe_ipipe_unregister_entities(&vpfe_dev->vpfe_ipipe); -out_ipipeif_register: - vpfe_ipipeif_unregister_entities(&vpfe_dev->vpfe_ipipeif); -out_isif_register: - vpfe_isif_unregister_entities(&vpfe_dev->vpfe_isif); - - return ret; -} - -/* - * vpfe_unregister_entities() - unregister all v4l2 subdevs and media entities - * @vpfe_dev - ptr to vpfe capture device - * - * unregister all v4l2 subdevs and media entities - */ -static void vpfe_unregister_entities(struct vpfe_device *vpfe_dev) -{ - vpfe_isif_unregister_entities(&vpfe_dev->vpfe_isif); - vpfe_ipipeif_unregister_entities(&vpfe_dev->vpfe_ipipeif); - vpfe_ipipe_unregister_entities(&vpfe_dev->vpfe_ipipe); - vpfe_resizer_unregister_entities(&vpfe_dev->vpfe_resizer); -} - -/* - * vpfe_cleanup_modules() - cleanup all non-i2c v4l2 subdevs - * @vpfe_dev - ptr to vpfe capture device - * @pdev - pointer to platform device - * - * cleanup all v4l2 subdevs - */ -static void vpfe_cleanup_modules(struct vpfe_device *vpfe_dev, - struct platform_device *pdev) -{ - vpfe_isif_cleanup(&vpfe_dev->vpfe_isif, pdev); - vpfe_ipipeif_cleanup(&vpfe_dev->vpfe_ipipeif, pdev); - vpfe_ipipe_cleanup(&vpfe_dev->vpfe_ipipe, pdev); - vpfe_resizer_cleanup(&vpfe_dev->vpfe_resizer, pdev); -} - -/* - * vpfe_initialize_modules() - initialize all non-i2c v4l2 subdevs - * @vpfe_dev - ptr to vpfe capture device - * @pdev - pointer to platform device - * - * initialize all v4l2 subdevs and media entities - */ -static int vpfe_initialize_modules(struct vpfe_device *vpfe_dev, - struct platform_device *pdev) -{ - int ret; - - ret = vpfe_isif_init(&vpfe_dev->vpfe_isif, pdev); - if (ret) - return ret; - - ret = vpfe_ipipeif_init(&vpfe_dev->vpfe_ipipeif, pdev); - if (ret) - goto out_isif_init; - - ret = vpfe_ipipe_init(&vpfe_dev->vpfe_ipipe, pdev); - if (ret) - goto out_ipipeif_init; - - ret = vpfe_resizer_init(&vpfe_dev->vpfe_resizer, pdev); - if (ret) - goto out_ipipe_init; - - return 0; - -out_ipipe_init: - vpfe_ipipe_cleanup(&vpfe_dev->vpfe_ipipe, pdev); -out_ipipeif_init: - vpfe_ipipeif_cleanup(&vpfe_dev->vpfe_ipipeif, pdev); -out_isif_init: - vpfe_isif_cleanup(&vpfe_dev->vpfe_isif, pdev); - - return ret; -} - -/* - * vpfe_probe() : vpfe probe function - * @pdev: platform device pointer - * - * This function creates device entries by register itself to the V4L2 driver - * and initializes fields of each device objects - */ -static int vpfe_probe(struct platform_device *pdev) -{ - struct vpfe_device *vpfe_dev; - struct resource *res1; - int ret = -ENOMEM; - - vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL); - if (!vpfe_dev) - return ret; - - if (pdev->dev.platform_data == NULL) { - v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - - vpfe_dev->cfg = pdev->dev.platform_data; - if (vpfe_dev->cfg->card_name == NULL || - vpfe_dev->cfg->sub_devs == NULL) { - v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - - /* Get VINT0 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT0\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - vpfe_dev->ccdc_irq0 = res1->start; - - /* Get VINT1 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT1\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - vpfe_dev->ccdc_irq1 = res1->start; - - /* Get DMA irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 2); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for DMA\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - vpfe_dev->imp_dma_irq = res1->start; - - vpfe_dev->pdev = &pdev->dev; - - /* enable vpss clocks */ - ret = vpfe_enable_clock(vpfe_dev); - if (ret) - goto probe_free_dev_mem; - - ret = vpfe_initialize_modules(vpfe_dev, pdev); - if (ret) - goto probe_disable_clock; - - vpfe_dev->media_dev.dev = vpfe_dev->pdev; - strscpy((char *)&vpfe_dev->media_dev.model, "davinci-media", - sizeof(vpfe_dev->media_dev.model)); - - ret = media_device_register(&vpfe_dev->media_dev); - if (ret) { - v4l2_err(pdev->dev.driver, - "Unable to register media device.\n"); - goto probe_out_entities_cleanup; - } - - vpfe_dev->v4l2_dev.mdev = &vpfe_dev->media_dev; - ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); - if (ret) { - v4l2_err(pdev->dev.driver, "Unable to register v4l2 device.\n"); - goto probe_out_media_unregister; - } - - v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); - /* set the driver data in platform device */ - platform_set_drvdata(pdev, vpfe_dev); - /* register subdevs/entities */ - ret = vpfe_register_entities(vpfe_dev); - if (ret) - goto probe_out_v4l2_unregister; - - ret = vpfe_attach_irq(vpfe_dev); - if (ret) - goto probe_out_entities_unregister; - - return 0; - -probe_out_entities_unregister: - vpfe_unregister_entities(vpfe_dev); - kzfree(vpfe_dev->sd); -probe_out_v4l2_unregister: - v4l2_device_unregister(&vpfe_dev->v4l2_dev); -probe_out_media_unregister: - media_device_unregister(&vpfe_dev->media_dev); -probe_out_entities_cleanup: - vpfe_cleanup_modules(vpfe_dev, pdev); -probe_disable_clock: - vpfe_disable_clock(vpfe_dev); -probe_free_dev_mem: - kzfree(vpfe_dev); - - return ret; -} - -/* - * vpfe_remove : This function un-registers device from V4L2 driver - */ -static int vpfe_remove(struct platform_device *pdev) -{ - struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); - - v4l2_info(pdev->dev.driver, "%s\n", __func__); - - kzfree(vpfe_dev->sd); - vpfe_detach_irq(vpfe_dev); - vpfe_unregister_entities(vpfe_dev); - vpfe_cleanup_modules(vpfe_dev, pdev); - v4l2_device_unregister(&vpfe_dev->v4l2_dev); - media_device_unregister(&vpfe_dev->media_dev); - vpfe_disable_clock(vpfe_dev); - kzfree(vpfe_dev); - - return 0; -} - -static struct platform_driver vpfe_driver = { - .driver = { - .name = CAPTURE_DRV_NAME, - }, - .probe = vpfe_probe, - .remove = vpfe_remove, -}; - -module_platform_driver(vpfe_driver); diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h deleted file mode 100644 index fe4a421b5dba..000000000000 --- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#ifndef _DAVINCI_VPFE_MC_CAPTURE_H -#define _DAVINCI_VPFE_MC_CAPTURE_H - -#include "dm365_ipipe.h" -#include "dm365_ipipeif.h" -#include "dm365_isif.h" -#include "dm365_resizer.h" -#include "vpfe_video.h" - -#define VPFE_MAJOR_RELEASE 0 -#define VPFE_MINOR_RELEASE 0 -#define VPFE_BUILD 1 -#define VPFE_CAPTURE_VERSION_CODE ((VPFE_MAJOR_RELEASE << 16) | \ - (VPFE_MINOR_RELEASE << 8) | \ - VPFE_BUILD) - -/* IPIPE hardware limits */ -#define IPIPE_MAX_OUTPUT_WIDTH_A 2176 -#define IPIPE_MAX_OUTPUT_WIDTH_B 640 - -/* Based on max resolution supported. QXGA */ -#define IPIPE_MAX_OUTPUT_HEIGHT_A 1536 -/* Based on max resolution supported. VGA */ -#define IPIPE_MAX_OUTPUT_HEIGHT_B 480 - -#define to_vpfe_device(ptr_module) \ - container_of(ptr_module, struct vpfe_device, vpfe_##ptr_module) -#define to_device(ptr_module) \ - (to_vpfe_device(ptr_module)->dev) - -struct vpfe_device { - /* external registered sub devices */ - struct v4l2_subdev **sd; - /* number of registered external subdevs */ - unsigned int num_ext_subdevs; - /* vpfe cfg */ - struct vpfe_config *cfg; - /* clock ptrs for vpfe capture */ - struct clk **clks; - /* V4l2 device */ - struct v4l2_device v4l2_dev; - /* parent device */ - struct device *pdev; - /* IRQ number for DMA transfer completion at the image processor */ - unsigned int imp_dma_irq; - /* CCDC IRQs used when CCDC/ISIF output to SDRAM */ - unsigned int ccdc_irq0; - unsigned int ccdc_irq1; - /* media device */ - struct media_device media_dev; - /* ccdc subdevice */ - struct vpfe_isif_device vpfe_isif; - /* ipipeif subdevice */ - struct vpfe_ipipeif_device vpfe_ipipeif; - /* ipipe subdevice */ - struct vpfe_ipipe_device vpfe_ipipe; - /* resizer subdevice */ - struct vpfe_resizer_device vpfe_resizer; -}; - -/* File handle structure */ -struct vpfe_fh { - struct v4l2_fh vfh; - struct vpfe_video_device *video; - /* Indicates whether this file handle is doing IO */ - u8 io_allowed; -}; - -void mbus_to_pix(const struct v4l2_mbus_framefmt *mbus, - struct v4l2_pix_format *pix); - -#endif /* _DAVINCI_VPFE_MC_CAPTURE_H */ diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c deleted file mode 100644 index ab6bc452d9f6..000000000000 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ /dev/null @@ -1,1646 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#include <linux/module.h> -#include <linux/slab.h> - -#include <media/v4l2-ioctl.h> - -#include "vpfe.h" -#include "vpfe_mc_capture.h" - -static int debug; - -/* get v4l2 subdev pointer to external subdev which is active */ -static struct media_entity *vpfe_get_input_entity - (struct vpfe_video_device *video) -{ - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct media_pad *remote; - - remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]); - if (!remote) { - pr_err("Invalid media connection to isif/ccdc\n"); - return NULL; - } - return remote->entity; -} - -/* updates external subdev(sensor/decoder) which is active */ -static int vpfe_update_current_ext_subdev(struct vpfe_video_device *video) -{ - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_config *vpfe_cfg; - struct v4l2_subdev *subdev; - struct media_pad *remote; - int i; - - remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]); - if (!remote) { - pr_err("Invalid media connection to isif/ccdc\n"); - return -EINVAL; - } - - subdev = media_entity_to_v4l2_subdev(remote->entity); - vpfe_cfg = vpfe_dev->pdev->platform_data; - for (i = 0; i < vpfe_cfg->num_subdevs; i++) { - if (!strcmp(vpfe_cfg->sub_devs[i].module_name, subdev->name)) { - video->current_ext_subdev = &vpfe_cfg->sub_devs[i]; - break; - } - } - - /* if user not linked decoder/sensor to isif/ccdc */ - if (i == vpfe_cfg->num_subdevs) { - pr_err("Invalid media chain connection to isif/ccdc\n"); - return -EINVAL; - } - /* find the v4l2 subdev pointer */ - for (i = 0; i < vpfe_dev->num_ext_subdevs; i++) { - if (!strcmp(video->current_ext_subdev->module_name, - vpfe_dev->sd[i]->name)) - video->current_ext_subdev->subdev = vpfe_dev->sd[i]; - } - return 0; -} - -/* get the subdev which is connected to the output video node */ -static struct v4l2_subdev * -vpfe_video_remote_subdev(struct vpfe_video_device *video, u32 *pad) -{ - struct media_pad *remote = media_entity_remote_pad(&video->pad); - - if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) - return NULL; - if (pad) - *pad = remote->index; - return media_entity_to_v4l2_subdev(remote->entity); -} - -/* get the format set at output pad of the adjacent subdev */ -static int -__vpfe_video_get_format(struct vpfe_video_device *video, - struct v4l2_format *format) -{ - struct v4l2_subdev_format fmt; - struct v4l2_subdev *subdev; - struct media_pad *remote; - u32 pad; - int ret; - - subdev = vpfe_video_remote_subdev(video, &pad); - if (!subdev) - return -EINVAL; - - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - remote = media_entity_remote_pad(&video->pad); - fmt.pad = remote->index; - - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); - if (ret == -ENOIOCTLCMD) - return -EINVAL; - - format->type = video->type; - /* convert mbus_format to v4l2_format */ - v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); - mbus_to_pix(&fmt.format, &format->fmt.pix); - - return 0; -} - -/* make a note of pipeline details */ -static int vpfe_prepare_pipeline(struct vpfe_video_device *video) -{ - struct media_graph graph; - struct media_entity *entity = &video->video_dev.entity; - struct media_device *mdev = entity->graph_obj.mdev; - struct vpfe_pipeline *pipe = &video->pipe; - struct vpfe_video_device *far_end = NULL; - int ret; - - pipe->input_num = 0; - pipe->output_num = 0; - - if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - pipe->inputs[pipe->input_num++] = video; - else - pipe->outputs[pipe->output_num++] = video; - - mutex_lock(&mdev->graph_mutex); - ret = media_graph_walk_init(&graph, mdev); - if (ret) { - mutex_unlock(&mdev->graph_mutex); - return -ENOMEM; - } - media_graph_walk_start(&graph, entity); - while ((entity = media_graph_walk_next(&graph))) { - if (entity == &video->video_dev.entity) - continue; - if (!is_media_entity_v4l2_video_device(entity)) - continue; - far_end = to_vpfe_video(media_entity_to_video_device(entity)); - if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - pipe->inputs[pipe->input_num++] = far_end; - else - pipe->outputs[pipe->output_num++] = far_end; - } - media_graph_walk_cleanup(&graph); - mutex_unlock(&mdev->graph_mutex); - - return 0; -} - -/* update pipe state selected by user */ -static int vpfe_update_pipe_state(struct vpfe_video_device *video) -{ - struct vpfe_pipeline *pipe = &video->pipe; - int ret; - - ret = vpfe_prepare_pipeline(video); - if (ret) - return ret; - - /* - * Find out if there is any input video - * if yes, it is single shot. - */ - if (pipe->input_num == 0) { - pipe->state = VPFE_PIPELINE_STREAM_CONTINUOUS; - ret = vpfe_update_current_ext_subdev(video); - if (ret) { - pr_err("Invalid external subdev\n"); - return ret; - } - } else { - pipe->state = VPFE_PIPELINE_STREAM_SINGLESHOT; - } - video->initialized = 1; - video->skip_frame_count = 1; - video->skip_frame_count_init = 1; - return 0; -} - -/* checks whether pipeline is ready for enabling */ -int vpfe_video_is_pipe_ready(struct vpfe_pipeline *pipe) -{ - int i; - - for (i = 0; i < pipe->input_num; i++) - if (!pipe->inputs[i]->started || - pipe->inputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED) - return 0; - for (i = 0; i < pipe->output_num; i++) - if (!pipe->outputs[i]->started || - pipe->outputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED) - return 0; - return 1; -} - -/* - * Validate a pipeline by checking both ends of all links for format - * discrepancies. - * - * Return 0 if all formats match, or -EPIPE if at least one link is found with - * different formats on its two ends. - */ -static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe) -{ - struct v4l2_subdev_format fmt_source; - struct v4l2_subdev_format fmt_sink; - struct v4l2_subdev *subdev; - struct media_pad *pad; - int ret; - - /* - * Should not matter if it is output[0] or 1 as - * the general ideas is to traverse backwards and - * the fact that the out video node always has the - * format of the connected pad. - */ - subdev = vpfe_video_remote_subdev(pipe->outputs[0], NULL); - if (!subdev) - return -EPIPE; - - while (1) { - /* Retrieve the sink format */ - pad = &subdev->entity.pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - - fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE; - fmt_sink.pad = pad->index; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, - &fmt_sink); - - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - - /* Retrieve the source format */ - pad = media_entity_remote_pad(pad); - if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) - break; - - subdev = media_entity_to_v4l2_subdev(pad->entity); - - fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE; - fmt_source.pad = pad->index; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source); - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - - /* Check if the two ends match */ - if (fmt_source.format.code != fmt_sink.format.code || - fmt_source.format.width != fmt_sink.format.width || - fmt_source.format.height != fmt_sink.format.height) - return -EPIPE; - } - return 0; -} - -/* - * vpfe_pipeline_enable() - Enable streaming on a pipeline - * @vpfe_dev: vpfe device - * @pipe: vpfe pipeline - * - * Walk the entities chain starting at the pipeline output video node and start - * all modules in the chain in the given mode. - * - * Return 0 if successful, or the return value of the failed video::s_stream - * operation otherwise. - */ -static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe) -{ - struct media_entity *entity; - struct v4l2_subdev *subdev; - struct media_device *mdev; - int ret; - - if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) - entity = vpfe_get_input_entity(pipe->outputs[0]); - else - entity = &pipe->inputs[0]->video_dev.entity; - - mdev = entity->graph_obj.mdev; - mutex_lock(&mdev->graph_mutex); - ret = media_graph_walk_init(&pipe->graph, mdev); - if (ret) - goto out; - media_graph_walk_start(&pipe->graph, entity); - while ((entity = media_graph_walk_next(&pipe->graph))) { - - if (!is_media_entity_v4l2_subdev(entity)) - continue; - subdev = media_entity_to_v4l2_subdev(entity); - ret = v4l2_subdev_call(subdev, video, s_stream, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) - break; - } -out: - if (ret) - media_graph_walk_cleanup(&pipe->graph); - mutex_unlock(&mdev->graph_mutex); - return ret; -} - -/* - * vpfe_pipeline_disable() - Disable streaming on a pipeline - * @vpfe_dev: vpfe device - * @pipe: VPFE pipeline - * - * Walk the entities chain starting at the pipeline output video node and stop - * all modules in the chain. - * - * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module - * can't be stopped. - */ -static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe) -{ - struct media_entity *entity; - struct v4l2_subdev *subdev; - struct media_device *mdev; - int ret = 0; - - if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) - entity = vpfe_get_input_entity(pipe->outputs[0]); - else - entity = &pipe->inputs[0]->video_dev.entity; - - mdev = entity->graph_obj.mdev; - mutex_lock(&mdev->graph_mutex); - media_graph_walk_start(&pipe->graph, entity); - - while ((entity = media_graph_walk_next(&pipe->graph))) { - - if (!is_media_entity_v4l2_subdev(entity)) - continue; - subdev = media_entity_to_v4l2_subdev(entity); - ret = v4l2_subdev_call(subdev, video, s_stream, 0); - if (ret < 0 && ret != -ENOIOCTLCMD) - break; - } - mutex_unlock(&mdev->graph_mutex); - - media_graph_walk_cleanup(&pipe->graph); - return ret ? -ETIMEDOUT : 0; -} - -/* - * vpfe_pipeline_set_stream() - Enable/disable streaming on a pipeline - * @vpfe_dev: VPFE device - * @pipe: VPFE pipeline - * @state: Stream state (stopped or active) - * - * Set the pipeline to the given stream state. - * - * Return 0 if successful, or the return value of the failed video::s_stream - * operation otherwise. - */ -static int vpfe_pipeline_set_stream(struct vpfe_pipeline *pipe, - enum vpfe_pipeline_stream_state state) -{ - if (state == VPFE_PIPELINE_STREAM_STOPPED) - return vpfe_pipeline_disable(pipe); - - return vpfe_pipeline_enable(pipe); -} - -static int all_videos_stopped(struct vpfe_video_device *video) -{ - struct vpfe_pipeline *pipe = &video->pipe; - int i; - - for (i = 0; i < pipe->input_num; i++) - if (pipe->inputs[i]->started) - return 0; - for (i = 0; i < pipe->output_num; i++) - if (pipe->outputs[i]->started) - return 0; - return 1; -} - -/* - * vpfe_open() - open video device - * @file: file pointer - * - * initialize media pipeline state, allocate memory for file handle - * - * Return 0 if successful, or the return -ENODEV otherwise. - */ -static int vpfe_open(struct file *file) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_fh *handle; - - /* Allocate memory for the file handle object */ - handle = kzalloc(sizeof(struct vpfe_fh), GFP_KERNEL); - - if (!handle) - return -ENOMEM; - - v4l2_fh_init(&handle->vfh, &video->video_dev); - v4l2_fh_add(&handle->vfh); - - mutex_lock(&video->lock); - /* If decoder is not initialized. initialize it */ - if (!video->initialized && vpfe_update_pipe_state(video)) { - mutex_unlock(&video->lock); - v4l2_fh_del(&handle->vfh); - v4l2_fh_exit(&handle->vfh); - kfree(handle); - return -ENODEV; - } - /* Increment device users counter */ - video->usrs++; - /* Set io_allowed member to false */ - handle->io_allowed = 0; - handle->video = video; - file->private_data = &handle->vfh; - mutex_unlock(&video->lock); - - return 0; -} - -/* get the next buffer available from dma queue */ -static unsigned long -vpfe_video_get_next_buffer(struct vpfe_video_device *video) -{ - video->cur_frm = video->next_frm = - list_entry(video->dma_queue.next, - struct vpfe_cap_buffer, list); - - list_del(&video->next_frm->list); - video->next_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - return vb2_dma_contig_plane_dma_addr(&video->next_frm->vb.vb2_buf, 0); -} - -/* schedule the next buffer which is available on dma queue */ -void vpfe_video_schedule_next_buffer(struct vpfe_video_device *video) -{ - struct vpfe_device *vpfe_dev = video->vpfe_dev; - unsigned long addr; - - if (list_empty(&video->dma_queue)) - return; - - video->next_frm = list_entry(video->dma_queue.next, - struct vpfe_cap_buffer, list); - - if (video->pipe.state == VPFE_PIPELINE_STREAM_SINGLESHOT) - video->cur_frm = video->next_frm; - - list_del(&video->next_frm->list); - video->next_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - addr = vb2_dma_contig_plane_dma_addr(&video->next_frm->vb.vb2_buf, 0); - video->ops->queue(vpfe_dev, addr); - video->state = VPFE_VIDEO_BUFFER_QUEUED; -} - -/* schedule the buffer for capturing bottom field */ -void vpfe_video_schedule_bottom_field(struct vpfe_video_device *video) -{ - struct vpfe_device *vpfe_dev = video->vpfe_dev; - unsigned long addr; - - addr = vb2_dma_contig_plane_dma_addr(&video->cur_frm->vb.vb2_buf, 0); - addr += video->field_off; - video->ops->queue(vpfe_dev, addr); -} - -/* make buffer available for dequeue */ -void vpfe_video_process_buffer_complete(struct vpfe_video_device *video) -{ - struct vpfe_pipeline *pipe = &video->pipe; - - video->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns(); - vb2_buffer_done(&video->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); - if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) - video->cur_frm = video->next_frm; -} - -/* vpfe_stop_capture() - stop streaming */ -static void vpfe_stop_capture(struct vpfe_video_device *video) -{ - struct vpfe_pipeline *pipe = &video->pipe; - - video->started = 0; - - if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - return; - if (all_videos_stopped(video)) - vpfe_pipeline_set_stream(pipe, - VPFE_PIPELINE_STREAM_STOPPED); -} - -/* - * vpfe_release() - release video device - * @file: file pointer - * - * deletes buffer queue, frees the buffers and the vpfe file handle - * - * Return 0 - */ -static int vpfe_release(struct file *file) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct v4l2_fh *vfh = file->private_data; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_fh *fh = container_of(vfh, struct vpfe_fh, vfh); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n"); - - /* Get the device lock */ - mutex_lock(&video->lock); - /* if this instance is doing IO */ - if (fh->io_allowed) { - if (video->started) { - vpfe_stop_capture(video); - /* - * mark pipe state as stopped in vpfe_release(), - * as app might call streamon() after streamoff() - * in which case driver has to start streaming. - */ - video->pipe.state = VPFE_PIPELINE_STREAM_STOPPED; - vb2_streamoff(&video->buffer_queue, - video->buffer_queue.type); - } - video->io_usrs = 0; - /* Free buffers allocated */ - vb2_queue_release(&video->buffer_queue); - } - /* Decrement device users counter */ - video->usrs--; - v4l2_fh_del(&fh->vfh); - v4l2_fh_exit(&fh->vfh); - /* If this is the last file handle */ - if (!video->usrs) - video->initialized = 0; - mutex_unlock(&video->lock); - file->private_data = NULL; - /* Free memory allocated to file handle object */ - v4l2_fh_del(vfh); - kzfree(fh); - return 0; -} - -/* - * vpfe_mmap() - It is used to map kernel space buffers - * into user spaces - */ -static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n"); - return vb2_mmap(&video->buffer_queue, vma); -} - -/* - * vpfe_poll() - It is used for select/poll system call - */ -static __poll_t vpfe_poll(struct file *file, poll_table *wait) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n"); - if (video->started) - return vb2_poll(&video->buffer_queue, file, wait); - return 0; -} - -/* vpfe capture driver file operations */ -static const struct v4l2_file_operations vpfe_fops = { - .owner = THIS_MODULE, - .open = vpfe_open, - .release = vpfe_release, - .unlocked_ioctl = video_ioctl2, - .mmap = vpfe_mmap, - .poll = vpfe_poll -}; - -/* - * vpfe_querycap() - query capabilities of video device - * @file: file pointer - * @priv: void pointer - * @cap: pointer to v4l2_capability structure - * - * fills v4l2 capabilities structure - * - * Return 0 - */ -static int vpfe_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); - - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | - V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; - strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); - strscpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); - strscpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); - - return 0; -} - -/* - * vpfe_g_fmt() - get the format which is active on video device - * @file: file pointer - * @priv: void pointer - * @fmt: pointer to v4l2_format structure - * - * fills v4l2 format structure with active format - * - * Return 0 - */ -static int vpfe_g_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt\n"); - /* Fill in the information about format */ - *fmt = video->fmt; - return 0; -} - -/* - * vpfe_enum_fmt() - enum formats supported on media chain - * @file: file pointer - * @priv: void pointer - * @fmt: pointer to v4l2_fmtdesc structure - * - * fills v4l2_fmtdesc structure with output format set on adjacent subdev, - * only one format is enumearted as subdevs are already configured - * - * Return 0 if successful, error code otherwise - */ -static int vpfe_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_subdev_format sd_fmt; - struct v4l2_mbus_framefmt mbus; - struct v4l2_subdev *subdev; - struct v4l2_format format; - struct media_pad *remote; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt\n"); - - /* - * since already subdev pad format is set, - * only one pixel format is available - */ - if (fmt->index > 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid index\n"); - return -EINVAL; - } - /* get the remote pad */ - remote = media_entity_remote_pad(&video->pad); - if (!remote) { - v4l2_err(&vpfe_dev->v4l2_dev, - "invalid remote pad for video node\n"); - return -EINVAL; - } - /* get the remote subdev */ - subdev = vpfe_video_remote_subdev(video, NULL); - if (!subdev) { - v4l2_err(&vpfe_dev->v4l2_dev, - "invalid remote subdev for video node\n"); - return -EINVAL; - } - sd_fmt.pad = remote->index; - sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - /* get output format of remote subdev */ - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &sd_fmt); - if (ret) { - v4l2_err(&vpfe_dev->v4l2_dev, - "invalid remote subdev for video node\n"); - return ret; - } - /* convert to pix format */ - mbus.code = sd_fmt.format.code; - mbus_to_pix(&mbus, &format.fmt.pix); - /* copy the result */ - fmt->pixelformat = format.fmt.pix.pixelformat; - - return 0; -} - -/* - * vpfe_s_fmt() - set the format on video device - * @file: file pointer - * @priv: void pointer - * @fmt: pointer to v4l2_format structure - * - * validate and set the format on video device - * - * Return 0 on success, error code otherwise - */ -static int vpfe_s_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_format format; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt\n"); - /* If streaming is started, return error */ - if (video->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n"); - return -EBUSY; - } - /* get adjacent subdev's output pad format */ - ret = __vpfe_video_get_format(video, &format); - if (ret) - return ret; - *fmt = format; - video->fmt = *fmt; - return 0; -} - -/* - * vpfe_try_fmt() - try the format on video device - * @file: file pointer - * @priv: void pointer - * @fmt: pointer to v4l2_format structure - * - * validate the format, update with correct format - * based on output format set on adjacent subdev - * - * Return 0 on success, error code otherwise - */ -static int vpfe_try_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_format format; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt\n"); - /* get adjacent subdev's output pad format */ - ret = __vpfe_video_get_format(video, &format); - if (ret) - return ret; - - *fmt = format; - return 0; -} - -/* - * vpfe_enum_input() - enum inputs supported on media chain - * @file: file pointer - * @priv: void pointer - * @fmt: pointer to v4l2_fmtdesc structure - * - * fills v4l2_input structure with input available on media chain, - * only one input is enumearted as media chain is setup by this time - * - * Return 0 if successful, -EINVAL is media chain is invalid - */ -static int vpfe_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_ext_subdev_info *sdinfo = video->current_ext_subdev; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); - /* enumerate from the subdev user has chosen through mc */ - if (inp->index < sdinfo->num_inputs) { - memcpy(inp, &sdinfo->inputs[inp->index], - sizeof(struct v4l2_input)); - return 0; - } - return -EINVAL; -} - -/* - * vpfe_g_input() - get index of the input which is active - * @file: file pointer - * @priv: void pointer - * @index: pointer to unsigned int - * - * set index with input index which is active - */ -static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n"); - - *index = video->current_input; - return 0; -} - -/* - * vpfe_s_input() - set input which is pointed by input index - * @file: file pointer - * @priv: void pointer - * @index: pointer to unsigned int - * - * set input on external subdev - * - * Return 0 on success, error code otherwise - */ -static int vpfe_s_input(struct file *file, void *priv, unsigned int index) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_ext_subdev_info *sdinfo; - struct vpfe_route *route; - struct v4l2_input *inps; - u32 output; - u32 input; - int ret; - int i; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); - - ret = mutex_lock_interruptible(&video->lock); - if (ret) - return ret; - /* - * If streaming is started return device busy - * error - */ - if (video->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n"); - ret = -EBUSY; - goto unlock_out; - } - - sdinfo = video->current_ext_subdev; - if (!sdinfo->registered) { - ret = -EINVAL; - goto unlock_out; - } - if (vpfe_dev->cfg->setup_input && - vpfe_dev->cfg->setup_input(sdinfo->grp_id) < 0) { - ret = -EFAULT; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "couldn't setup input for %s\n", - sdinfo->module_name); - goto unlock_out; - } - route = &sdinfo->routes[index]; - if (route && sdinfo->can_route) { - input = route->input; - output = route->output; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, video, - s_routing, input, output, 0); - if (ret) { - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "s_input:error in setting input in decoder\n"); - ret = -EINVAL; - goto unlock_out; - } - } - /* set standards set by subdev in video device */ - for (i = 0; i < sdinfo->num_inputs; i++) { - inps = &sdinfo->inputs[i]; - video->video_dev.tvnorms |= inps->std; - } - video->current_input = index; -unlock_out: - mutex_unlock(&video->lock); - return ret; -} - -/* - * vpfe_querystd() - query std which is being input on external subdev - * @file: file pointer - * @priv: void pointer - * @std_id: pointer to v4l2_std_id structure - * - * call external subdev through v4l2_device_call_until_err to - * get the std that is being active. - * - * Return 0 on success, error code otherwise - */ -static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_ext_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); - - ret = mutex_lock_interruptible(&video->lock); - sdinfo = video->current_ext_subdev; - if (ret) - return ret; - /* Call querystd function of decoder device */ - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, querystd, std_id); - mutex_unlock(&video->lock); - return ret; -} - -/* - * vpfe_s_std() - set std on external subdev - * @file: file pointer - * @priv: void pointer - * @std_id: pointer to v4l2_std_id structure - * - * set std pointed by std_id on external subdev by calling it using - * v4l2_device_call_until_err - * - * Return 0 on success, error code otherwise - */ -static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_ext_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); - - /* Call decoder driver function to set the standard */ - ret = mutex_lock_interruptible(&video->lock); - if (ret) - return ret; - sdinfo = video->current_ext_subdev; - /* If streaming is started, return device busy error */ - if (video->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n"); - ret = -EBUSY; - goto unlock_out; - } - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_std, std_id); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); - video->stdid = V4L2_STD_UNKNOWN; - goto unlock_out; - } - video->stdid = std_id; -unlock_out: - mutex_unlock(&video->lock); - return ret; -} - -static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); - *tvnorm = video->stdid; - return 0; -} - -/* - * vpfe_enum_dv_timings() - enumerate dv_timings which are supported by - * to external subdev - * @file: file pointer - * @priv: void pointer - * @timings: pointer to v4l2_enum_dv_timings structure - * - * enum dv_timings's which are supported by external subdev through - * v4l2_subdev_call - * - * Return 0 on success, error code otherwise - */ -static int -vpfe_enum_dv_timings(struct file *file, void *fh, - struct v4l2_enum_dv_timings *timings) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_subdev *subdev = video->current_ext_subdev->subdev; - - timings->pad = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_dv_timings\n"); - return v4l2_subdev_call(subdev, pad, enum_dv_timings, timings); -} - -/* - * vpfe_query_dv_timings() - query the dv_timings which is being input - * to external subdev - * @file: file pointer - * @priv: void pointer - * @timings: pointer to v4l2_dv_timings structure - * - * get dv_timings which is being input on external subdev through - * v4l2_subdev_call - * - * Return 0 on success, error code otherwise - */ -static int -vpfe_query_dv_timings(struct file *file, void *fh, - struct v4l2_dv_timings *timings) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_subdev *subdev = video->current_ext_subdev->subdev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_query_dv_timings\n"); - return v4l2_subdev_call(subdev, video, query_dv_timings, timings); -} - -/* - * vpfe_s_dv_timings() - set dv_timings on external subdev - * @file: file pointer - * @priv: void pointer - * @timings: pointer to v4l2_dv_timings structure - * - * set dv_timings pointed by timings on external subdev through - * v4l2_device_call_until_err, this configures amplifier also - * - * Return 0 on success, error code otherwise - */ -static int -vpfe_s_dv_timings(struct file *file, void *fh, - struct v4l2_dv_timings *timings) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_dv_timings\n"); - - video->stdid = V4L2_STD_UNKNOWN; - return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - video->current_ext_subdev->grp_id, - video, s_dv_timings, timings); -} - -/* - * vpfe_g_dv_timings() - get dv_timings which is set on external subdev - * @file: file pointer - * @priv: void pointer - * @timings: pointer to v4l2_dv_timings structure - * - * get dv_timings which is set on external subdev through - * v4l2_subdev_call - * - * Return 0 on success, error code otherwise - */ -static int -vpfe_g_dv_timings(struct file *file, void *fh, - struct v4l2_dv_timings *timings) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_subdev *subdev = video->current_ext_subdev->subdev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_dv_timings\n"); - return v4l2_subdev_call(subdev, video, g_dv_timings, timings); -} - -/* - * Videobuf operations - */ -/* - * vpfe_buffer_queue_setup : Callback function for buffer setup. - * @vq: vb2_queue ptr - * @fmt: v4l2 format - * @nbuffers: ptr to number of buffers requested by application - * @nplanes:: contains number of distinct video planes needed to hold a frame - * @sizes[]: contains the size (in bytes) of each plane. - * @alloc_devs: ptr to allocation context - * - * This callback function is called when reqbuf() is called to adjust - * the buffer nbuffers and buffer size - */ -static int -vpfe_buffer_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], struct device *alloc_devs[]) -{ - struct vpfe_fh *fh = vb2_get_drv_priv(vq); - struct vpfe_video_device *video = fh->video; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - unsigned long size; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue_setup\n"); - size = video->fmt.fmt.pix.sizeimage; - - if (vq->num_buffers + *nbuffers < 3) - *nbuffers = 3 - vq->num_buffers; - - *nplanes = 1; - sizes[0] = size; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "nbuffers=%d, size=%lu\n", *nbuffers, size); - return 0; -} - -/* - * vpfe_buffer_prepare : callback function for buffer prepare - * @vb: ptr to vb2_buffer - * - * This is the callback function for buffer prepare when vb2_qbuf() - * function is called. The buffer is prepared and user space virtual address - * or user address is converted into physical address - */ -static int vpfe_buffer_prepare(struct vb2_buffer *vb) -{ - struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); - struct vpfe_video_device *video = fh->video; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - unsigned long addr; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n"); - - /* Initialize buffer */ - vb2_set_plane_payload(vb, 0, video->fmt.fmt.pix.sizeimage); - if (vb2_plane_vaddr(vb, 0) && - vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) - return -EINVAL; - - addr = vb2_dma_contig_plane_dma_addr(vb, 0); - /* Make sure user addresses are aligned to 32 bytes */ - if (!ALIGN(addr, 32)) - return -EINVAL; - - return 0; -} - -static void vpfe_buffer_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - /* Get the file handle object and device object */ - struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); - struct vpfe_video_device *video = fh->video; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_pipeline *pipe = &video->pipe; - struct vpfe_cap_buffer *buf = container_of(vbuf, - struct vpfe_cap_buffer, vb); - unsigned long flags; - unsigned long empty; - unsigned long addr; - - spin_lock_irqsave(&video->dma_queue_lock, flags); - empty = list_empty(&video->dma_queue); - /* add the buffer to the DMA queue */ - list_add_tail(&buf->list, &video->dma_queue); - spin_unlock_irqrestore(&video->dma_queue_lock, flags); - /* this case happens in case of single shot */ - if (empty && video->started && pipe->state == - VPFE_PIPELINE_STREAM_SINGLESHOT && - video->state == VPFE_VIDEO_BUFFER_NOT_QUEUED) { - spin_lock(&video->dma_queue_lock); - addr = vpfe_video_get_next_buffer(video); - video->ops->queue(vpfe_dev, addr); - - video->state = VPFE_VIDEO_BUFFER_QUEUED; - spin_unlock(&video->dma_queue_lock); - - /* enable h/w each time in single shot */ - if (vpfe_video_is_pipe_ready(pipe)) - vpfe_pipeline_set_stream(pipe, - VPFE_PIPELINE_STREAM_SINGLESHOT); - } -} - -/* vpfe_start_capture() - start streaming on all the subdevs */ -static int vpfe_start_capture(struct vpfe_video_device *video) -{ - struct vpfe_pipeline *pipe = &video->pipe; - int ret = 0; - - video->started = 1; - if (vpfe_video_is_pipe_ready(pipe)) - ret = vpfe_pipeline_set_stream(pipe, pipe->state); - - return ret; -} - -static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct vpfe_fh *fh = vb2_get_drv_priv(vq); - struct vpfe_video_device *video = fh->video; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - unsigned long addr; - int ret; - - ret = mutex_lock_interruptible(&video->lock); - if (ret) - goto streamoff; - - /* Get the next frame from the buffer queue */ - video->cur_frm = video->next_frm = - list_entry(video->dma_queue.next, struct vpfe_cap_buffer, list); - /* Remove buffer from the buffer queue */ - list_del(&video->cur_frm->list); - /* Mark state of the current frame to active */ - video->cur_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - /* Initialize field_id and started member */ - video->field_id = 0; - addr = vb2_dma_contig_plane_dma_addr(&video->cur_frm->vb.vb2_buf, 0); - video->ops->queue(vpfe_dev, addr); - video->state = VPFE_VIDEO_BUFFER_QUEUED; - - ret = vpfe_start_capture(video); - if (ret) { - struct vpfe_cap_buffer *buf, *tmp; - - vb2_buffer_done(&video->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - list_for_each_entry_safe(buf, tmp, &video->dma_queue, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - goto unlock_out; - } - - mutex_unlock(&video->lock); - - return ret; -unlock_out: - mutex_unlock(&video->lock); -streamoff: - ret = vb2_streamoff(&video->buffer_queue, video->buffer_queue.type); - return 0; -} - -static int vpfe_buffer_init(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vpfe_cap_buffer *buf = container_of(vbuf, - struct vpfe_cap_buffer, vb); - - INIT_LIST_HEAD(&buf->list); - return 0; -} - -/* abort streaming and wait for last buffer */ -static void vpfe_stop_streaming(struct vb2_queue *vq) -{ - struct vpfe_fh *fh = vb2_get_drv_priv(vq); - struct vpfe_video_device *video = fh->video; - - /* release all active buffers */ - if (video->cur_frm == video->next_frm) { - vb2_buffer_done(&video->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } else { - if (video->cur_frm != NULL) - vb2_buffer_done(&video->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - if (video->next_frm != NULL) - vb2_buffer_done(&video->next_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } - - while (!list_empty(&video->dma_queue)) { - video->next_frm = list_entry(video->dma_queue.next, - struct vpfe_cap_buffer, list); - list_del(&video->next_frm->list); - vb2_buffer_done(&video->next_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } -} - -static void vpfe_buf_cleanup(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); - struct vpfe_video_device *video = fh->video; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_cap_buffer *buf = container_of(vbuf, - struct vpfe_cap_buffer, vb); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buf_cleanup\n"); - if (vb->state == VB2_BUF_STATE_ACTIVE) - list_del_init(&buf->list); -} - -static const struct vb2_ops video_qops = { - .queue_setup = vpfe_buffer_queue_setup, - .buf_init = vpfe_buffer_init, - .buf_prepare = vpfe_buffer_prepare, - .start_streaming = vpfe_start_streaming, - .stop_streaming = vpfe_stop_streaming, - .buf_cleanup = vpfe_buf_cleanup, - .buf_queue = vpfe_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -/* - * vpfe_reqbufs() - supported REQBUF only once opening - * the device. - */ -static int vpfe_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req_buf) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_fh *fh = file->private_data; - struct vb2_queue *q; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); - - if (req_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - req_buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT){ - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&video->lock); - if (ret) - return ret; - - if (video->io_usrs != 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n"); - ret = -EBUSY; - goto unlock_out; - } - video->memory = req_buf->memory; - - /* Initialize videobuf2 queue as per the buffer type */ - q = &video->buffer_queue; - q->type = req_buf->type; - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->drv_priv = fh; - q->min_buffers_needed = 1; - q->ops = &video_qops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct vpfe_cap_buffer); - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->dev = vpfe_dev->pdev; - q->lock = &video->lock; - - ret = vb2_queue_init(q); - if (ret) { - v4l2_err(&vpfe_dev->v4l2_dev, "vb2_queue_init() failed\n"); - goto unlock_out; - } - - fh->io_allowed = 1; - video->io_usrs = 1; - INIT_LIST_HEAD(&video->dma_queue); - ret = vb2_reqbufs(&video->buffer_queue, req_buf); - -unlock_out: - mutex_unlock(&video->lock); - return ret; -} - -/* - * vpfe_querybuf() - query buffers for exchange - */ -static int vpfe_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n"); - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - if (video->memory != V4L2_MEMORY_MMAP) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n"); - return -EINVAL; - } - - /* Call vb2_querybuf to get information */ - return vb2_querybuf(&video->buffer_queue, buf); -} - -/* - * vpfe_qbuf() - queue buffers for capture or processing - */ -static int vpfe_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_fh *fh = file->private_data; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n"); - - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - p->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - /* - * If this file handle is not allowed to do IO, - * return error - */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - return vb2_qbuf(&video->buffer_queue, - video->video_dev.v4l2_dev->mdev, p); -} - -/* - * vpfe_dqbuf() - deque buffer which is done with processing - */ -static int vpfe_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n"); - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - return vb2_dqbuf(&video->buffer_queue, - buf, (file->f_flags & O_NONBLOCK)); -} - -/* - * vpfe_streamon() - start streaming - * @file: file pointer - * @priv: void pointer - * @buf_type: enum v4l2_buf_type - * - * queue buffer onto hardware for capture/processing and - * start all the subdevs which are in media chain - * - * Return 0 on success, error code otherwise - */ -static int vpfe_streamon(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_pipeline *pipe = &video->pipe; - struct vpfe_fh *fh = file->private_data; - int ret = -EINVAL; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); - - if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - buf_type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return ret; - } - /* If file handle is not allowed IO, return error */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - /* If buffer queue is empty, return error */ - if (list_empty(&video->buffer_queue.queued_list)) { - v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n"); - return -EIO; - } - /* Validate the pipeline */ - if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - ret = vpfe_video_validate_pipeline(pipe); - if (ret < 0) - return ret; - } - /* Call vb2_streamon to start streaming */ - return vb2_streamon(&video->buffer_queue, buf_type); -} - -/* - * vpfe_streamoff() - stop streaming - * @file: file pointer - * @priv: void pointer - * @buf_type: enum v4l2_buf_type - * - * stop all the subdevs which are in media chain - * - * Return 0 on success, error code otherwise - */ -static int vpfe_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_fh *fh = file->private_data; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); - - if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - buf_type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* If io is allowed for this file handle, return error */ - if (!fh->io_allowed) { - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - /* If streaming is not started, return error */ - if (!video->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "device is not started\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&video->lock); - if (ret) - return ret; - - vpfe_stop_capture(video); - ret = vb2_streamoff(&video->buffer_queue, buf_type); - mutex_unlock(&video->lock); - - return ret; -} - -/* vpfe capture ioctl operations */ -static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { - .vidioc_querycap = vpfe_querycap, - .vidioc_g_fmt_vid_cap = vpfe_g_fmt, - .vidioc_s_fmt_vid_cap = vpfe_s_fmt, - .vidioc_try_fmt_vid_cap = vpfe_try_fmt, - .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt, - .vidioc_g_fmt_vid_out = vpfe_g_fmt, - .vidioc_s_fmt_vid_out = vpfe_s_fmt, - .vidioc_try_fmt_vid_out = vpfe_try_fmt, - .vidioc_enum_fmt_vid_out = vpfe_enum_fmt, - .vidioc_enum_input = vpfe_enum_input, - .vidioc_g_input = vpfe_g_input, - .vidioc_s_input = vpfe_s_input, - .vidioc_querystd = vpfe_querystd, - .vidioc_s_std = vpfe_s_std, - .vidioc_g_std = vpfe_g_std, - .vidioc_enum_dv_timings = vpfe_enum_dv_timings, - .vidioc_query_dv_timings = vpfe_query_dv_timings, - .vidioc_s_dv_timings = vpfe_s_dv_timings, - .vidioc_g_dv_timings = vpfe_g_dv_timings, - .vidioc_reqbufs = vpfe_reqbufs, - .vidioc_querybuf = vpfe_querybuf, - .vidioc_qbuf = vpfe_qbuf, - .vidioc_dqbuf = vpfe_dqbuf, - .vidioc_streamon = vpfe_streamon, - .vidioc_streamoff = vpfe_streamoff, -}; - -/* VPFE video init function */ -int vpfe_video_init(struct vpfe_video_device *video, const char *name) -{ - const char *direction; - int ret; - - switch (video->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - direction = "output"; - video->pad.flags = MEDIA_PAD_FL_SINK; - video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - direction = "input"; - video->pad.flags = MEDIA_PAD_FL_SOURCE; - video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - break; - - default: - return -EINVAL; - } - /* Initialize field of video device */ - mutex_init(&video->lock); - video->video_dev.release = video_device_release; - video->video_dev.fops = &vpfe_fops; - video->video_dev.ioctl_ops = &vpfe_ioctl_ops; - video->video_dev.minor = -1; - video->video_dev.tvnorms = 0; - video->video_dev.lock = &video->lock; - snprintf(video->video_dev.name, sizeof(video->video_dev.name), - "DAVINCI VIDEO %s %s", name, direction); - - spin_lock_init(&video->irqlock); - spin_lock_init(&video->dma_queue_lock); - ret = media_entity_pads_init(&video->video_dev.entity, - 1, &video->pad); - if (ret < 0) - return ret; - - video_set_drvdata(&video->video_dev, video); - - return 0; -} - -/* vpfe video device register function */ -int vpfe_video_register(struct vpfe_video_device *video, - struct v4l2_device *vdev) -{ - int ret; - - video->video_dev.v4l2_dev = vdev; - - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - video->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE; - else - video->video_dev.device_caps = V4L2_CAP_VIDEO_OUTPUT; - video->video_dev.device_caps |= V4L2_CAP_STREAMING; - ret = video_register_device(&video->video_dev, VFL_TYPE_GRABBER, -1); - if (ret < 0) - pr_err("%s: could not register video device (%d)\n", - __func__, ret); - return ret; -} - -/* vpfe video device unregister function */ -void vpfe_video_unregister(struct vpfe_video_device *video) -{ - if (video_is_registered(&video->video_dev)) { - video_unregister_device(&video->video_dev); - media_entity_cleanup(&video->video_dev.entity); - } -} diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.h b/drivers/staging/media/davinci_vpfe/vpfe_video.h deleted file mode 100644 index 5d01c4883ab4..000000000000 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.h +++ /dev/null @@ -1,150 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli <manjunath.hadli@ti.com> - * Prabhakar Lad <prabhakar.lad@ti.com> - */ - -#ifndef _DAVINCI_VPFE_VIDEO_H -#define _DAVINCI_VPFE_VIDEO_H - -#include <media/videobuf2-v4l2.h> -#include <media/videobuf2-dma-contig.h> - -struct vpfe_device; - -/* - * struct vpfe_video_operations - VPFE video operations - * @queue: Resume streaming when a buffer is queued. Called on VIDIOC_QBUF - * if there was no buffer previously queued. - */ -struct vpfe_video_operations { - int (*queue)(struct vpfe_device *vpfe_dev, unsigned long addr); -}; - -enum vpfe_pipeline_stream_state { - VPFE_PIPELINE_STREAM_STOPPED = 0, - VPFE_PIPELINE_STREAM_CONTINUOUS = 1, - VPFE_PIPELINE_STREAM_SINGLESHOT = 2, -}; - -enum vpfe_video_state { - /* indicates that buffer is not queued */ - VPFE_VIDEO_BUFFER_NOT_QUEUED = 0, - /* indicates that buffer is queued */ - VPFE_VIDEO_BUFFER_QUEUED = 1, -}; - -struct vpfe_pipeline { - /* media pipeline */ - struct media_pipeline *pipe; - struct media_graph graph; - /* state of the pipeline, continuous, - * single-shot or stopped - */ - enum vpfe_pipeline_stream_state state; - /* number of active input video entities */ - unsigned int input_num; - /* number of active output video entities */ - unsigned int output_num; - /* input video nodes in case of single-shot mode */ - struct vpfe_video_device *inputs[10]; - /* capturing video nodes */ - struct vpfe_video_device *outputs[10]; -}; - -#define to_vpfe_pipeline(__e) \ - container_of((__e)->pipe, struct vpfe_pipeline, pipe) - -#define to_vpfe_video(vdev) \ - container_of(vdev, struct vpfe_video_device, video_dev) - -struct vpfe_cap_buffer { - struct vb2_v4l2_buffer vb; - struct list_head list; -}; - -struct vpfe_video_device { - /* vpfe device */ - struct vpfe_device *vpfe_dev; - /* video dev */ - struct video_device video_dev; - /* media pad of video entity */ - struct media_pad pad; - /* video operations supported by video device */ - const struct vpfe_video_operations *ops; - /* type of the video buffers used by user */ - enum v4l2_buf_type type; - /* Indicates id of the field which is being captured */ - u32 field_id; - /* pipeline for which video device is part of */ - struct vpfe_pipeline pipe; - /* Indicates whether streaming started */ - u8 started; - /* Indicates state of the stream */ - unsigned int state; - /* current input at the sub device */ - int current_input; - /* - * This field keeps track of type of buffer exchange mechanism - * user has selected - */ - enum v4l2_memory memory; - /* number of open instances of the channel */ - u32 usrs; - /* flag to indicate whether decoder is initialized */ - u8 initialized; - /* skip frame count */ - u8 skip_frame_count; - /* skip frame count init value */ - u8 skip_frame_count_init; - /* time per frame for skipping */ - struct v4l2_fract timeperframe; - /* ptr to currently selected sub device */ - struct vpfe_ext_subdev_info *current_ext_subdev; - /* Pointer pointing to current vpfe_cap_buffer */ - struct vpfe_cap_buffer *cur_frm; - /* Pointer pointing to next vpfe_cap_buffer */ - struct vpfe_cap_buffer *next_frm; - /* Used to store pixel format */ - struct v4l2_format fmt; - struct vb2_queue buffer_queue; - /* Queue of filled frames */ - struct list_head dma_queue; - spinlock_t irqlock; - /* IRQ lock for DMA queue */ - spinlock_t dma_queue_lock; - /* lock used to serialize all video4linux ioctls */ - struct mutex lock; - /* number of users performing IO */ - u32 io_usrs; - /* Currently selected or default standard */ - v4l2_std_id stdid; - /* - * offset where second field starts from the starting of the - * buffer for field separated YCbCr formats - */ - u32 field_off; -}; - -int vpfe_video_is_pipe_ready(struct vpfe_pipeline *pipe); -void vpfe_video_unregister(struct vpfe_video_device *video); -int vpfe_video_register(struct vpfe_video_device *video, - struct v4l2_device *vdev); -int vpfe_video_init(struct vpfe_video_device *video, const char *name); -void vpfe_video_process_buffer_complete(struct vpfe_video_device *video); -void vpfe_video_schedule_bottom_field(struct vpfe_video_device *video); -void vpfe_video_schedule_next_buffer(struct vpfe_video_device *video); - -#endif /* _DAVINCI_VPFE_VIDEO_H */ diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig index be133bbaa68a..de77fe6554e7 100644 --- a/drivers/staging/media/hantro/Kconfig +++ b/drivers/staging/media/hantro/Kconfig @@ -20,4 +20,4 @@ config VIDEO_HANTRO_ROCKCHIP depends on ARCH_ROCKCHIP || COMPILE_TEST default y help - Enable support for RK3288 and RK3399 SoCs. + Enable support for RK3288, RK3328, and RK3399 SoCs. diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile index 1584acdbf4a3..5d6b0383d280 100644 --- a/drivers/staging/media/hantro/Makefile +++ b/drivers/staging/media/hantro/Makefile @@ -4,11 +4,16 @@ hantro-vpu-y += \ hantro_drv.o \ hantro_v4l2.o \ hantro_h1_jpeg_enc.o \ + hantro_g1_h264_dec.o \ hantro_g1_mpeg2_dec.o \ + hantro_g1_vp8_dec.o \ rk3399_vpu_hw_jpeg_enc.o \ rk3399_vpu_hw_mpeg2_dec.o \ + rk3399_vpu_hw_vp8_dec.o \ hantro_jpeg.o \ - hantro_mpeg2.o + hantro_h264.o \ + hantro_mpeg2.o \ + hantro_vp8.o hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \ rk3288_vpu_hw.o \ diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index 62dcca9ff19c..f670bbde4159 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -20,11 +20,20 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-mem2mem.h> #include <media/videobuf2-core.h> #include <media/videobuf2-dma-contig.h> #include "hantro_hw.h" +#define VP8_MB_DIM 16 +#define VP8_MB_WIDTH(w) DIV_ROUND_UP(w, VP8_MB_DIM) +#define VP8_MB_HEIGHT(h) DIV_ROUND_UP(h, VP8_MB_DIM) + +#define H264_MB_DIM 16 +#define H264_MB_WIDTH(w) DIV_ROUND_UP(w, H264_MB_DIM) +#define H264_MB_HEIGHT(h) DIV_ROUND_UP(h, H264_MB_DIM) + #define MPEG2_MB_DIM 16 #define MPEG2_MB_WIDTH(w) DIV_ROUND_UP(w, MPEG2_MB_DIM) #define MPEG2_MB_HEIGHT(h) DIV_ROUND_UP(h, MPEG2_MB_DIM) @@ -38,8 +47,9 @@ struct hantro_codec_ops; #define HANTRO_JPEG_ENCODER BIT(0) #define HANTRO_ENCODERS 0x0000ffff - #define HANTRO_MPEG2_DECODER BIT(16) +#define HANTRO_VP8_DECODER BIT(17) +#define HANTRO_H264_DECODER BIT(18) #define HANTRO_DECODERS 0xffff0000 /** @@ -96,22 +106,24 @@ struct hantro_variant { * enum hantro_codec_mode - codec operating mode. * @HANTRO_MODE_NONE: No operating mode. Used for RAW video formats. * @HANTRO_MODE_JPEG_ENC: JPEG encoder. + * @HANTRO_MODE_H264_DEC: H264 decoder. * @HANTRO_MODE_MPEG2_DEC: MPEG-2 decoder. + * @HANTRO_MODE_VP8_DEC: VP8 decoder. */ enum hantro_codec_mode { HANTRO_MODE_NONE = -1, HANTRO_MODE_JPEG_ENC, + HANTRO_MODE_H264_DEC, HANTRO_MODE_MPEG2_DEC, + HANTRO_MODE_VP8_DEC, }; /* * struct hantro_ctrl - helper type to declare supported controls - * @id: V4L2 control ID (V4L2_CID_xxx) * @codec: codec id this control belong to (HANTRO_JPEG_ENCODER, etc.) * @cfg: control configuration */ struct hantro_ctrl { - unsigned int id; unsigned int codec; struct v4l2_ctrl_config cfg; }; @@ -215,6 +227,7 @@ struct hantro_dev { * @codec_ops: Set of operations related to codec mode. * @jpeg_enc: JPEG-encoding context. * @mpeg2_dec: MPEG-2-decoding context. + * @vp8_dec: VP8-decoding context. */ struct hantro_ctx { struct hantro_dev *dev; @@ -239,8 +252,10 @@ struct hantro_ctx { /* Specific for particular codec modes. */ union { + struct hantro_h264_dec_hw_ctx h264_dec; struct hantro_jpeg_enc_hw_ctx jpeg_enc; struct hantro_mpeg2_dec_hw_ctx mpeg2_dec; + struct hantro_vp8_dec_hw_ctx vp8_dec; }; }; @@ -265,6 +280,12 @@ struct hantro_fmt { struct v4l2_frmsize_stepwise frmsize; }; +struct hantro_reg { + u32 base; + u32 shift; + u32 mask; +}; + /* Logging helpers */ /** @@ -343,9 +364,33 @@ static inline u32 vdpu_read(struct hantro_dev *vpu, u32 reg) return val; } +static inline void hantro_reg_write(struct hantro_dev *vpu, + const struct hantro_reg *reg, + u32 val) +{ + u32 v; + + v = vdpu_read(vpu, reg->base); + v &= ~(reg->mask << reg->shift); + v |= ((val & reg->mask) << reg->shift); + vdpu_write_relaxed(vpu, v, reg->base); +} + bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx); void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id); dma_addr_t hantro_get_ref(struct vb2_queue *q, u64 ts); +static inline struct vb2_v4l2_buffer * +hantro_get_src_buf(struct hantro_ctx *ctx) +{ + return v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); +} + +static inline struct vb2_v4l2_buffer * +hantro_get_dst_buf(struct hantro_ctx *ctx) +{ + return v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); +} + #endif /* HANTRO_H_ */ diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index c3665f0e87a2..d8b6816b643b 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -111,8 +111,6 @@ static void hantro_job_finish(struct hantro_dev *vpu, src->sequence = ctx->sequence_out++; dst->sequence = ctx->sequence_cap++; - v4l2_m2m_buf_copy_metadata(src, dst, true); - ret = ctx->buf_finish(ctx, &dst->vb2_buf, bytesused); if (ret) result = VB2_BUF_STATE_ERROR; @@ -153,11 +151,37 @@ void hantro_watchdog(struct work_struct *work) } } +void hantro_prepare_run(struct hantro_ctx *ctx) +{ + struct vb2_v4l2_buffer *src_buf; + + src_buf = hantro_get_src_buf(ctx); + v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); +} + +void hantro_finish_run(struct hantro_ctx *ctx) +{ + struct vb2_v4l2_buffer *src_buf; + + src_buf = hantro_get_src_buf(ctx); + v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + + /* Kick the watchdog. */ + schedule_delayed_work(&ctx->dev->watchdog_work, + msecs_to_jiffies(2000)); +} + static void device_run(void *priv) { struct hantro_ctx *ctx = priv; + struct vb2_v4l2_buffer *src, *dst; int ret; + src = hantro_get_src_buf(ctx); + dst = hantro_get_dst_buf(ctx); + ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks); if (ret) goto err_cancel_job; @@ -165,6 +189,8 @@ static void device_run(void *priv) if (ret < 0) goto err_cancel_job; + v4l2_m2m_buf_copy_metadata(src, dst, true); + ctx->codec_ops->run(ctx); return; @@ -262,28 +288,74 @@ static const struct v4l2_ctrl_ops hantro_ctrl_ops = { .s_ctrl = hantro_s_ctrl, }; -static struct hantro_ctrl controls[] = { +static const struct hantro_ctrl controls[] = { { - .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, .codec = HANTRO_JPEG_ENCODER, .cfg = { + .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, .min = 5, .max = 100, .step = 1, .def = 50, + .ops = &hantro_ctrl_ops, }, }, { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, .codec = HANTRO_MPEG2_DECODER, .cfg = { - .elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params), + .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, }, }, { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, .codec = HANTRO_MPEG2_DECODER, .cfg = { - .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization), + .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, + }, + }, { + .codec = HANTRO_VP8_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SPS, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_PPS, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, + .min = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + .def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + .max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_START_CODE, + .min = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + .def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + .max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + }, + }, { }, }; @@ -298,22 +370,12 @@ static int hantro_ctrls_setup(struct hantro_dev *vpu, for (i = 0; i < num_ctrls; i++) { if (!(allowed_codecs & controls[i].codec)) continue; - if (!controls[i].cfg.elem_size) { - v4l2_ctrl_new_std(&ctx->ctrl_handler, - &hantro_ctrl_ops, - controls[i].id, controls[i].cfg.min, - controls[i].cfg.max, - controls[i].cfg.step, - controls[i].cfg.def); - } else { - controls[i].cfg.id = controls[i].id; - v4l2_ctrl_new_custom(&ctx->ctrl_handler, - &controls[i].cfg, NULL); - } + v4l2_ctrl_new_custom(&ctx->ctrl_handler, + &controls[i].cfg, NULL); if (ctx->ctrl_handler.error) { vpu_err("Adding control (%d) failed %d\n", - controls[i].id, + controls[i].cfg.id, ctx->ctrl_handler.error); v4l2_ctrl_handler_free(&ctx->ctrl_handler); return ctx->ctrl_handler.error; @@ -419,6 +481,7 @@ static const struct v4l2_file_operations hantro_fops = { static const struct of_device_id of_hantro_match[] = { #ifdef CONFIG_VIDEO_HANTRO_ROCKCHIP { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, + { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, #endif { /* sentinel */ } @@ -724,6 +787,7 @@ static int hantro_probe(struct platform_device *pdev) dev_err(vpu->dev, "Could not set DMA coherent mask.\n"); return ret; } + vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); for (i = 0; i < vpu->variant->num_irqs; i++) { const char *irq_name = vpu->variant->irqs[i].name; diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c new file mode 100644 index 000000000000..7ab534936843 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (c) 2014 Rockchip Electronics Co., Ltd. + * Hertz Wong <hertz.wong@rock-chips.com> + * Herman Chen <herman.chen@rock-chips.com> + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa <tfiga@chromium.org> + */ + +#include <linux/types.h> +#include <linux/sort.h> + +#include <media/v4l2-mem2mem.h> + +#include "hantro_g1_regs.h" +#include "hantro_hw.h" +#include "hantro_v4l2.h" + +static void set_params(struct hantro_ctx *ctx) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; + const struct v4l2_ctrl_h264_slice_params *slices = ctrls->slices; + const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; + const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; + struct vb2_v4l2_buffer *src_buf = hantro_get_src_buf(ctx); + struct hantro_dev *vpu = ctx->dev; + u32 reg; + + /* Decoder control register 0. */ + reg = G1_REG_DEC_CTRL0_DEC_AXI_WR_ID(0x0); + if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) + reg |= G1_REG_DEC_CTRL0_SEQ_MBAFF_E; + reg |= G1_REG_DEC_CTRL0_PICORD_COUNT_E; + if (dec_param->nal_ref_idc) + reg |= G1_REG_DEC_CTRL0_WRITE_MVS_E; + + if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && + (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || + slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)) + reg |= G1_REG_DEC_CTRL0_PIC_INTERLACE_E; + if (slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) + reg |= G1_REG_DEC_CTRL0_PIC_FIELDMODE_E; + if (!(slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)) + reg |= G1_REG_DEC_CTRL0_PIC_TOPFIELD_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0); + + /* Decoder control register 1. */ + reg = G1_REG_DEC_CTRL1_PIC_MB_WIDTH(sps->pic_width_in_mbs_minus1 + 1) | + G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(sps->pic_height_in_map_units_minus1 + 1) | + G1_REG_DEC_CTRL1_REF_FRAMES(sps->max_num_ref_frames); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL1); + + /* Decoder control register 2. */ + reg = G1_REG_DEC_CTRL2_CH_QP_OFFSET(pps->chroma_qp_index_offset) | + G1_REG_DEC_CTRL2_CH_QP_OFFSET2(pps->second_chroma_qp_index_offset); + + /* always use the matrix sent from userspace */ + reg |= G1_REG_DEC_CTRL2_TYPE1_QUANT_E; + + if (slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) + reg |= G1_REG_DEC_CTRL2_FIELDPIC_FLAG_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL2); + + /* Decoder control register 3. */ + reg = G1_REG_DEC_CTRL3_START_CODE_E | + G1_REG_DEC_CTRL3_INIT_QP(pps->pic_init_qp_minus26 + 26) | + G1_REG_DEC_CTRL3_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0)); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL3); + + /* Decoder control register 4. */ + reg = G1_REG_DEC_CTRL4_FRAMENUM_LEN(sps->log2_max_frame_num_minus4 + 4) | + G1_REG_DEC_CTRL4_FRAMENUM(slices[0].frame_num) | + G1_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc); + if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) + reg |= G1_REG_DEC_CTRL4_CABAC_E; + if (sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) + reg |= G1_REG_DEC_CTRL4_DIR_8X8_INFER_E; + if (sps->chroma_format_idc == 0) + reg |= G1_REG_DEC_CTRL4_BLACKWHITE_E; + if (pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) + reg |= G1_REG_DEC_CTRL4_WEIGHT_PRED_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL4); + + /* Decoder control register 5. */ + reg = G1_REG_DEC_CTRL5_REFPIC_MK_LEN(slices[0].dec_ref_pic_marking_bit_size) | + G1_REG_DEC_CTRL5_IDR_PIC_ID(slices[0].idr_pic_id); + if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) + reg |= G1_REG_DEC_CTRL5_CONST_INTRA_E; + if (pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) + reg |= G1_REG_DEC_CTRL5_FILT_CTRL_PRES; + if (pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT) + reg |= G1_REG_DEC_CTRL5_RDPIC_CNT_PRES; + if (pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) + reg |= G1_REG_DEC_CTRL5_8X8TRANS_FLAG_E; + if (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) + reg |= G1_REG_DEC_CTRL5_IDR_PIC_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL5); + + /* Decoder control register 6. */ + reg = G1_REG_DEC_CTRL6_PPS_ID(slices[0].pic_parameter_set_id) | + G1_REG_DEC_CTRL6_REFIDX0_ACTIVE(pps->num_ref_idx_l0_default_active_minus1 + 1) | + G1_REG_DEC_CTRL6_REFIDX1_ACTIVE(pps->num_ref_idx_l1_default_active_minus1 + 1) | + G1_REG_DEC_CTRL6_POC_LENGTH(slices[0].pic_order_cnt_bit_size); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL6); + + /* Error concealment register. */ + vdpu_write_relaxed(vpu, 0, G1_REG_ERR_CONC); + + /* Prediction filter tap register. */ + vdpu_write_relaxed(vpu, + G1_REG_PRED_FLT_PRED_BC_TAP_0_0(1) | + G1_REG_PRED_FLT_PRED_BC_TAP_0_1(-5 & 0x3ff) | + G1_REG_PRED_FLT_PRED_BC_TAP_0_2(20), + G1_REG_PRED_FLT); + + /* Reference picture buffer control register. */ + vdpu_write_relaxed(vpu, 0, G1_REG_REF_BUF_CTRL); + + /* Reference picture buffer control register 2. */ + vdpu_write_relaxed(vpu, G1_REG_REF_BUF_CTRL2_APF_THRESHOLD(8), + G1_REG_REF_BUF_CTRL2); +} + +static void set_ref(struct hantro_ctx *ctx) +{ + struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + const u8 *b0_reflist, *b1_reflist, *p_reflist; + struct hantro_dev *vpu = ctx->dev; + u32 dpb_longterm = 0; + u32 dpb_valid = 0; + int reg_num; + u32 reg; + int i; + + /* + * Set up bit maps of valid and long term DPBs. + * NOTE: The bits are reversed, i.e. MSb is DPB 0. + */ + for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); + } + vdpu_write_relaxed(vpu, dpb_valid << 16, G1_REG_VALID_REF); + vdpu_write_relaxed(vpu, dpb_longterm << 16, G1_REG_LT_REF); + + /* + * Set up reference frame picture numbers. + * + * Each G1_REG_REF_PIC(x) register contains numbers of two + * subsequential reference pictures. + */ + for (i = 0; i < HANTRO_H264_DPB_SIZE; i += 2) { + reg = 0; + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].pic_num); + else + reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].frame_num); + + if (dpb[i + 1].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].pic_num); + else + reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].frame_num); + + vdpu_write_relaxed(vpu, reg, G1_REG_REF_PIC(i / 2)); + } + + b0_reflist = ctx->h264_dec.reflists.b0; + b1_reflist = ctx->h264_dec.reflists.b1; + p_reflist = ctx->h264_dec.reflists.p; + + /* + * Each G1_REG_BD_REF_PIC(x) register contains three entries + * of each forward and backward picture list. + */ + reg_num = 0; + for (i = 0; i < 15; i += 3) { + reg = G1_REG_BD_REF_PIC_BINIT_RLIST_F0(b0_reflist[i]) | + G1_REG_BD_REF_PIC_BINIT_RLIST_F1(b0_reflist[i + 1]) | + G1_REG_BD_REF_PIC_BINIT_RLIST_F2(b0_reflist[i + 2]) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B0(b1_reflist[i]) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B1(b1_reflist[i + 1]) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B2(b1_reflist[i + 2]); + vdpu_write_relaxed(vpu, reg, G1_REG_BD_REF_PIC(reg_num++)); + } + + /* + * G1_REG_BD_P_REF_PIC register contains last entries (index 15) + * of forward and backward reference picture lists and first 4 entries + * of P forward picture list. + */ + reg = G1_REG_BD_P_REF_PIC_BINIT_RLIST_F15(b0_reflist[15]) | + G1_REG_BD_P_REF_PIC_BINIT_RLIST_B15(b1_reflist[15]) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F0(p_reflist[0]) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F1(p_reflist[1]) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F2(p_reflist[2]) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F3(p_reflist[3]); + vdpu_write_relaxed(vpu, reg, G1_REG_BD_P_REF_PIC); + + /* + * Each G1_REG_FWD_PIC(x) register contains six consecutive + * entries of P forward picture list, starting from index 4. + */ + reg_num = 0; + for (i = 4; i < HANTRO_H264_DPB_SIZE; i += 6) { + reg = G1_REG_FWD_PIC_PINIT_RLIST_F0(p_reflist[i]) | + G1_REG_FWD_PIC_PINIT_RLIST_F1(p_reflist[i + 1]) | + G1_REG_FWD_PIC_PINIT_RLIST_F2(p_reflist[i + 2]) | + G1_REG_FWD_PIC_PINIT_RLIST_F3(p_reflist[i + 3]) | + G1_REG_FWD_PIC_PINIT_RLIST_F4(p_reflist[i + 4]) | + G1_REG_FWD_PIC_PINIT_RLIST_F5(p_reflist[i + 5]); + vdpu_write_relaxed(vpu, reg, G1_REG_FWD_PIC(reg_num++)); + } + + /* Set up addresses of DPB buffers. */ + for (i = 0; i < HANTRO_H264_DPB_SIZE; i++) { + struct vb2_buffer *buf = hantro_h264_get_ref_buf(ctx, i); + + vdpu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(buf, 0), + G1_REG_ADDR_REF(i)); + } +} + +static void set_buffers(struct hantro_ctx *ctx) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct hantro_dev *vpu = ctx->dev; + dma_addr_t src_dma, dst_dma; + + src_buf = hantro_get_src_buf(ctx); + dst_buf = hantro_get_dst_buf(ctx); + + /* Source (stream) buffer. */ + src_dma = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + vdpu_write_relaxed(vpu, src_dma, G1_REG_ADDR_STR); + + /* Destination (decoded frame) buffer. */ + dst_dma = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + vdpu_write_relaxed(vpu, dst_dma, G1_REG_ADDR_DST); + + /* Higher profiles require DMV buffer appended to reference frames. */ + if (ctrls->sps->profile_idc > 66) { + size_t pic_size = ctx->h264_dec.pic_size; + size_t mv_offset = round_up(pic_size, 8); + + if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) + mv_offset += 32 * H264_MB_WIDTH(ctx->dst_fmt.width); + + vdpu_write_relaxed(vpu, dst_dma + mv_offset, + G1_REG_ADDR_DIR_MV); + } + + /* Auxiliary buffer prepared in hantro_g1_h264_dec_prepare_table(). */ + vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, G1_REG_ADDR_QTABLE); +} + +void hantro_g1_h264_dec_run(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + /* Prepare the H264 decoder context. */ + if (hantro_h264_dec_prepare_run(ctx)) + return; + + /* Configure hardware registers. */ + set_params(ctx); + set_ref(ctx); + set_buffers(ctx); + + hantro_finish_run(ctx); + + /* Start decoding! */ + vdpu_write_relaxed(vpu, + G1_REG_CONFIG_DEC_AXI_RD_ID(0xffu) | + G1_REG_CONFIG_DEC_TIMEOUT_E | + G1_REG_CONFIG_DEC_OUT_ENDIAN | + G1_REG_CONFIG_DEC_STRENDIAN_E | + G1_REG_CONFIG_DEC_MAX_BURST(16) | + G1_REG_CONFIG_DEC_OUTSWAP32_E | + G1_REG_CONFIG_DEC_INSWAP32_E | + G1_REG_CONFIG_DEC_STRSWAP32_E | + G1_REG_CONFIG_DEC_CLK_GATE_E, + G1_REG_CONFIG); + vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT); +} diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c index e592c1b66375..80f0e94f8afa 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -167,12 +167,11 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) const struct v4l2_mpeg2_picture *picture; u32 reg; - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = hantro_get_src_buf(ctx); + dst_buf = hantro_get_dst_buf(ctx); /* Apply request controls if any */ - v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, - &ctx->ctrl_handler); + hantro_prepare_run(ctx); slice_params = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); @@ -248,12 +247,7 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) &dst_buf->vb2_buf, sequence, picture, slice_params); - /* Controls no longer in-use, we can complete them */ - v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req, - &ctx->ctrl_handler); - - /* Kick the watchdog and start decoding */ - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + hantro_finish_run(ctx); reg = G1_REG_DEC_E(1); vdpu_write(vpu, reg, G1_SWREG(1)); diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c new file mode 100644 index 000000000000..6d99c2be01cf --- /dev/null +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VP8 codec driver + * + * Copyright (C) 2019 Rockchip Electronics Co., Ltd. + * ZhiChao Yu <zhichao.yu@rock-chips.com> + * + * Copyright (C) 2019 Google, Inc. + * Tomasz Figa <tfiga@chromium.org> + */ + +#include <media/v4l2-mem2mem.h> +#include <media/vp8-ctrls.h> + +#include "hantro_hw.h" +#include "hantro.h" +#include "hantro_g1_regs.h" + +/* DCT partition base address regs */ +static const struct hantro_reg vp8_dec_dct_base[8] = { + { G1_REG_ADDR_STR, 0, 0xffffffff }, + { G1_REG_ADDR_REF(8), 0, 0xffffffff }, + { G1_REG_ADDR_REF(9), 0, 0xffffffff }, + { G1_REG_ADDR_REF(10), 0, 0xffffffff }, + { G1_REG_ADDR_REF(11), 0, 0xffffffff }, + { G1_REG_ADDR_REF(12), 0, 0xffffffff }, + { G1_REG_ADDR_REF(14), 0, 0xffffffff }, + { G1_REG_ADDR_REF(15), 0, 0xffffffff }, +}; + +/* Loop filter level regs */ +static const struct hantro_reg vp8_dec_lf_level[4] = { + { G1_REG_REF_PIC(2), 18, 0x3f }, + { G1_REG_REF_PIC(2), 12, 0x3f }, + { G1_REG_REF_PIC(2), 6, 0x3f }, + { G1_REG_REF_PIC(2), 0, 0x3f }, +}; + +/* Macroblock loop filter level adjustment regs */ +static const struct hantro_reg vp8_dec_mb_adj[4] = { + { G1_REG_REF_PIC(0), 21, 0x7f }, + { G1_REG_REF_PIC(0), 14, 0x7f }, + { G1_REG_REF_PIC(0), 7, 0x7f }, + { G1_REG_REF_PIC(0), 0, 0x7f }, +}; + +/* Reference frame adjustment regs */ +static const struct hantro_reg vp8_dec_ref_adj[4] = { + { G1_REG_REF_PIC(1), 21, 0x7f }, + { G1_REG_REF_PIC(1), 14, 0x7f }, + { G1_REG_REF_PIC(1), 7, 0x7f }, + { G1_REG_REF_PIC(1), 0, 0x7f }, +}; + +/* Quantizer */ +static const struct hantro_reg vp8_dec_quant[4] = { + { G1_REG_REF_PIC(3), 11, 0x7ff }, + { G1_REG_REF_PIC(3), 0, 0x7ff }, + { G1_REG_BD_REF_PIC(4), 11, 0x7ff }, + { G1_REG_BD_REF_PIC(4), 0, 0x7ff }, +}; + +/* Quantizer delta regs */ +static const struct hantro_reg vp8_dec_quant_delta[5] = { + { G1_REG_REF_PIC(3), 27, 0x1f }, + { G1_REG_REF_PIC(3), 22, 0x1f }, + { G1_REG_BD_REF_PIC(4), 27, 0x1f }, + { G1_REG_BD_REF_PIC(4), 22, 0x1f }, + { G1_REG_BD_P_REF_PIC, 27, 0x1f }, +}; + +/* DCT partition start bits regs */ +static const struct hantro_reg vp8_dec_dct_start_bits[8] = { + { G1_REG_DEC_CTRL2, 26, 0x3f }, { G1_REG_DEC_CTRL4, 26, 0x3f }, + { G1_REG_DEC_CTRL4, 20, 0x3f }, { G1_REG_DEC_CTRL7, 24, 0x3f }, + { G1_REG_DEC_CTRL7, 18, 0x3f }, { G1_REG_DEC_CTRL7, 12, 0x3f }, + { G1_REG_DEC_CTRL7, 6, 0x3f }, { G1_REG_DEC_CTRL7, 0, 0x3f }, +}; + +/* Precision filter tap regs */ +static const struct hantro_reg vp8_dec_pred_bc_tap[8][4] = { + { + { G1_REG_PRED_FLT, 22, 0x3ff }, + { G1_REG_PRED_FLT, 12, 0x3ff }, + { G1_REG_PRED_FLT, 2, 0x3ff }, + { G1_REG_REF_PIC(4), 22, 0x3ff }, + }, + { + { G1_REG_REF_PIC(4), 12, 0x3ff }, + { G1_REG_REF_PIC(4), 2, 0x3ff }, + { G1_REG_REF_PIC(5), 22, 0x3ff }, + { G1_REG_REF_PIC(5), 12, 0x3ff }, + }, + { + { G1_REG_REF_PIC(5), 2, 0x3ff }, + { G1_REG_REF_PIC(6), 22, 0x3ff }, + { G1_REG_REF_PIC(6), 12, 0x3ff }, + { G1_REG_REF_PIC(6), 2, 0x3ff }, + }, + { + { G1_REG_REF_PIC(7), 22, 0x3ff }, + { G1_REG_REF_PIC(7), 12, 0x3ff }, + { G1_REG_REF_PIC(7), 2, 0x3ff }, + { G1_REG_LT_REF, 22, 0x3ff }, + }, + { + { G1_REG_LT_REF, 12, 0x3ff }, + { G1_REG_LT_REF, 2, 0x3ff }, + { G1_REG_VALID_REF, 22, 0x3ff }, + { G1_REG_VALID_REF, 12, 0x3ff }, + }, + { + { G1_REG_VALID_REF, 2, 0x3ff }, + { G1_REG_BD_REF_PIC(0), 22, 0x3ff }, + { G1_REG_BD_REF_PIC(0), 12, 0x3ff }, + { G1_REG_BD_REF_PIC(0), 2, 0x3ff }, + }, + { + { G1_REG_BD_REF_PIC(1), 22, 0x3ff }, + { G1_REG_BD_REF_PIC(1), 12, 0x3ff }, + { G1_REG_BD_REF_PIC(1), 2, 0x3ff }, + { G1_REG_BD_REF_PIC(2), 22, 0x3ff }, + }, + { + { G1_REG_BD_REF_PIC(2), 12, 0x3ff }, + { G1_REG_BD_REF_PIC(2), 2, 0x3ff }, + { G1_REG_BD_REF_PIC(3), 22, 0x3ff }, + { G1_REG_BD_REF_PIC(3), 12, 0x3ff }, + }, +}; + +/* + * Set loop filters + */ +static void cfg_lf(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + const struct v4l2_vp8_loopfilter_header *lf = &hdr->lf_header; + struct hantro_dev *vpu = ctx->dev; + unsigned int i; + u32 reg; + + if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) { + hantro_reg_write(vpu, &vp8_dec_lf_level[0], lf->level); + } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) { + for (i = 0; i < 4; i++) { + u32 lf_level = clamp(lf->level + seg->lf_update[i], + 0, 63); + + hantro_reg_write(vpu, &vp8_dec_lf_level[i], lf_level); + } + } else { + for (i = 0; i < 4; i++) + hantro_reg_write(vpu, &vp8_dec_lf_level[i], + seg->lf_update[i]); + } + + reg = G1_REG_REF_PIC_FILT_SHARPNESS(lf->sharpness_level); + if (lf->flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE) + reg |= G1_REG_REF_PIC_FILT_TYPE_E; + vdpu_write_relaxed(vpu, reg, G1_REG_REF_PIC(0)); + + if (lf->flags & V4L2_VP8_LF_HEADER_ADJ_ENABLE) { + for (i = 0; i < 4; i++) { + hantro_reg_write(vpu, &vp8_dec_mb_adj[i], + lf->mb_mode_delta[i]); + hantro_reg_write(vpu, &vp8_dec_ref_adj[i], + lf->ref_frm_delta[i]); + } + } +} + +/* + * Set quantization parameters + */ +static void cfg_qp(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_quantization_header *q = &hdr->quant_header; + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + struct hantro_dev *vpu = ctx->dev; + unsigned int i; + + if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) { + hantro_reg_write(vpu, &vp8_dec_quant[0], q->y_ac_qi); + } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) { + for (i = 0; i < 4; i++) { + u32 quant = clamp(q->y_ac_qi + seg->quant_update[i], + 0, 127); + + hantro_reg_write(vpu, &vp8_dec_quant[i], quant); + } + } else { + for (i = 0; i < 4; i++) + hantro_reg_write(vpu, &vp8_dec_quant[i], + seg->quant_update[i]); + } + + hantro_reg_write(vpu, &vp8_dec_quant_delta[0], q->y_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[1], q->y2_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[2], q->y2_ac_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[3], q->uv_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[4], q->uv_ac_delta); +} + +/* + * set control partition and DCT partition regs + * + * VP8 frame stream data layout: + * + * first_part_size parttion_sizes[0] + * ^ ^ + * src_dma | | + * ^ +--------+------+ +-----+-----+ + * | | control part | | | + * +--------+----------------+------------------+-----------+-----+-----------+ + * | tag 3B | extra 7B | hdr | mb_data | DCT sz | DCT part0 | ... | DCT partn | + * +--------+-----------------------------------+-----------+-----+-----------+ + * | | | | + * v +----+---+ v + * mb_start | src_dma_end + * v + * DCT size part + * (num_dct-1)*3B + * Note: + * 1. only key-frames have extra 7-bytes + * 2. all offsets are base on src_dma + * 3. number of DCT parts is 1, 2, 4 or 8 + * 4. the addresses set to the VPU must be 64-bits aligned + */ +static void cfg_parts(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_src; + u32 first_part_offset = VP8_FRAME_IS_KEY_FRAME(hdr) ? 10 : 3; + u32 mb_size, mb_offset_bytes, mb_offset_bits, mb_start_bits; + u32 dct_size_part_size, dct_part_offset; + struct hantro_reg reg; + dma_addr_t src_dma; + u32 dct_part_total_len = 0; + u32 count = 0; + unsigned int i; + + vb2_src = hantro_get_src_buf(ctx); + src_dma = vb2_dma_contig_plane_dma_addr(&vb2_src->vb2_buf, 0); + + /* + * Calculate control partition mb data info + * @first_part_header_bits: bits offset of mb data from first + * part start pos + * @mb_offset_bits: bits offset of mb data from src_dma + * base addr + * @mb_offset_byte: bytes offset of mb data from src_dma + * base addr + * @mb_start_bits: bits offset of mb data from mb data + * 64bits alignment addr + */ + mb_offset_bits = first_part_offset * 8 + + hdr->first_part_header_bits + 8; + mb_offset_bytes = mb_offset_bits / 8; + mb_start_bits = mb_offset_bits - + (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) * 8; + mb_size = hdr->first_part_size - + (mb_offset_bytes - first_part_offset) + + (mb_offset_bytes & DEC_8190_ALIGN_MASK); + + /* Macroblock data aligned base addr */ + vdpu_write_relaxed(vpu, (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) + + src_dma, G1_REG_ADDR_REF(13)); + + /* Macroblock data start bits */ + reg.base = G1_REG_DEC_CTRL2; + reg.mask = 0x3f; + reg.shift = 18; + hantro_reg_write(vpu, ®, mb_start_bits); + + /* Macroblock aligned data length */ + reg.base = G1_REG_DEC_CTRL6; + reg.mask = 0x3fffff; + reg.shift = 0; + hantro_reg_write(vpu, ®, mb_size + 1); + + /* + * Calculate DCT partition info + * @dct_size_part_size: Containing sizes of DCT part, every DCT part + * has 3 bytes to store its size, except the last + * DCT part + * @dct_part_offset: bytes offset of DCT parts from src_dma base addr + * @dct_part_total_len: total size of all DCT parts + */ + dct_size_part_size = (hdr->num_dct_parts - 1) * 3; + dct_part_offset = first_part_offset + hdr->first_part_size; + for (i = 0; i < hdr->num_dct_parts; i++) + dct_part_total_len += hdr->dct_part_sizes[i]; + dct_part_total_len += dct_size_part_size; + dct_part_total_len += (dct_part_offset & DEC_8190_ALIGN_MASK); + + /* Number of DCT partitions */ + reg.base = G1_REG_DEC_CTRL6; + reg.mask = 0xf; + reg.shift = 24; + hantro_reg_write(vpu, ®, hdr->num_dct_parts - 1); + + /* DCT partition length */ + vdpu_write_relaxed(vpu, + G1_REG_DEC_CTRL3_STREAM_LEN(dct_part_total_len), + G1_REG_DEC_CTRL3); + + /* DCT partitions base address */ + for (i = 0; i < hdr->num_dct_parts; i++) { + u32 byte_offset = dct_part_offset + dct_size_part_size + count; + u32 base_addr = byte_offset + src_dma; + + hantro_reg_write(vpu, &vp8_dec_dct_base[i], + base_addr & (~DEC_8190_ALIGN_MASK)); + + hantro_reg_write(vpu, &vp8_dec_dct_start_bits[i], + (byte_offset & DEC_8190_ALIGN_MASK) * 8); + + count += hdr->dct_part_sizes[i]; + } +} + +/* + * prediction filter taps + * normal 6-tap filters + */ +static void cfg_tap(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_reg reg; + u32 val = 0; + int i, j; + + reg.base = G1_REG_BD_REF_PIC(3); + reg.mask = 0xf; + + if ((hdr->version & 0x03) != 0) + return; /* Tap filter not used. */ + + for (i = 0; i < 8; i++) { + val = (hantro_vp8_dec_mc_filter[i][0] << 2) | + hantro_vp8_dec_mc_filter[i][5]; + + for (j = 0; j < 4; j++) + hantro_reg_write(vpu, &vp8_dec_pred_bc_tap[i][j], + hantro_vp8_dec_mc_filter[i][j + 1]); + + switch (i) { + case 2: + reg.shift = 8; + break; + case 4: + reg.shift = 4; + break; + case 6: + reg.shift = 0; + break; + default: + continue; + } + + hantro_reg_write(vpu, ®, val); + } +} + +static void cfg_ref(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; + dma_addr_t ref; + + vb2_dst = hantro_get_dst_buf(ctx); + + ref = hantro_get_ref(cap_q, hdr->last_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(0)); + + ref = hantro_get_ref(cap_q, hdr->golden_frame_ts); + WARN_ON(!ref && hdr->golden_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN) + ref |= G1_REG_ADDR_REF_TOPC_E; + vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(4)); + + ref = hantro_get_ref(cap_q, hdr->alt_frame_ts); + WARN_ON(!ref && hdr->alt_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT) + ref |= G1_REG_ADDR_REF_TOPC_E; + vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(5)); +} + +static void cfg_buffers(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; + dma_addr_t dst_dma; + u32 reg; + + vb2_dst = hantro_get_dst_buf(ctx); + + /* Set probability table buffer address */ + vdpu_write_relaxed(vpu, ctx->vp8_dec.prob_tbl.dma, + G1_REG_ADDR_QTABLE); + + /* Set segment map address */ + reg = G1_REG_FWD_PIC1_SEGMENT_BASE(ctx->vp8_dec.segment_map.dma); + if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED) { + reg |= G1_REG_FWD_PIC1_SEGMENT_E; + if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP) + reg |= G1_REG_FWD_PIC1_SEGMENT_UPD_E; + } + vdpu_write_relaxed(vpu, reg, G1_REG_FWD_PIC(0)); + + dst_dma = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + vdpu_write_relaxed(vpu, dst_dma, G1_REG_ADDR_DST); +} + +void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_header *hdr; + struct hantro_dev *vpu = ctx->dev; + size_t height = ctx->dst_fmt.height; + size_t width = ctx->dst_fmt.width; + u32 mb_width, mb_height; + u32 reg; + + hantro_prepare_run(ctx); + + hdr = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER); + if (WARN_ON(!hdr)) + return; + + /* Reset segment_map buffer in keyframe */ + if (VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu) + memset(ctx->vp8_dec.segment_map.cpu, 0, + ctx->vp8_dec.segment_map.size); + + hantro_vp8_prob_update(ctx, hdr); + + reg = G1_REG_CONFIG_DEC_TIMEOUT_E | + G1_REG_CONFIG_DEC_STRENDIAN_E | + G1_REG_CONFIG_DEC_INSWAP32_E | + G1_REG_CONFIG_DEC_STRSWAP32_E | + G1_REG_CONFIG_DEC_OUTSWAP32_E | + G1_REG_CONFIG_DEC_CLK_GATE_E | + G1_REG_CONFIG_DEC_IN_ENDIAN | + G1_REG_CONFIG_DEC_OUT_ENDIAN | + G1_REG_CONFIG_DEC_MAX_BURST(16); + vdpu_write_relaxed(vpu, reg, G1_REG_CONFIG); + + reg = G1_REG_DEC_CTRL0_DEC_MODE(10); + if (!VP8_FRAME_IS_KEY_FRAME(hdr)) + reg |= G1_REG_DEC_CTRL0_PIC_INTER_E; + if (!(hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF)) + reg |= G1_REG_DEC_CTRL0_SKIP_MODE; + if (hdr->lf_header.level == 0) + reg |= G1_REG_DEC_CTRL0_FILTERING_DIS; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0); + + /* Frame dimensions */ + mb_width = VP8_MB_WIDTH(width); + mb_height = VP8_MB_HEIGHT(height); + reg = G1_REG_DEC_CTRL1_PIC_MB_WIDTH(mb_width) | + G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(mb_height) | + G1_REG_DEC_CTRL1_PIC_MB_W_EXT(mb_width >> 9) | + G1_REG_DEC_CTRL1_PIC_MB_H_EXT(mb_height >> 8); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL1); + + /* Boolean decoder */ + reg = G1_REG_DEC_CTRL2_BOOLEAN_RANGE(hdr->coder_state.range) + | G1_REG_DEC_CTRL2_BOOLEAN_VALUE(hdr->coder_state.value); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL2); + + reg = 0; + if (hdr->version != 3) + reg |= G1_REG_DEC_CTRL4_VC1_HEIGHT_EXT; + if (hdr->version & 0x3) + reg |= G1_REG_DEC_CTRL4_BILIN_MC_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL4); + + cfg_lf(ctx, hdr); + cfg_qp(ctx, hdr); + cfg_parts(ctx, hdr); + cfg_tap(ctx, hdr); + cfg_ref(ctx, hdr); + cfg_buffers(ctx, hdr); + + hantro_finish_run(ctx); + + vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT); +} diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c index 0c1e3043dc7e..ecd34a7db190 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -84,8 +84,10 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) struct hantro_jpeg_ctx jpeg_ctx; u32 reg; - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = hantro_get_src_buf(ctx); + dst_buf = hantro_get_dst_buf(ctx); + + hantro_prepare_run(ctx); memset(&jpeg_ctx, 0, sizeof(jpeg_ctx)); jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); @@ -119,7 +121,8 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) | H1_REG_ENC_CTRL_ENC_MODE_JPEG | H1_REG_ENC_PIC_INTRA | H1_REG_ENC_CTRL_EN_BIT; - /* Kick the watchdog and start encoding */ - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + + hantro_finish_run(ctx); + vepu_write(vpu, reg, H1_REG_ENC_CTRL); } diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c new file mode 100644 index 000000000000..0d758e0c0f99 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_h264.c @@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (c) 2014 Rockchip Electronics Co., Ltd. + * Hertz Wong <hertz.wong@rock-chips.com> + * Herman Chen <herman.chen@rock-chips.com> + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa <tfiga@chromium.org> + */ + +#include <linux/types.h> +#include <linux/sort.h> +#include <media/v4l2-mem2mem.h> + +#include "hantro.h" +#include "hantro_hw.h" + +/* Size with u32 units. */ +#define CABAC_INIT_BUFFER_SIZE (460 * 2) +#define POC_BUFFER_SIZE 34 +#define SCALING_LIST_SIZE (6 * 16 + 6 * 64) + +#define POC_CMP(p0, p1) ((p0) < (p1) ? -1 : 1) + +/* Data structure describing auxiliary buffer format. */ +struct hantro_h264_dec_priv_tbl { + u32 cabac_table[CABAC_INIT_BUFFER_SIZE]; + u32 poc[POC_BUFFER_SIZE]; + u8 scaling_list[SCALING_LIST_SIZE]; +}; + +/* + * Constant CABAC table. + * From drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_h264d.c + * in https://chromium.googlesource.com/chromiumos/third_party/kernel, + * chromeos-3.14 branch. + */ +static const u32 h264_cabac_table[] = { + 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07330000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, 0x0d29033e, 0x000b0137, + 0x0045ef7f, 0xf3660052, 0xf94aeb6b, 0xe57fe17f, 0xe87fee5f, 0xe57feb72, + 0xe27fef7b, 0xf473f07a, 0xf573f43f, 0xfe44f154, 0xf368fd46, 0xf85df65a, + 0xe27fff4a, 0xfa61f95b, 0xec7ffc38, 0xfb52f94c, 0xea7df95d, 0xf557fd4d, + 0xfb47fc3f, 0xfc44f454, 0xf93ef941, 0x083d0538, 0xfe420140, 0x003dfe4e, + 0x01320734, 0x0a23002c, 0x0b26012d, 0x002e052c, 0x1f110133, 0x07321c13, + 0x10210e3e, 0xf36cf164, 0xf365f35b, 0xf45ef658, 0xf054f656, 0xf953f357, + 0xed5e0146, 0x0048fb4a, 0x123bf866, 0xf164005f, 0xfc4b0248, 0xf54bfd47, + 0x0f2ef345, 0x003e0041, 0x1525f148, 0x09391036, 0x003e0c48, 0x18000f09, + 0x08190d12, 0x0f090d13, 0x0a250c12, 0x061d1421, 0x0f1e042d, 0x013a003e, + 0x073d0c26, 0x0b2d0f27, 0x0b2a0d2c, 0x102d0c29, 0x0a311e22, 0x122a0a37, + 0x1133112e, 0x00591aed, 0x16ef1aef, 0x1ee71cec, 0x21e925e5, 0x21e928e4, + 0x26ef21f5, 0x28f129fa, 0x26012911, 0x1efa1b03, 0x1a1625f0, 0x23fc26f8, + 0x26fd2503, 0x26052a00, 0x23102716, 0x0e301b25, 0x153c0c44, 0x0261fd47, + 0xfa2afb32, 0xfd36fe3e, 0x003a013f, 0xfe48ff4a, 0xf75bfb43, 0xfb1bfd27, + 0xfe2c002e, 0xf040f844, 0xf64efa4d, 0xf656f45c, 0xf137f63c, 0xfa3efc41, + 0xf449f84c, 0xf950f758, 0xef6ef561, 0xec54f54f, 0xfa49fc4a, 0xf356f360, + 0xf561ed75, 0xf84efb21, 0xfc30fe35, 0xfd3ef347, 0xf64ff456, 0xf35af261, + 0x0000fa5d, 0xfa54f84f, 0x0042ff47, 0x003efe3c, 0xfe3bfb4b, 0xfd3efc3a, + 0xf742ff4f, 0x00470344, 0x0a2cf93e, 0x0f240e28, 0x101b0c1d, 0x012c1424, + 0x1220052a, 0x01300a3e, 0x112e0940, 0xf468f561, 0xf060f958, 0xf855f955, + 0xf755f358, 0x0442fd4d, 0xfd4cfa4c, 0x0a3aff4c, 0xff53f963, 0xf25f025f, + 0x004cfb4a, 0x0046f54b, 0x01440041, 0xf249033e, 0x043eff44, 0xf34b0b37, + 0x05400c46, 0x0f060613, 0x07100c0e, 0x120d0d0b, 0x0d0f0f10, 0x0c170d17, + 0x0f140e1a, 0x0e2c1128, 0x112f1811, 0x15151916, 0x1f1b161d, 0x13230e32, + 0x0a39073f, 0xfe4dfc52, 0xfd5e0945, 0xf46d24dd, 0x24de20e6, 0x25e22ce0, + 0x22ee22f1, 0x28f121f9, 0x23fb2100, 0x2602210d, 0x17230d3a, 0x1dfd1a00, + 0x161e1ff9, 0x23f122fd, 0x220324ff, 0x2205200b, 0x2305220c, 0x270b1e1d, + 0x221a1d27, 0x13421f15, 0x1f1f1932, 0xef78ec70, 0xee72f555, 0xf15cf259, + 0xe647f151, 0xf2500044, 0xf246e838, 0xe944e832, 0xf54a17f3, 0x1af328f1, + 0x31f22c03, 0x2d062c22, 0x21361352, 0xfd4bff17, 0x0122012b, 0x0036fe37, + 0x003d0140, 0x0044f75c, 0xf26af361, 0xf15af45a, 0xee58f649, 0xf74ff256, + 0xf649f646, 0xf645fb42, 0xf740fb3a, 0x023b15f6, 0x18f51cf8, 0x1cff1d03, + 0x1d092314, 0x1d240e43, 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, + 0xfa35ff36, 0x07331721, 0x17021500, 0x01090031, 0xdb760539, 0xf34ef541, + 0x013e0c31, 0xfc491132, 0x1240092b, 0x1d001a43, 0x105a0968, 0xd27fec68, + 0x0143f34e, 0xf541013e, 0xfa56ef5f, 0xfa3d092d, 0xfd45fa51, 0xf5600637, + 0x0743fb56, 0x0258003a, 0xfd4cf65e, 0x05360445, 0xfd510058, 0xf943fb4a, + 0xfc4afb50, 0xf948013a, 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, + 0x0d29033e, 0x002dfc4e, 0xfd60e57e, 0xe462e765, 0xe943e452, 0xec5ef053, + 0xea6eeb5b, 0xee66f35d, 0xe37ff95c, 0xfb59f960, 0xf36cfd2e, 0xff41ff39, + 0xf75dfd4a, 0xf75cf857, 0xe97e0536, 0x063c063b, 0x0645ff30, 0x0044fc45, + 0xf858fe55, 0xfa4eff4b, 0xf94d0236, 0x0532fd44, 0x0132062a, 0xfc51013f, + 0xfc460043, 0x0239fe4c, 0x0b230440, 0x013d0b23, 0x12190c18, 0x0d1d0d24, + 0xf65df949, 0xfe490d2e, 0x0931f964, 0x09350235, 0x0535fe3d, 0x00380038, + 0xf33ffb3c, 0xff3e0439, 0xfa450439, 0x0e270433, 0x0d440340, 0x013d093f, + 0x07321027, 0x052c0434, 0x0b30fb3c, 0xff3b003b, 0x1621052c, 0x0e2bff4e, + 0x003c0945, 0x0b1c0228, 0x032c0031, 0x002e022c, 0x0233002f, 0x0427023e, + 0x062e0036, 0x0336023a, 0x043f0633, 0x06390735, 0x06340637, 0x0b2d0e24, + 0x0835ff52, 0x0737fd4e, 0x0f2e161f, 0xff541907, 0x1ef91c03, 0x1c042000, + 0x22ff1e06, 0x1e062009, 0x1f131a1b, 0x1a1e2514, 0x1c221146, 0x0143053b, + 0x0943101e, 0x12201223, 0x161d181f, 0x1726122b, 0x14290b3f, 0x093b0940, + 0xff5efe59, 0xf76cfa4c, 0xfe2c002d, 0x0034fd40, 0xfe3bfc46, 0xfc4bf852, + 0xef66f74d, 0x0318002a, 0x00300037, 0xfa3bf947, 0xf453f557, 0xe277013a, + 0xfd1dff24, 0x0126022b, 0xfa37003a, 0x0040fd4a, 0xf65a0046, 0xfc1d051f, + 0x072a013b, 0xfe3afd48, 0xfd51f561, 0x003a0805, 0x0a0e0e12, 0x0d1b0228, + 0x003afd46, 0xfa4ff855, 0x0000f36a, 0xf06af657, 0xeb72ee6e, 0xf262ea6e, + 0xeb6aee67, 0xeb6be96c, 0xe670f660, 0xf45ffb5b, 0xf75dea5e, 0xfb560943, + 0xfc50f655, 0xff46073c, 0x093a053d, 0x0c320f32, 0x12311136, 0x0a29072e, + 0xff330731, 0x08340929, 0x062f0237, 0x0d290a2c, 0x06320535, 0x0d31043f, + 0x0640fe45, 0xfe3b0646, 0x0a2c091f, 0x0c2b0335, 0x0e220a26, 0xfd340d28, + 0x1120072c, 0x07260d32, 0x0a391a2b, 0x0e0b0b0e, 0x090b120b, 0x150917fe, + 0x20f120f1, 0x22eb27e9, 0x2adf29e1, 0x2ee426f4, 0x151d2de8, 0x35d330e6, + 0x41d52bed, 0x27f61e09, 0x121a141b, 0x0039f252, 0xfb4bed61, 0xdd7d1b00, + 0x1c001ffc, 0x1b062208, 0x1e0a1816, 0x21131620, 0x1a1f1529, 0x1a2c172f, + 0x10410e47, 0x083c063f, 0x11411518, 0x17141a17, 0x1b201c17, 0x1c181728, + 0x18201c1d, 0x172a1339, 0x1635163d, 0x0b560c28, 0x0b330e3b, 0xfc4ff947, + 0xfb45f746, 0xf842f644, 0xed49f445, 0xf046f143, 0xec3eed46, 0xf042ea41, + 0xec3f09fe, 0x1af721f7, 0x27f929fe, 0x2d033109, 0x2d1b243b, 0xfa42f923, + 0xf92af82d, 0xfb30f438, 0xfa3cfb3e, 0xf842f84c, 0xfb55fa51, 0xf64df951, + 0xef50ee49, 0xfc4af653, 0xf747f743, 0xff3df842, 0xf242003b, 0x023b15f3, + 0x21f227f9, 0x2efe3302, 0x3c063d11, 0x37222a3e, 0x14f10236, 0x034a14f1, + 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07331619, 0x22001000, 0xfe090429, + 0xe3760241, 0xfa47f34f, 0x05340932, 0xfd460a36, 0x1a221316, 0x28003902, + 0x29241a45, 0xd37ff165, 0xfc4cfa47, 0xf34f0534, 0x0645f35a, 0x0034082b, + 0xfe45fb52, 0xf660023b, 0x024bfd57, 0xfd640138, 0xfd4afa55, 0x003bfd51, + 0xf956fb5f, 0xff42ff4d, 0x0146fe56, 0xfb48003d, 0x0029003f, 0x003f003f, + 0xf7530456, 0x0061f948, 0x0d29033e, 0x0d0f0733, 0x0250d97f, 0xee5bef60, + 0xe651dd62, 0xe866e961, 0xe577e863, 0xeb6eee66, 0xdc7f0050, 0xfb59f95e, + 0xfc5c0027, 0x0041f154, 0xdd7ffe49, 0xf468f75b, 0xe17f0337, 0x07380737, + 0x083dfd35, 0x0044f94a, 0xf758f367, 0xf35bf759, 0xf25cf84c, 0xf457e96e, + 0xe869f64e, 0xec70ef63, 0xb27fba7f, 0xce7fd27f, 0xfc42fb4e, 0xfc47f848, + 0x023bff37, 0xf946fa4b, 0xf859de77, 0xfd4b2014, 0x1e16d47f, 0x0036fb3d, + 0x003aff3c, 0xfd3df843, 0xe754f24a, 0xfb410534, 0x0239003d, 0xf745f546, + 0x1237fc47, 0x003a073d, 0x09291219, 0x0920052b, 0x092f002c, 0x0033022e, + 0x1326fc42, 0x0f260c2a, 0x09220059, 0x042d0a1c, 0x0a1f21f5, 0x34d5120f, + 0x1c0023ea, 0x26e72200, 0x27ee20f4, 0x66a20000, 0x38f121fc, 0x1d0a25fb, + 0x33e327f7, 0x34de45c6, 0x43c12cfb, 0x200737e3, 0x20010000, 0x1b2421e7, + 0x22e224e4, 0x26e426e5, 0x22ee23f0, 0x22f220f8, 0x25fa2300, 0x1e0a1c12, + 0x1a191d29, 0x004b0248, 0x084d0e23, 0x121f1123, 0x151e112d, 0x142a122d, + 0x1b1a1036, 0x07421038, 0x0b490a43, 0xf674e970, 0xf147f93d, 0x0035fb42, + 0xf54df750, 0xf754f657, 0xde7feb65, 0xfd27fb35, 0xf93df54b, 0xf14def5b, + 0xe76be76f, 0xe47af54c, 0xf62cf634, 0xf639f73a, 0xf048f945, 0xfc45fb4a, + 0xf7560242, 0xf7220120, 0x0b1f0534, 0xfe37fe43, 0x0049f859, 0x03340704, + 0x0a081108, 0x10130325, 0xff3dfb49, 0xff46fc4e, 0x0000eb7e, 0xe97cec6e, + 0xe67ee77c, 0xef69e579, 0xe575ef66, 0xe675e574, 0xdf7af65f, 0xf264f85f, + 0xef6fe472, 0xfa59fe50, 0xfc52f755, 0xf851ff48, 0x05400143, 0x09380045, + 0x01450745, 0xf945fa43, 0xf04dfe40, 0x023dfa43, 0xfd400239, 0xfd41fd42, + 0x003e0933, 0xff42fe47, 0xfe4bff46, 0xf7480e3c, 0x1025002f, 0x12230b25, + 0x0c290a29, 0x02300c29, 0x0d29003b, 0x03321328, 0x03421232, 0x13fa12fa, + 0x0e001af4, 0x1ff021e7, 0x21ea25e4, 0x27e22ae2, 0x2fd62ddc, 0x31de29ef, + 0x200945b9, 0x3fc142c0, 0x4db636d9, 0x34dd29f6, 0x240028ff, 0x1e0e1c1a, + 0x17250c37, 0x0b4125df, 0x27dc28db, 0x26e22edf, 0x2ae228e8, 0x31e326f4, + 0x28f626fd, 0x2efb1f14, 0x1d1e192c, 0x0c300b31, 0x1a2d1616, 0x17161b15, + 0x21141a1c, 0x1e181b22, 0x122a1927, 0x12320c46, 0x15360e47, 0x0b531920, + 0x15311536, 0xfb55fa51, 0xf64df951, 0xef50ee49, 0xfc4af653, 0xf747f743, + 0xff3df842, 0xf242003b, 0x023b11f6, 0x20f32af7, 0x31fb3500, 0x4003440a, + 0x421b2f39, 0xfb470018, 0xff24fe2a, 0xfe34f739, 0xfa3ffc41, 0xfc43f952, + 0xfd51fd4c, 0xf948fa4e, 0xf448f244, 0xfd46fa4c, 0xfb42fb3e, 0x0039fc3d, + 0xf73c0136, 0x023a11f6, 0x20f32af7, 0x31fb3500, 0x4003440a, 0x421b2f39, + 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07331d10, + 0x19000e00, 0xf633fd3e, 0xe5631a10, 0xfc55e866, 0x05390639, 0xef490e39, + 0x1428140a, 0x1d003600, 0x252a0c61, 0xe07fea75, 0xfe4afc55, 0xe8660539, + 0xfa5df258, 0xfa2c0437, 0xf559f167, 0xeb741339, 0x143a0454, 0x0660013f, + 0xfb55f36a, 0x053f064b, 0xfd5aff65, 0x0337fc4f, 0xfe4bf461, 0xf932013c, + 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, 0x0d29033e, 0x0722f758, + 0xec7fdc7f, 0xef5bf25f, 0xe754e756, 0xf459ef5b, 0xe17ff24c, 0xee67f35a, + 0xdb7f0b50, 0x054c0254, 0x054efa37, 0x043df253, 0xdb7ffb4f, 0xf568f55b, + 0xe27f0041, 0xfe4f0048, 0xfc5cfa38, 0x0344f847, 0xf362fc56, 0xf458fb52, + 0xfd48fc43, 0xf848f059, 0xf745ff3b, 0x05420439, 0xfc47fe47, 0x023aff4a, + 0xfc2cff45, 0x003ef933, 0xfc2ffa2a, 0xfd29fa35, 0x084cf74e, 0xf5530934, + 0x0043fb5a, 0x0143f148, 0xfb4bf850, 0xeb53eb40, 0xf31fe740, 0xe35e094b, + 0x113ff84a, 0xfb23fe1b, 0x0d5b0341, 0xf945084d, 0xf642033e, 0xfd44ec51, + 0x001e0107, 0xfd17eb4a, 0x1042e97c, 0x11252cee, 0x32deea7f, 0x0427002a, + 0x07220b1d, 0x081f0625, 0x072a0328, 0x08210d2b, 0x0d24042f, 0x0337023a, + 0x063c082c, 0x0b2c0e2a, 0x07300438, 0x04340d25, 0x0931133a, 0x0a300c2d, + 0x00451421, 0x083f23ee, 0x21e71cfd, 0x180a1b00, 0x22f234d4, 0x27e81311, + 0x1f19241d, 0x1821220f, 0x1e141649, 0x1422131f, 0x1b2c1310, 0x0f240f24, + 0x151c1915, 0x1e141f0c, 0x1b10182a, 0x005d0e38, 0x0f391a26, 0xe87fe873, + 0xea52f73e, 0x0035003b, 0xf255f359, 0xf35ef55c, 0xe37feb64, 0xf239f443, + 0xf547f64d, 0xeb55f058, 0xe968f162, 0xdb7ff652, 0xf830f83d, 0xf842f946, + 0xf24bf64f, 0xf753f45c, 0xee6cfc4f, 0xea45f04b, 0xfe3a013a, 0xf34ef753, + 0xfc51f363, 0xf351fa26, 0xf33efa3a, 0xfe3bf049, 0xf64cf356, 0xf753f657, + 0x0000ea7f, 0xe77fe778, 0xe57fed72, 0xe975e776, 0xe675e871, 0xe476e178, + 0xdb7cf65e, 0xf166f663, 0xf36ace7f, 0xfb5c1139, 0xfb56f35e, 0xf45bfe4d, + 0x0047ff49, 0x0440f951, 0x05400f39, 0x01430044, 0xf6430144, 0x004d0240, + 0x0044fb4e, 0x0737053b, 0x02410e36, 0x0f2c053c, 0x0246fe4c, 0xee560c46, + 0x0540f446, 0x0b370538, 0x00450241, 0xfa4a0536, 0x0736fa4c, 0xf552fe4d, + 0xfe4d192a, 0x11f310f7, 0x11f41beb, 0x25e229d8, 0x2ad730d1, 0x27e02ed8, + 0x34cd2ed7, 0x34d92bed, 0x200b3dc9, 0x38d23ece, 0x51bd2dec, 0x23fe1c0f, + 0x22012701, 0x1e111426, 0x122d0f36, 0x004f24f0, 0x25f225ef, 0x2001220f, + 0x1d0f1819, 0x22161f10, 0x23121f1c, 0x2129241c, 0x1b2f153e, 0x121f131a, + 0x24181817, 0x1b10181e, 0x1f1d1629, 0x162a103c, 0x0f340e3c, 0x034ef07b, + 0x15351638, 0x193d1521, 0x1332113d, 0xfd4ef84a, 0xf748f648, 0xee4bf447, + 0xf53ffb46, 0xef4bf248, 0xf043f835, 0xf23bf734, 0xf54409fe, 0x1ef61ffc, + 0x21ff2107, 0x1f0c2517, 0x1f261440, 0xf747f925, 0xf82cf531, 0xf638f43b, + 0xf83ff743, 0xfa44f64f, 0xfd4ef84a, 0xf748f648, 0xee4bf447, 0xf53ffb46, + 0xef4bf248, 0xf043f835, 0xf23bf734, 0xf54409fe, 0x1ef61ffc, 0x21ff2107, + 0x1f0c2517, 0x1f261440 +}; + +/* + * NOTE: The scaling lists are in zig-zag order, apply inverse scanning process + * to get the values in matrix order. In addition, the hardware requires bytes + * swapped within each subsequent 4 bytes. Both arrays below include both + * transformations. + */ +static const u32 zig_zag_4x4[] = { + 3, 2, 7, 11, 6, 1, 0, 5, 10, 15, 14, 9, 4, 8, 13, 12 +}; + +static const u32 zig_zag_8x8[] = { + 3, 2, 11, 19, 10, 1, 0, 9, 18, 27, 35, 26, 17, 8, 7, 6, + 15, 16, 25, 34, 43, 51, 42, 33, 24, 23, 14, 5, 4, 13, 22, 31, + 32, 41, 50, 59, 58, 49, 40, 39, 30, 21, 12, 20, 29, 38, 47, 48, + 57, 56, 55, 46, 37, 28, 36, 45, 54, 63, 62, 53, 44, 52, 61, 60 +}; + +static void +reorder_scaling_list(struct hantro_ctx *ctx) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_scaling_matrix *scaling = ctrls->scaling; + const size_t num_list_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4); + const size_t list_len_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4[0]); + const size_t num_list_8x8 = ARRAY_SIZE(scaling->scaling_list_8x8); + const size_t list_len_8x8 = ARRAY_SIZE(scaling->scaling_list_8x8[0]); + struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; + u8 *dst = tbl->scaling_list; + const u8 *src; + int i, j; + + BUILD_BUG_ON(ARRAY_SIZE(zig_zag_4x4) != list_len_4x4); + BUILD_BUG_ON(ARRAY_SIZE(zig_zag_8x8) != list_len_8x8); + BUILD_BUG_ON(ARRAY_SIZE(tbl->scaling_list) != + num_list_4x4 * list_len_4x4 + + num_list_8x8 * list_len_8x8); + + src = &scaling->scaling_list_4x4[0][0]; + for (i = 0; i < num_list_4x4; ++i) { + for (j = 0; j < list_len_4x4; ++j) + dst[zig_zag_4x4[j]] = src[j]; + src += list_len_4x4; + dst += list_len_4x4; + } + + src = &scaling->scaling_list_8x8[0][0]; + for (i = 0; i < num_list_8x8; ++i) { + for (j = 0; j < list_len_8x8; ++j) + dst[zig_zag_8x8[j]] = src[j]; + src += list_len_8x8; + dst += list_len_8x8; + } +} + +static void prepare_table(struct hantro_ctx *ctx) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; + struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; + const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + int i; + + for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { + tbl->poc[i * 2] = dpb[i].top_field_order_cnt; + tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; + } + + tbl->poc[32] = dec_param->top_field_order_cnt; + tbl->poc[33] = dec_param->bottom_field_order_cnt; + + reorder_scaling_list(ctx); +} + +struct hantro_h264_reflist_builder { + const struct v4l2_h264_dpb_entry *dpb; + s32 pocs[HANTRO_H264_DPB_SIZE]; + u8 unordered_reflist[HANTRO_H264_DPB_SIZE]; + s32 curpoc; + u8 num_valid; +}; + +static s32 get_poc(enum v4l2_field field, s32 top_field_order_cnt, + s32 bottom_field_order_cnt) +{ + switch (field) { + case V4L2_FIELD_TOP: + return top_field_order_cnt; + case V4L2_FIELD_BOTTOM: + return bottom_field_order_cnt; + default: + break; + } + + return min(top_field_order_cnt, bottom_field_order_cnt); +} + +static void +init_reflist_builder(struct hantro_ctx *ctx, + struct hantro_h264_reflist_builder *b) +{ + const struct v4l2_ctrl_h264_decode_params *dec_param; + struct vb2_v4l2_buffer *buf = hantro_get_dst_buf(ctx); + const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + unsigned int i; + + dec_param = ctx->h264_dec.ctrls.decode; + + memset(b, 0, sizeof(*b)); + b->dpb = dpb; + b->curpoc = get_poc(buf->field, dec_param->top_field_order_cnt, + dec_param->bottom_field_order_cnt); + + for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) { + int buf_idx; + + if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + buf_idx = vb2_find_timestamp(cap_q, dpb[i].reference_ts, 0); + if (buf_idx < 0) + continue; + + buf = to_vb2_v4l2_buffer(vb2_get_buffer(cap_q, buf_idx)); + b->pocs[i] = get_poc(buf->field, dpb[i].top_field_order_cnt, + dpb[i].bottom_field_order_cnt); + b->unordered_reflist[b->num_valid] = i; + b->num_valid++; + } + + for (i = b->num_valid; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) + b->unordered_reflist[i] = i; +} + +static int p_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) +{ + const struct hantro_h264_reflist_builder *builder = data; + const struct v4l2_h264_dpb_entry *a, *b; + u8 idxa, idxb; + + idxa = *((u8 *)ptra); + idxb = *((u8 *)ptrb); + a = &builder->dpb[idxa]; + b = &builder->dpb[idxb]; + + if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) != + (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) { + /* Short term pics firt. */ + if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + return -1; + else + return 1; + } + + /* + * Short term pics in descending pic num order, long term ones in + * ascending order. + */ + if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + return b->frame_num - a->frame_num; + + return a->pic_num - b->pic_num; +} + +static int b0_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) +{ + const struct hantro_h264_reflist_builder *builder = data; + const struct v4l2_h264_dpb_entry *a, *b; + s32 poca, pocb; + u8 idxa, idxb; + + idxa = *((u8 *)ptra); + idxb = *((u8 *)ptrb); + a = &builder->dpb[idxa]; + b = &builder->dpb[idxb]; + + if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) != + (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) { + /* Short term pics firt. */ + if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + return -1; + else + return 1; + } + + /* Long term pics in ascending pic num order. */ + if (a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + return a->pic_num - b->pic_num; + + poca = builder->pocs[idxa]; + pocb = builder->pocs[idxb]; + + /* + * Short term pics with POC < cur POC first in POC descending order + * followed by short term pics with POC > cur POC in POC ascending + * order. + */ + if ((poca < builder->curpoc) != (pocb < builder->curpoc)) + return POC_CMP(poca, pocb); + else if (poca < builder->curpoc) + return POC_CMP(pocb, poca); + + return POC_CMP(poca, pocb); +} + +static int b1_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) +{ + const struct hantro_h264_reflist_builder *builder = data; + const struct v4l2_h264_dpb_entry *a, *b; + s32 poca, pocb; + u8 idxa, idxb; + + idxa = *((u8 *)ptra); + idxb = *((u8 *)ptrb); + a = &builder->dpb[idxa]; + b = &builder->dpb[idxb]; + + if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) != + (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) { + /* Short term pics firt. */ + if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + return -1; + else + return 1; + } + + /* Long term pics in ascending pic num order. */ + if (a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + return a->pic_num - b->pic_num; + + poca = builder->pocs[idxa]; + pocb = builder->pocs[idxb]; + + /* + * Short term pics with POC > cur POC first in POC ascending order + * followed by short term pics with POC > cur POC in POC descending + * order. + */ + if ((poca < builder->curpoc) != (pocb < builder->curpoc)) + return POC_CMP(pocb, poca); + else if (poca < builder->curpoc) + return POC_CMP(pocb, poca); + + return POC_CMP(poca, pocb); +} + +static void +build_p_ref_list(const struct hantro_h264_reflist_builder *builder, + u8 *reflist) +{ + memcpy(reflist, builder->unordered_reflist, + sizeof(builder->unordered_reflist)); + sort_r(reflist, builder->num_valid, sizeof(*reflist), + p_ref_list_cmp, NULL, builder); +} + +static void +build_b_ref_lists(const struct hantro_h264_reflist_builder *builder, + u8 *b0_reflist, u8 *b1_reflist) +{ + memcpy(b0_reflist, builder->unordered_reflist, + sizeof(builder->unordered_reflist)); + sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist), + b0_ref_list_cmp, NULL, builder); + + memcpy(b1_reflist, builder->unordered_reflist, + sizeof(builder->unordered_reflist)); + sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist), + b1_ref_list_cmp, NULL, builder); + + if (builder->num_valid > 1 && + !memcmp(b1_reflist, b0_reflist, builder->num_valid)) + swap(b1_reflist[0], b1_reflist[1]); +} + +static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, + const struct v4l2_h264_dpb_entry *b) +{ + return a->top_field_order_cnt == b->top_field_order_cnt && + a->bottom_field_order_cnt == b->bottom_field_order_cnt; +} + +static void update_dpb(struct hantro_ctx *ctx) +{ + const struct v4l2_ctrl_h264_decode_params *dec_param; + DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + unsigned int i, j; + + dec_param = ctx->h264_dec.ctrls.decode; + + /* Disable all entries by default. */ + for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) + ctx->h264_dec.dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; + + /* Try to match new DPB entries with existing ones by their POCs. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + + if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + /* + * To cut off some comparisons, iterate only on target DPB + * entries which are not used yet. + */ + for_each_clear_bit(j, used, ARRAY_SIZE(ctx->h264_dec.dpb)) { + struct v4l2_h264_dpb_entry *cdpb; + + cdpb = &ctx->h264_dec.dpb[j]; + if (cdpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE || + !dpb_entry_match(cdpb, ndpb)) + continue; + + *cdpb = *ndpb; + set_bit(j, used); + break; + } + + if (j == ARRAY_SIZE(ctx->h264_dec.dpb)) + set_bit(i, new); + } + + /* For entries that could not be matched, use remaining free slots. */ + for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + struct v4l2_h264_dpb_entry *cdpb; + + /* + * Both arrays are of the same sizes, so there is no way + * we can end up with no space in target array, unless + * something is buggy. + */ + j = find_first_zero_bit(used, ARRAY_SIZE(ctx->h264_dec.dpb)); + if (WARN_ON(j >= ARRAY_SIZE(ctx->h264_dec.dpb))) + return; + + cdpb = &ctx->h264_dec.dpb[j]; + *cdpb = *ndpb; + set_bit(j, used); + } +} + +struct vb2_buffer *hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + unsigned int dpb_idx) +{ + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + struct vb2_buffer *buf; + int buf_idx = -1; + + if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + buf_idx = vb2_find_timestamp(cap_q, + dpb[dpb_idx].reference_ts, 0); + + if (buf_idx >= 0) { + buf = vb2_get_buffer(cap_q, buf_idx); + } else { + struct vb2_v4l2_buffer *dst_buf; + + /* + * If a DPB entry is unused or invalid, address of current + * destination buffer is returned. + */ + dst_buf = hantro_get_dst_buf(ctx); + buf = &dst_buf->vb2_buf; + } + + return buf; +} + +int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) +{ + struct hantro_h264_dec_hw_ctx *h264_ctx = &ctx->h264_dec; + struct hantro_h264_dec_ctrls *ctrls = &h264_ctx->ctrls; + struct hantro_h264_reflist_builder reflist_builder; + + hantro_prepare_run(ctx); + + ctrls->scaling = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX); + if (WARN_ON(!ctrls->scaling)) + return -EINVAL; + + ctrls->decode = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS); + if (WARN_ON(!ctrls->decode)) + return -EINVAL; + + ctrls->slices = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS); + if (WARN_ON(!ctrls->slices)) + return -EINVAL; + + ctrls->sps = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SPS); + if (WARN_ON(!ctrls->sps)) + return -EINVAL; + + ctrls->pps = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_PPS); + if (WARN_ON(!ctrls->pps)) + return -EINVAL; + + /* Update the DPB with new refs. */ + update_dpb(ctx); + + /* Prepare data in memory. */ + prepare_table(ctx); + + /* Build the P/B{0,1} ref lists. */ + init_reflist_builder(ctx, &reflist_builder); + build_p_ref_list(&reflist_builder, h264_ctx->reflists.p); + build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0, + h264_ctx->reflists.b1); + return 0; +} + +void hantro_h264_dec_exit(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_h264_dec_hw_ctx *h264_dec = &ctx->h264_dec; + struct hantro_aux_buf *priv = &h264_dec->priv; + + dma_free_coherent(vpu->dev, priv->size, priv->cpu, priv->dma); +} + +int hantro_h264_dec_init(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_h264_dec_hw_ctx *h264_dec = &ctx->h264_dec; + struct hantro_aux_buf *priv = &h264_dec->priv; + struct hantro_h264_dec_priv_tbl *tbl; + struct v4l2_pix_format_mplane pix_mp; + + priv->cpu = dma_alloc_coherent(vpu->dev, sizeof(*tbl), &priv->dma, + GFP_KERNEL); + if (!priv->cpu) + return -ENOMEM; + + priv->size = sizeof(*tbl); + tbl = priv->cpu; + memcpy(tbl->cabac_table, h264_cabac_table, sizeof(tbl->cabac_table)); + + v4l2_fill_pixfmt_mp(&pix_mp, ctx->dst_fmt.pixelformat, + ctx->dst_fmt.width, ctx->dst_fmt.height); + h264_dec->pic_size = pix_mp.plane_fmt[0].sizeimage; + + return 0; +} diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 3c361c2e9b88..2fab655bf098 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -11,9 +11,13 @@ #include <linux/interrupt.h> #include <linux/v4l2-controls.h> +#include <media/h264-ctrls.h> #include <media/mpeg2-ctrls.h> +#include <media/vp8-ctrls.h> #include <media/videobuf2-core.h> +#define DEC_8190_ALIGN_MASK 0x07U + struct hantro_dev; struct hantro_ctx; struct hantro_buf; @@ -39,6 +43,54 @@ struct hantro_jpeg_enc_hw_ctx { struct hantro_aux_buf bounce_buffer; }; +/* Max. number of entries in the DPB (HW limitation). */ +#define HANTRO_H264_DPB_SIZE 16 + +/** + * struct hantro_h264_dec_ctrls + * @decode: Decode params + * @scaling: Scaling info + * @slice: Slice params + * @sps: SPS info + * @pps: PPS info + */ +struct hantro_h264_dec_ctrls { + const struct v4l2_ctrl_h264_decode_params *decode; + const struct v4l2_ctrl_h264_scaling_matrix *scaling; + const struct v4l2_ctrl_h264_slice_params *slices; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; +}; + +/** + * struct hantro_h264_dec_reflists + * @p: P reflist + * @b0: B0 reflist + * @b1: B1 reflist + */ +struct hantro_h264_dec_reflists { + u8 p[HANTRO_H264_DPB_SIZE]; + u8 b0[HANTRO_H264_DPB_SIZE]; + u8 b1[HANTRO_H264_DPB_SIZE]; +}; + +/** + * struct hantro_h264_dec_hw_ctx + * @priv: Private auxiliary buffer for hardware. + * @dpb: DPB + * @reflists: P/B0/B1 reflists + * @ctrls: V4L2 controls attached to a run + * @pic_size: Size in bytes of decoded picture, this is needed + * to pass the location of motion vectors. + */ +struct hantro_h264_dec_hw_ctx { + struct hantro_aux_buf priv; + struct v4l2_h264_dpb_entry dpb[HANTRO_H264_DPB_SIZE]; + struct hantro_h264_dec_reflists reflists; + struct hantro_h264_dec_ctrls ctrls; + size_t pic_size; +}; + /** * struct hantro_mpeg2_dec_hw_ctx * @qtable: Quantization table @@ -48,6 +100,16 @@ struct hantro_mpeg2_dec_hw_ctx { }; /** + * struct hantro_vp8d_hw_ctx + * @segment_map: Segment map buffer. + * @prob_tbl: Probability table buffer. + */ +struct hantro_vp8_dec_hw_ctx { + struct hantro_aux_buf segment_map; + struct hantro_aux_buf prob_tbl; +}; + +/** * struct hantro_codec_ops - codec mode specific operations * * @init: If needed, can be used for initialization. @@ -82,16 +144,27 @@ extern const struct hantro_variant rk3399_vpu_variant; extern const struct hantro_variant rk3328_vpu_variant; extern const struct hantro_variant rk3288_vpu_variant; +extern const u32 hantro_vp8_dec_mc_filter[8][6]; + void hantro_watchdog(struct work_struct *work); void hantro_run(struct hantro_ctx *ctx); void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, enum vb2_buffer_state result); +void hantro_prepare_run(struct hantro_ctx *ctx); +void hantro_finish_run(struct hantro_ctx *ctx); void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx); void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx); int hantro_jpeg_enc_init(struct hantro_ctx *ctx); void hantro_jpeg_enc_exit(struct hantro_ctx *ctx); +struct vb2_buffer *hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + unsigned int dpb_idx); +int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx); +void hantro_g1_h264_dec_run(struct hantro_ctx *ctx); +int hantro_h264_dec_init(struct hantro_ctx *ctx); +void hantro_h264_dec_exit(struct hantro_ctx *ctx); + void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx); void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx); void hantro_mpeg2_dec_copy_qtable(u8 *qtable, @@ -99,4 +172,11 @@ void hantro_mpeg2_dec_copy_qtable(u8 *qtable, int hantro_mpeg2_dec_init(struct hantro_ctx *ctx); void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx); +void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx); +void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx); +int hantro_vp8_dec_init(struct hantro_ctx *ctx); +void hantro_vp8_dec_exit(struct hantro_ctx *ctx); +void hantro_vp8_prob_update(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr); + #endif /* HANTRO_HW_H_ */ diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c index 68f45ee66821..3dae52abb96c 100644 --- a/drivers/staging/media/hantro/hantro_v4l2.c +++ b/drivers/staging/media/hantro/hantro_v4l2.c @@ -239,6 +239,15 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f, /* Fill remaining fields */ v4l2_fill_pixfmt_mp(pix_mp, fmt->fourcc, pix_mp->width, pix_mp->height); + /* + * The H264 decoder needs extra space on the output buffers + * to store motion vectors. This is needed for reference + * frames. + */ + if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE) + pix_mp->plane_fmt[0].sizeimage += + 128 * DIV_ROUND_UP(pix_mp->width, 16) * + DIV_ROUND_UP(pix_mp->height, 16); } else if (!pix_mp->plane_fmt[0].sizeimage) { /* * For coded formats the application can specify @@ -344,6 +353,8 @@ hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc) ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = false; break; case V4L2_PIX_FMT_MPEG2_SLICE: + case V4L2_PIX_FMT_VP8_FRAME: + case V4L2_PIX_FMT_H264_SLICE: ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true; break; default: diff --git a/drivers/staging/media/hantro/hantro_vp8.c b/drivers/staging/media/hantro/hantro_vp8.c new file mode 100644 index 000000000000..0e02d147b189 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_vp8.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + */ + +#include "hantro.h" + +/* + * probs table with packed + */ +struct vp8_prob_tbl_packed { + u8 prob_mb_skip_false; + u8 prob_intra; + u8 prob_ref_last; + u8 prob_ref_golden; + u8 prob_segment[3]; + u8 padding0; + + u8 prob_luma_16x16_pred_mode[4]; + u8 prob_chroma_pred_mode[3]; + u8 padding1; + + /* mv prob */ + u8 prob_mv_context[2][19]; + u8 padding2[2]; + + /* coeff probs */ + u8 prob_coeffs[4][8][3][11]; + u8 padding3[96]; +}; + +/* + * filter taps taken to 7-bit precision, + * reference RFC6386#Page-16, filters[8][6] + */ +const u32 hantro_vp8_dec_mc_filter[8][6] = { + { 0, 0, 128, 0, 0, 0 }, + { 0, -6, 123, 12, -1, 0 }, + { 2, -11, 108, 36, -8, 1 }, + { 0, -9, 93, 50, -6, 0 }, + { 3, -16, 77, 77, -16, 3 }, + { 0, -6, 50, 93, -9, 0 }, + { 1, -8, 36, 108, -11, 2 }, + { 0, -1, 12, 123, -6, 0 } +}; + +void hantro_vp8_prob_update(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_entropy_header *entropy = &hdr->entropy_header; + u32 i, j, k; + u8 *dst; + + /* first probs */ + dst = ctx->vp8_dec.prob_tbl.cpu; + + dst[0] = hdr->prob_skip_false; + dst[1] = hdr->prob_intra; + dst[2] = hdr->prob_last; + dst[3] = hdr->prob_gf; + dst[4] = hdr->segment_header.segment_probs[0]; + dst[5] = hdr->segment_header.segment_probs[1]; + dst[6] = hdr->segment_header.segment_probs[2]; + dst[7] = 0; + + dst += 8; + dst[0] = entropy->y_mode_probs[0]; + dst[1] = entropy->y_mode_probs[1]; + dst[2] = entropy->y_mode_probs[2]; + dst[3] = entropy->y_mode_probs[3]; + dst[4] = entropy->uv_mode_probs[0]; + dst[5] = entropy->uv_mode_probs[1]; + dst[6] = entropy->uv_mode_probs[2]; + dst[7] = 0; /*unused */ + + /* mv probs */ + dst += 8; + dst[0] = entropy->mv_probs[0][0]; /* is short */ + dst[1] = entropy->mv_probs[1][0]; + dst[2] = entropy->mv_probs[0][1]; /* sign */ + dst[3] = entropy->mv_probs[1][1]; + dst[4] = entropy->mv_probs[0][8 + 9]; + dst[5] = entropy->mv_probs[0][9 + 9]; + dst[6] = entropy->mv_probs[1][8 + 9]; + dst[7] = entropy->mv_probs[1][9 + 9]; + dst += 8; + for (i = 0; i < 2; ++i) { + for (j = 0; j < 8; j += 4) { + dst[0] = entropy->mv_probs[i][j + 9 + 0]; + dst[1] = entropy->mv_probs[i][j + 9 + 1]; + dst[2] = entropy->mv_probs[i][j + 9 + 2]; + dst[3] = entropy->mv_probs[i][j + 9 + 3]; + dst += 4; + } + } + for (i = 0; i < 2; ++i) { + dst[0] = entropy->mv_probs[i][0 + 2]; + dst[1] = entropy->mv_probs[i][1 + 2]; + dst[2] = entropy->mv_probs[i][2 + 2]; + dst[3] = entropy->mv_probs[i][3 + 2]; + dst[4] = entropy->mv_probs[i][4 + 2]; + dst[5] = entropy->mv_probs[i][5 + 2]; + dst[6] = entropy->mv_probs[i][6 + 2]; + dst[7] = 0; /*unused */ + dst += 8; + } + + /* coeff probs (header part) */ + dst = ctx->vp8_dec.prob_tbl.cpu; + dst += (8 * 7); + for (i = 0; i < 4; ++i) { + for (j = 0; j < 8; ++j) { + for (k = 0; k < 3; ++k) { + dst[0] = entropy->coeff_probs[i][j][k][0]; + dst[1] = entropy->coeff_probs[i][j][k][1]; + dst[2] = entropy->coeff_probs[i][j][k][2]; + dst[3] = entropy->coeff_probs[i][j][k][3]; + dst += 4; + } + } + } + + /* coeff probs (footer part) */ + dst = ctx->vp8_dec.prob_tbl.cpu; + dst += (8 * 55); + for (i = 0; i < 4; ++i) { + for (j = 0; j < 8; ++j) { + for (k = 0; k < 3; ++k) { + dst[0] = entropy->coeff_probs[i][j][k][4]; + dst[1] = entropy->coeff_probs[i][j][k][5]; + dst[2] = entropy->coeff_probs[i][j][k][6]; + dst[3] = entropy->coeff_probs[i][j][k][7]; + dst[4] = entropy->coeff_probs[i][j][k][8]; + dst[5] = entropy->coeff_probs[i][j][k][9]; + dst[6] = entropy->coeff_probs[i][j][k][10]; + dst[7] = 0; /*unused */ + dst += 8; + } + } + } +} + +int hantro_vp8_dec_init(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_aux_buf *aux_buf; + unsigned int mb_width, mb_height; + size_t segment_map_size; + int ret; + + /* segment map table size calculation */ + mb_width = DIV_ROUND_UP(ctx->dst_fmt.width, 16); + mb_height = DIV_ROUND_UP(ctx->dst_fmt.height, 16); + segment_map_size = round_up(DIV_ROUND_UP(mb_width * mb_height, 4), 64); + + /* + * In context init the dma buffer for segment map must be allocated. + * And the data in segment map buffer must be set to all zero. + */ + aux_buf = &ctx->vp8_dec.segment_map; + aux_buf->size = segment_map_size; + aux_buf->cpu = dma_alloc_coherent(vpu->dev, aux_buf->size, + &aux_buf->dma, GFP_KERNEL); + if (!aux_buf->cpu) + return -ENOMEM; + + /* + * Allocate probability table buffer, + * total 1208 bytes, 4K page is far enough. + */ + aux_buf = &ctx->vp8_dec.prob_tbl; + aux_buf->size = sizeof(struct vp8_prob_tbl_packed); + aux_buf->cpu = dma_alloc_coherent(vpu->dev, aux_buf->size, + &aux_buf->dma, GFP_KERNEL); + if (!aux_buf->cpu) { + ret = -ENOMEM; + goto err_free_seg_map; + } + + return 0; + +err_free_seg_map: + dma_free_coherent(vpu->dev, ctx->vp8_dec.segment_map.size, + ctx->vp8_dec.segment_map.cpu, + ctx->vp8_dec.segment_map.dma); + + return ret; +} + +void hantro_vp8_dec_exit(struct hantro_ctx *ctx) +{ + struct hantro_vp8_dec_hw_ctx *vp8_dec = &ctx->vp8_dec; + struct hantro_dev *vpu = ctx->dev; + + dma_free_coherent(vpu->dev, vp8_dec->segment_map.size, + vp8_dec->segment_map.cpu, vp8_dec->segment_map.dma); + dma_free_coherent(vpu->dev, vp8_dec->prob_tbl.size, + vp8_dec->prob_tbl.cpu, vp8_dec->prob_tbl.dma); +} diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c index bcacc4f51093..6bfcc47d1e58 100644 --- a/drivers/staging/media/hantro/rk3288_vpu_hw.c +++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c @@ -62,6 +62,19 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { .codec_mode = HANTRO_MODE_NONE, }, { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .codec_mode = HANTRO_MODE_H264_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 3840, + .step_width = H264_MB_DIM, + .min_height = 48, + .max_height = 2160, + .step_height = H264_MB_DIM, + }, + }, + { .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, .codec_mode = HANTRO_MODE_MPEG2_DEC, .max_depth = 2, @@ -74,6 +87,19 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { .step_height = MPEG2_MB_DIM, }, }, + { + .fourcc = V4L2_PIX_FMT_VP8_FRAME, + .codec_mode = HANTRO_MODE_VP8_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 3840, + .step_width = VP8_MB_DIM, + .min_height = 48, + .max_height = 2160, + .step_height = VP8_MB_DIM, + }, + }, }; static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id) @@ -149,12 +175,24 @@ static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { .init = hantro_jpeg_enc_init, .exit = hantro_jpeg_enc_exit, }, + [HANTRO_MODE_H264_DEC] = { + .run = hantro_g1_h264_dec_run, + .reset = rk3288_vpu_dec_reset, + .init = hantro_h264_dec_init, + .exit = hantro_h264_dec_exit, + }, [HANTRO_MODE_MPEG2_DEC] = { .run = hantro_g1_mpeg2_dec_run, .reset = rk3288_vpu_dec_reset, .init = hantro_mpeg2_dec_init, .exit = hantro_mpeg2_dec_exit, }, + [HANTRO_MODE_VP8_DEC] = { + .run = hantro_g1_vp8_dec_run, + .reset = rk3288_vpu_dec_reset, + .init = hantro_vp8_dec_init, + .exit = hantro_vp8_dec_exit, + }, }; /* @@ -177,7 +215,8 @@ const struct hantro_variant rk3288_vpu_variant = { .dec_offset = 0x400, .dec_fmts = rk3288_vpu_dec_fmts, .num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts), - .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER, + .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | + HANTRO_VP8_DECODER | HANTRO_H264_DECODER, .codec_ops = rk3288_vpu_codec_ops, .irqs = rk3288_irqs, .num_irqs = ARRAY_SIZE(rk3288_irqs), diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c index 5718f8063542..14d14bc6b12b 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c @@ -73,6 +73,19 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { .step_height = MPEG2_MB_DIM, }, }, + { + .fourcc = V4L2_PIX_FMT_VP8_FRAME, + .codec_mode = HANTRO_MODE_VP8_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 3840, + .step_width = VP8_MB_DIM, + .min_height = 48, + .max_height = 2160, + .step_height = VP8_MB_DIM, + }, + }, }; static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id) @@ -154,6 +167,12 @@ static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = { .init = hantro_mpeg2_dec_init, .exit = hantro_mpeg2_dec_exit, }, + [HANTRO_MODE_VP8_DEC] = { + .run = rk3399_vpu_vp8_dec_run, + .reset = rk3399_vpu_dec_reset, + .init = hantro_vp8_dec_init, + .exit = hantro_vp8_dec_exit, + }, }; /* @@ -176,7 +195,8 @@ const struct hantro_variant rk3399_vpu_variant = { .dec_offset = 0x400, .dec_fmts = rk3399_vpu_dec_fmts, .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), - .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER, + .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | + HANTRO_VP8_DECODER, .codec_ops = rk3399_vpu_codec_ops, .irqs = rk3399_irqs, .num_irqs = ARRAY_SIZE(rk3399_irqs), @@ -184,3 +204,20 @@ const struct hantro_variant rk3399_vpu_variant = { .clk_names = rk3399_clk_names, .num_clocks = ARRAY_SIZE(rk3399_clk_names) }; + +static const struct hantro_irq rk3328_irqs[] = { + { "vdpu", rk3399_vdpu_irq }, +}; + +const struct hantro_variant rk3328_vpu_variant = { + .dec_offset = 0x400, + .dec_fmts = rk3399_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), + .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER, + .codec_ops = rk3399_vpu_codec_ops, + .irqs = rk3328_irqs, + .num_irqs = ARRAY_SIZE(rk3328_irqs), + .init = rk3399_vpu_hw_init, + .clk_names = rk3399_clk_names, + .num_clocks = ARRAY_SIZE(rk3399_clk_names), +}; diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c index ae66354d2d93..06162f569b5e 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c @@ -113,14 +113,12 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; struct hantro_jpeg_ctx jpeg_ctx; - struct media_request *src_req; u32 reg; - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = hantro_get_src_buf(ctx); + dst_buf = hantro_get_dst_buf(ctx); - src_req = src_buf->vb2_buf.req_obj.req; - v4l2_ctrl_request_setup(src_req, &ctx->ctrl_handler); + hantro_prepare_run(ctx); memset(&jpeg_ctx, 0, sizeof(jpeg_ctx)); jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); @@ -157,9 +155,7 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx) | VEPU_REG_ENCODE_FORMAT_JPEG | VEPU_REG_ENCODE_ENABLE; - v4l2_ctrl_request_complete(src_req, &ctx->ctrl_handler); - /* Kick the watchdog and start encoding */ - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + hantro_finish_run(ctx); vepu_write(vpu, reg, VEPU_REG_ENCODE_START); } diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c index 8685bddfbcab..e7ba5c0441cc 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -169,12 +169,10 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) const struct v4l2_mpeg2_picture *picture; u32 reg; - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = hantro_get_src_buf(ctx); + dst_buf = hantro_get_dst_buf(ctx); - /* Apply request controls if any */ - v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, - &ctx->ctrl_handler); + hantro_prepare_run(ctx); slice_params = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); @@ -254,12 +252,8 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) &dst_buf->vb2_buf, sequence, picture, slice_params); - /* Controls no longer in-use, we can complete them */ - v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req, - &ctx->ctrl_handler); - /* Kick the watchdog and start decoding */ - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + hantro_finish_run(ctx); reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1); vdpu_write(vpu, reg, VDPU_SWREG(57)); diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c new file mode 100644 index 000000000000..f17e32620b08 --- /dev/null +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c @@ -0,0 +1,595 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip VPU codec vp8 decode driver + * + * Copyright (C) 2014 Rockchip Electronics Co., Ltd. + * ZhiChao Yu <zhichao.yu@rock-chips.com> + * + * Copyright (C) 2014 Google LLC. + * Tomasz Figa <tfiga@chromium.org> + * + * Copyright (C) 2015 Rockchip Electronics Co., Ltd. + * Alpha Lin <alpha.lin@rock-chips.com> + */ + +#include <media/v4l2-mem2mem.h> +#include <media/vp8-ctrls.h> + +#include "hantro_hw.h" +#include "hantro.h" +#include "hantro_g1_regs.h" + +#define VDPU_REG_DEC_CTRL0 0x0c8 +#define VDPU_REG_STREAM_LEN 0x0cc +#define VDPU_REG_DEC_FORMAT 0x0d4 +#define VDPU_REG_DEC_CTRL0_DEC_MODE(x) (((x) & 0xf) << 0) +#define VDPU_REG_DATA_ENDIAN 0x0d8 +#define VDPU_REG_CONFIG_DEC_STRENDIAN_E BIT(5) +#define VDPU_REG_CONFIG_DEC_STRSWAP32_E BIT(4) +#define VDPU_REG_CONFIG_DEC_OUTSWAP32_E BIT(3) +#define VDPU_REG_CONFIG_DEC_INSWAP32_E BIT(2) +#define VDPU_REG_CONFIG_DEC_OUT_ENDIAN BIT(1) +#define VDPU_REG_CONFIG_DEC_IN_ENDIAN BIT(0) +#define VDPU_REG_AXI_CTRL 0x0e0 +#define VDPU_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 16) +#define VDPU_REG_EN_FLAGS 0x0e4 +#define VDPU_REG_DEC_CTRL0_PIC_INTER_E BIT(14) +#define VDPU_REG_CONFIG_DEC_TIMEOUT_E BIT(5) +#define VDPU_REG_CONFIG_DEC_CLK_GATE_E BIT(4) +#define VDPU_REG_PRED_FLT 0x0ec +#define VDPU_REG_ADDR_QTABLE 0x0f4 +#define VDPU_REG_ADDR_DST 0x0fc +#define VDPU_REG_ADDR_STR 0x100 +#define VDPU_REG_VP8_PIC_MB_SIZE 0x1e0 +#define VDPU_REG_VP8_DCT_START_BIT 0x1e4 +#define VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT BIT(13) +#define VDPU_REG_DEC_CTRL4_BILIN_MC_E BIT(12) +#define VDPU_REG_VP8_CTRL0 0x1e8 +#define VDPU_REG_VP8_DATA_VAL 0x1f0 +#define VDPU_REG_PRED_FLT7 0x1f4 +#define VDPU_REG_PRED_FLT8 0x1f8 +#define VDPU_REG_PRED_FLT9 0x1fc +#define VDPU_REG_PRED_FLT10 0x200 +#define VDPU_REG_FILTER_LEVEL 0x204 +#define VDPU_REG_VP8_QUANTER0 0x208 +#define VDPU_REG_VP8_ADDR_REF0 0x20c +#define VDPU_REG_FILTER_MB_ADJ 0x210 +#define VDPU_REG_REF_PIC_FILT_TYPE_E BIT(31) +#define VDPU_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28) +#define VDPU_REG_FILTER_REF_ADJ 0x214 +#define VDPU_REG_VP8_ADDR_REF2_5(i) (0x218 + ((i) * 0x4)) +#define VDPU_REG_VP8_GREF_SIGN_BIAS BIT(0) +#define VDPU_REG_VP8_AREF_SIGN_BIAS BIT(0) +#define VDPU_REG_VP8_DCT_BASE(i) \ + (0x230 + ((((i) < 5) ? (i) : ((i) + 1)) * 0x4)) +#define VDPU_REG_VP8_ADDR_CTRL_PART 0x244 +#define VDPU_REG_VP8_SEGMENT_VAL 0x254 +#define VDPU_REG_FWD_PIC1_SEGMENT_BASE(x) ((x) << 0) +#define VDPU_REG_FWD_PIC1_SEGMENT_UPD_E BIT(1) +#define VDPU_REG_FWD_PIC1_SEGMENT_E BIT(0) +#define VDPU_REG_VP8_DCT_START_BIT2 0x258 +#define VDPU_REG_VP8_QUANTER1 0x25c +#define VDPU_REG_VP8_QUANTER2 0x260 +#define VDPU_REG_PRED_FLT1 0x264 +#define VDPU_REG_PRED_FLT2 0x268 +#define VDPU_REG_PRED_FLT3 0x26c +#define VDPU_REG_PRED_FLT4 0x270 +#define VDPU_REG_PRED_FLT5 0x274 +#define VDPU_REG_PRED_FLT6 0x278 + +static const struct hantro_reg vp8_dec_dct_base[8] = { + { VDPU_REG_ADDR_STR, 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(0), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(1), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(2), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(3), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(4), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(5), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(6), 0, 0xffffffff }, +}; + +static const struct hantro_reg vp8_dec_lf_level[4] = { + { VDPU_REG_FILTER_LEVEL, 18, 0x3f }, + { VDPU_REG_FILTER_LEVEL, 12, 0x3f }, + { VDPU_REG_FILTER_LEVEL, 6, 0x3f }, + { VDPU_REG_FILTER_LEVEL, 0, 0x3f }, +}; + +static const struct hantro_reg vp8_dec_mb_adj[4] = { + { VDPU_REG_FILTER_MB_ADJ, 21, 0x7f }, + { VDPU_REG_FILTER_MB_ADJ, 14, 0x7f }, + { VDPU_REG_FILTER_MB_ADJ, 7, 0x7f }, + { VDPU_REG_FILTER_MB_ADJ, 0, 0x7f }, +}; + +static const struct hantro_reg vp8_dec_ref_adj[4] = { + { VDPU_REG_FILTER_REF_ADJ, 21, 0x7f }, + { VDPU_REG_FILTER_REF_ADJ, 14, 0x7f }, + { VDPU_REG_FILTER_REF_ADJ, 7, 0x7f }, + { VDPU_REG_FILTER_REF_ADJ, 0, 0x7f }, +}; + +static const struct hantro_reg vp8_dec_quant[4] = { + { VDPU_REG_VP8_QUANTER0, 11, 0x7ff }, + { VDPU_REG_VP8_QUANTER0, 0, 0x7ff }, + { VDPU_REG_VP8_QUANTER1, 11, 0x7ff }, + { VDPU_REG_VP8_QUANTER1, 0, 0x7ff }, +}; + +static const struct hantro_reg vp8_dec_quant_delta[5] = { + { VDPU_REG_VP8_QUANTER0, 27, 0x1f }, + { VDPU_REG_VP8_QUANTER0, 22, 0x1f }, + { VDPU_REG_VP8_QUANTER1, 27, 0x1f }, + { VDPU_REG_VP8_QUANTER1, 22, 0x1f }, + { VDPU_REG_VP8_QUANTER2, 27, 0x1f }, +}; + +static const struct hantro_reg vp8_dec_dct_start_bits[8] = { + { VDPU_REG_VP8_CTRL0, 26, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT, 26, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT, 20, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT2, 24, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT2, 18, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT2, 12, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT2, 6, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT2, 0, 0x3f }, +}; + +static const struct hantro_reg vp8_dec_pred_bc_tap[8][6] = { + { + { 0, 0, 0}, + { VDPU_REG_PRED_FLT, 22, 0x3ff }, + { VDPU_REG_PRED_FLT, 12, 0x3ff }, + { VDPU_REG_PRED_FLT, 2, 0x3ff }, + { VDPU_REG_PRED_FLT1, 22, 0x3ff }, + { 0, 0, 0}, + }, { + { 0, 0, 0}, + { VDPU_REG_PRED_FLT1, 12, 0x3ff }, + { VDPU_REG_PRED_FLT1, 2, 0x3ff }, + { VDPU_REG_PRED_FLT2, 22, 0x3ff }, + { VDPU_REG_PRED_FLT2, 12, 0x3ff }, + { 0, 0, 0}, + }, { + { VDPU_REG_PRED_FLT10, 10, 0x3 }, + { VDPU_REG_PRED_FLT2, 2, 0x3ff }, + { VDPU_REG_PRED_FLT3, 22, 0x3ff }, + { VDPU_REG_PRED_FLT3, 12, 0x3ff }, + { VDPU_REG_PRED_FLT3, 2, 0x3ff }, + { VDPU_REG_PRED_FLT10, 8, 0x3}, + }, { + { 0, 0, 0}, + { VDPU_REG_PRED_FLT4, 22, 0x3ff }, + { VDPU_REG_PRED_FLT4, 12, 0x3ff }, + { VDPU_REG_PRED_FLT4, 2, 0x3ff }, + { VDPU_REG_PRED_FLT5, 22, 0x3ff }, + { 0, 0, 0}, + }, { + { VDPU_REG_PRED_FLT10, 6, 0x3 }, + { VDPU_REG_PRED_FLT5, 12, 0x3ff }, + { VDPU_REG_PRED_FLT5, 2, 0x3ff }, + { VDPU_REG_PRED_FLT6, 22, 0x3ff }, + { VDPU_REG_PRED_FLT6, 12, 0x3ff }, + { VDPU_REG_PRED_FLT10, 4, 0x3 }, + }, { + { 0, 0, 0}, + { VDPU_REG_PRED_FLT6, 2, 0x3ff }, + { VDPU_REG_PRED_FLT7, 22, 0x3ff }, + { VDPU_REG_PRED_FLT7, 12, 0x3ff }, + { VDPU_REG_PRED_FLT7, 2, 0x3ff }, + { 0, 0, 0}, + }, { + { VDPU_REG_PRED_FLT10, 2, 0x3 }, + { VDPU_REG_PRED_FLT8, 22, 0x3ff }, + { VDPU_REG_PRED_FLT8, 12, 0x3ff }, + { VDPU_REG_PRED_FLT8, 2, 0x3ff }, + { VDPU_REG_PRED_FLT9, 22, 0x3ff }, + { VDPU_REG_PRED_FLT10, 0, 0x3 }, + }, { + { 0, 0, 0}, + { VDPU_REG_PRED_FLT9, 12, 0x3ff }, + { VDPU_REG_PRED_FLT9, 2, 0x3ff }, + { VDPU_REG_PRED_FLT10, 22, 0x3ff }, + { VDPU_REG_PRED_FLT10, 12, 0x3ff }, + { 0, 0, 0}, + }, +}; + +static const struct hantro_reg vp8_dec_mb_start_bit = { + .base = VDPU_REG_VP8_CTRL0, + .shift = 18, + .mask = 0x3f +}; + +static const struct hantro_reg vp8_dec_mb_aligned_data_len = { + .base = VDPU_REG_VP8_DATA_VAL, + .shift = 0, + .mask = 0x3fffff +}; + +static const struct hantro_reg vp8_dec_num_dct_partitions = { + .base = VDPU_REG_VP8_DATA_VAL, + .shift = 24, + .mask = 0xf +}; + +static const struct hantro_reg vp8_dec_stream_len = { + .base = VDPU_REG_STREAM_LEN, + .shift = 0, + .mask = 0xffffff +}; + +static const struct hantro_reg vp8_dec_mb_width = { + .base = VDPU_REG_VP8_PIC_MB_SIZE, + .shift = 23, + .mask = 0x1ff +}; + +static const struct hantro_reg vp8_dec_mb_height = { + .base = VDPU_REG_VP8_PIC_MB_SIZE, + .shift = 11, + .mask = 0xff +}; + +static const struct hantro_reg vp8_dec_mb_width_ext = { + .base = VDPU_REG_VP8_PIC_MB_SIZE, + .shift = 3, + .mask = 0x7 +}; + +static const struct hantro_reg vp8_dec_mb_height_ext = { + .base = VDPU_REG_VP8_PIC_MB_SIZE, + .shift = 0, + .mask = 0x7 +}; + +static const struct hantro_reg vp8_dec_bool_range = { + .base = VDPU_REG_VP8_CTRL0, + .shift = 0, + .mask = 0xff +}; + +static const struct hantro_reg vp8_dec_bool_value = { + .base = VDPU_REG_VP8_CTRL0, + .shift = 8, + .mask = 0xff +}; + +static const struct hantro_reg vp8_dec_filter_disable = { + .base = VDPU_REG_DEC_CTRL0, + .shift = 8, + .mask = 1 +}; + +static const struct hantro_reg vp8_dec_skip_mode = { + .base = VDPU_REG_DEC_CTRL0, + .shift = 9, + .mask = 1 +}; + +static const struct hantro_reg vp8_dec_start_dec = { + .base = VDPU_REG_EN_FLAGS, + .shift = 0, + .mask = 1 +}; + +static void cfg_lf(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + const struct v4l2_vp8_loopfilter_header *lf = &hdr->lf_header; + struct hantro_dev *vpu = ctx->dev; + unsigned int i; + u32 reg; + + if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) { + hantro_reg_write(vpu, &vp8_dec_lf_level[0], lf->level); + } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) { + for (i = 0; i < 4; i++) { + u32 lf_level = clamp(lf->level + seg->lf_update[i], + 0, 63); + + hantro_reg_write(vpu, &vp8_dec_lf_level[i], lf_level); + } + } else { + for (i = 0; i < 4; i++) + hantro_reg_write(vpu, &vp8_dec_lf_level[i], + seg->lf_update[i]); + } + + reg = VDPU_REG_REF_PIC_FILT_SHARPNESS(lf->sharpness_level); + if (lf->flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE) + reg |= VDPU_REG_REF_PIC_FILT_TYPE_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_FILTER_MB_ADJ); + + if (lf->flags & V4L2_VP8_LF_HEADER_ADJ_ENABLE) { + for (i = 0; i < 4; i++) { + hantro_reg_write(vpu, &vp8_dec_mb_adj[i], + lf->mb_mode_delta[i]); + hantro_reg_write(vpu, &vp8_dec_ref_adj[i], + lf->ref_frm_delta[i]); + } + } +} + +static void cfg_qp(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_quantization_header *q = &hdr->quant_header; + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + struct hantro_dev *vpu = ctx->dev; + unsigned int i; + + if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) { + hantro_reg_write(vpu, &vp8_dec_quant[0], q->y_ac_qi); + } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) { + for (i = 0; i < 4; i++) { + u32 quant = clamp(q->y_ac_qi + seg->quant_update[i], + 0, 127); + + hantro_reg_write(vpu, &vp8_dec_quant[i], quant); + } + } else { + for (i = 0; i < 4; i++) + hantro_reg_write(vpu, &vp8_dec_quant[i], + seg->quant_update[i]); + } + + hantro_reg_write(vpu, &vp8_dec_quant_delta[0], q->y_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[1], q->y2_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[2], q->y2_ac_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[3], q->uv_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[4], q->uv_ac_delta); +} + +static void cfg_parts(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_src; + u32 first_part_offset = VP8_FRAME_IS_KEY_FRAME(hdr) ? 10 : 3; + u32 mb_size, mb_offset_bytes, mb_offset_bits, mb_start_bits; + u32 dct_size_part_size, dct_part_offset; + dma_addr_t src_dma; + u32 dct_part_total_len = 0; + u32 count = 0; + unsigned int i; + + vb2_src = hantro_get_src_buf(ctx); + src_dma = vb2_dma_contig_plane_dma_addr(&vb2_src->vb2_buf, 0); + + /* + * Calculate control partition mb data info + * @first_part_header_bits: bits offset of mb data from first + * part start pos + * @mb_offset_bits: bits offset of mb data from src_dma + * base addr + * @mb_offset_byte: bytes offset of mb data from src_dma + * base addr + * @mb_start_bits: bits offset of mb data from mb data + * 64bits alignment addr + */ + mb_offset_bits = first_part_offset * 8 + + hdr->first_part_header_bits + 8; + mb_offset_bytes = mb_offset_bits / 8; + mb_start_bits = mb_offset_bits - + (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) * 8; + mb_size = hdr->first_part_size - + (mb_offset_bytes - first_part_offset) + + (mb_offset_bytes & DEC_8190_ALIGN_MASK); + + /* Macroblock data aligned base addr */ + vdpu_write_relaxed(vpu, (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) + + src_dma, VDPU_REG_VP8_ADDR_CTRL_PART); + hantro_reg_write(vpu, &vp8_dec_mb_start_bit, mb_start_bits); + hantro_reg_write(vpu, &vp8_dec_mb_aligned_data_len, mb_size); + + /* + * Calculate DCT partition info + * @dct_size_part_size: Containing sizes of DCT part, every DCT part + * has 3 bytes to store its size, except the last + * DCT part + * @dct_part_offset: bytes offset of DCT parts from src_dma base addr + * @dct_part_total_len: total size of all DCT parts + */ + dct_size_part_size = (hdr->num_dct_parts - 1) * 3; + dct_part_offset = first_part_offset + hdr->first_part_size; + for (i = 0; i < hdr->num_dct_parts; i++) + dct_part_total_len += hdr->dct_part_sizes[i]; + dct_part_total_len += dct_size_part_size; + dct_part_total_len += (dct_part_offset & DEC_8190_ALIGN_MASK); + + /* Number of DCT partitions */ + hantro_reg_write(vpu, &vp8_dec_num_dct_partitions, + hdr->num_dct_parts - 1); + + /* DCT partition length */ + hantro_reg_write(vpu, &vp8_dec_stream_len, dct_part_total_len); + + /* DCT partitions base address */ + for (i = 0; i < hdr->num_dct_parts; i++) { + u32 byte_offset = dct_part_offset + dct_size_part_size + count; + u32 base_addr = byte_offset + src_dma; + + hantro_reg_write(vpu, &vp8_dec_dct_base[i], + base_addr & (~DEC_8190_ALIGN_MASK)); + + hantro_reg_write(vpu, &vp8_dec_dct_start_bits[i], + (byte_offset & DEC_8190_ALIGN_MASK) * 8); + + count += hdr->dct_part_sizes[i]; + } +} + +/* + * prediction filter taps + * normal 6-tap filters + */ +static void cfg_tap(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct hantro_dev *vpu = ctx->dev; + int i, j; + + if ((hdr->version & 0x03) != 0) + return; /* Tap filter not used. */ + + for (i = 0; i < 8; i++) { + for (j = 0; j < 6; j++) { + if (vp8_dec_pred_bc_tap[i][j].base != 0) + hantro_reg_write(vpu, + &vp8_dec_pred_bc_tap[i][j], + hantro_vp8_dec_mc_filter[i][j]); + } + } +} + +static void cfg_ref(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; + struct vb2_queue *cap_q; + dma_addr_t ref; + + cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + vb2_dst = hantro_get_dst_buf(ctx); + + ref = hantro_get_ref(cap_q, hdr->last_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF0); + + ref = hantro_get_ref(cap_q, hdr->golden_frame_ts); + WARN_ON(!ref && hdr->golden_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN) + ref |= VDPU_REG_VP8_GREF_SIGN_BIAS; + vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF2_5(2)); + + ref = hantro_get_ref(cap_q, hdr->alt_frame_ts); + WARN_ON(!ref && hdr->alt_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT) + ref |= VDPU_REG_VP8_AREF_SIGN_BIAS; + vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF2_5(3)); +} + +static void cfg_buffers(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; + dma_addr_t dst_dma; + u32 reg; + + vb2_dst = hantro_get_dst_buf(ctx); + + /* Set probability table buffer address */ + vdpu_write_relaxed(vpu, ctx->vp8_dec.prob_tbl.dma, + VDPU_REG_ADDR_QTABLE); + + /* Set segment map address */ + reg = VDPU_REG_FWD_PIC1_SEGMENT_BASE(ctx->vp8_dec.segment_map.dma); + if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED) { + reg |= VDPU_REG_FWD_PIC1_SEGMENT_E; + if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP) + reg |= VDPU_REG_FWD_PIC1_SEGMENT_UPD_E; + } + vdpu_write_relaxed(vpu, reg, VDPU_REG_VP8_SEGMENT_VAL); + + /* set output frame buffer address */ + dst_dma = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + vdpu_write_relaxed(vpu, dst_dma, VDPU_REG_ADDR_DST); +} + +void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_header *hdr; + struct hantro_dev *vpu = ctx->dev; + size_t height = ctx->dst_fmt.height; + size_t width = ctx->dst_fmt.width; + u32 mb_width, mb_height; + u32 reg; + + hantro_prepare_run(ctx); + + hdr = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER); + if (WARN_ON(!hdr)) + return; + + /* Reset segment_map buffer in keyframe */ + if (VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu) + memset(ctx->vp8_dec.segment_map.cpu, 0, + ctx->vp8_dec.segment_map.size); + + hantro_vp8_prob_update(ctx, hdr); + + /* + * Extensive testing shows that the hardware does not properly + * clear the internal state from previous a decoding run. This + * causes corruption in decoded frames for multi-instance use cases. + * A soft reset before programming the registers has been found + * to resolve those problems. + */ + ctx->codec_ops->reset(ctx); + + reg = VDPU_REG_CONFIG_DEC_TIMEOUT_E + | VDPU_REG_CONFIG_DEC_CLK_GATE_E; + if (!VP8_FRAME_IS_KEY_FRAME(hdr)) + reg |= VDPU_REG_DEC_CTRL0_PIC_INTER_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_EN_FLAGS); + + reg = VDPU_REG_CONFIG_DEC_STRENDIAN_E + | VDPU_REG_CONFIG_DEC_INSWAP32_E + | VDPU_REG_CONFIG_DEC_STRSWAP32_E + | VDPU_REG_CONFIG_DEC_OUTSWAP32_E + | VDPU_REG_CONFIG_DEC_IN_ENDIAN + | VDPU_REG_CONFIG_DEC_OUT_ENDIAN; + vdpu_write_relaxed(vpu, reg, VDPU_REG_DATA_ENDIAN); + + reg = VDPU_REG_CONFIG_DEC_MAX_BURST(16); + vdpu_write_relaxed(vpu, reg, VDPU_REG_AXI_CTRL); + + reg = VDPU_REG_DEC_CTRL0_DEC_MODE(10); + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_FORMAT); + + if (!(hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF)) + hantro_reg_write(vpu, &vp8_dec_skip_mode, 1); + if (hdr->lf_header.level == 0) + hantro_reg_write(vpu, &vp8_dec_filter_disable, 1); + + /* Frame dimensions */ + mb_width = VP8_MB_WIDTH(width); + mb_height = VP8_MB_HEIGHT(height); + + hantro_reg_write(vpu, &vp8_dec_mb_width, mb_width); + hantro_reg_write(vpu, &vp8_dec_mb_height, mb_height); + hantro_reg_write(vpu, &vp8_dec_mb_width_ext, mb_width >> 9); + hantro_reg_write(vpu, &vp8_dec_mb_height_ext, mb_height >> 8); + + /* Boolean decoder */ + hantro_reg_write(vpu, &vp8_dec_bool_range, hdr->coder_state.range); + hantro_reg_write(vpu, &vp8_dec_bool_value, hdr->coder_state.value); + + reg = vdpu_read(vpu, VDPU_REG_VP8_DCT_START_BIT); + if (hdr->version != 3) + reg |= VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT; + if (hdr->version & 0x3) + reg |= VDPU_REG_DEC_CTRL4_BILIN_MC_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_VP8_DCT_START_BIT); + + cfg_lf(ctx, hdr); + cfg_qp(ctx, hdr); + cfg_parts(ctx, hdr); + cfg_tap(ctx, hdr); + cfg_ref(ctx, hdr); + cfg_buffers(ctx, hdr); + + hantro_finish_run(ctx); + + hantro_reg_write(vpu, &vp8_dec_start_dec, 1); +} diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig index 4c726345dc25..8f1ae50a4abd 100644 --- a/drivers/staging/media/imx/Kconfig +++ b/drivers/staging/media/imx/Kconfig @@ -7,6 +7,7 @@ config VIDEO_IMX_MEDIA depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE + select V4L2_MEM2MEM_DEV help Say yes here to enable support for video4linux media controller driver for the i.MX5/6 SOC. @@ -22,11 +23,11 @@ config VIDEO_IMX_CSI A video4linux camera sensor interface driver for i.MX5/6. config VIDEO_IMX7_CSI - tristate "i.MX7 Camera Sensor Interface driver" + tristate "i.MX6UL/L / i.MX7 Camera Sensor Interface driver" depends on VIDEO_IMX_MEDIA && VIDEO_DEV && I2C default y help Enable support for video4linux camera sensor interface driver for - i.MX7. + i.MX6UL/L or i.MX7. endmenu endif diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile index aa6c4b4ad37e..9bd9e873ba7c 100644 --- a/drivers/staging/media/imx/Makefile +++ b/drivers/staging/media/imx/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 imx6-media-objs := imx-media-dev.o imx-media-internal-sd.o \ - imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o imx-media-vdic.o + imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o imx-media-vdic.o \ + imx-media-csc-scaler.o imx-media-common-objs := imx-media-capture.o imx-media-dev-common.o \ imx-media-of.o imx-media-utils.o diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c new file mode 100644 index 000000000000..2b635ebf62d6 --- /dev/null +++ b/drivers/staging/media/imx/imx-media-csc-scaler.c @@ -0,0 +1,925 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * i.MX IPUv3 IC PP mem2mem CSC/Scaler driver + * + * Copyright (C) 2011 Pengutronix, Sascha Hauer + * Copyright (C) 2018 Pengutronix, Philipp Zabel + */ +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <video/imx-ipu-v3.h> +#include <video/imx-ipu-image-convert.h> + +#include <media/media-device.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/v4l2-mem2mem.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-dma-contig.h> + +#include "imx-media.h" + +#define fh_to_ctx(__fh) container_of(__fh, struct ipu_csc_scaler_ctx, fh) + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, +}; + +struct ipu_csc_scaler_priv { + struct imx_media_video_dev vdev; + + struct v4l2_m2m_dev *m2m_dev; + struct device *dev; + + struct imx_media_dev *md; + + struct mutex mutex; /* mem2mem device mutex */ +}; + +#define vdev_to_priv(v) container_of(v, struct ipu_csc_scaler_priv, vdev) + +/* Per-queue, driver-specific private data */ +struct ipu_csc_scaler_q_data { + struct v4l2_pix_format cur_fmt; + struct v4l2_rect rect; +}; + +struct ipu_csc_scaler_ctx { + struct ipu_csc_scaler_priv *priv; + + struct v4l2_fh fh; + struct ipu_csc_scaler_q_data q_data[2]; + struct ipu_image_convert_ctx *icc; + + struct v4l2_ctrl_handler ctrl_hdlr; + int rotate; + bool hflip; + bool vflip; + enum ipu_rotate_mode rot_mode; + unsigned int sequence; +}; + +static struct ipu_csc_scaler_q_data *get_q_data(struct ipu_csc_scaler_ctx *ctx, + enum v4l2_buf_type type) +{ + if (V4L2_TYPE_IS_OUTPUT(type)) + return &ctx->q_data[V4L2_M2M_SRC]; + else + return &ctx->q_data[V4L2_M2M_DST]; +} + +/* + * mem2mem callbacks + */ + +static void job_abort(void *_ctx) +{ + struct ipu_csc_scaler_ctx *ctx = _ctx; + + if (ctx->icc) + ipu_image_convert_abort(ctx->icc); +} + +static void ipu_ic_pp_complete(struct ipu_image_convert_run *run, void *_ctx) +{ + struct ipu_csc_scaler_ctx *ctx = _ctx; + struct ipu_csc_scaler_priv *priv = ctx->priv; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + + src_buf->sequence = ctx->sequence++; + dst_buf->sequence = src_buf->sequence; + + v4l2_m2m_buf_done(src_buf, run->status ? VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_buf, run->status ? VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_DONE); + + v4l2_m2m_job_finish(priv->m2m_dev, ctx->fh.m2m_ctx); + kfree(run); +} + +static void device_run(void *_ctx) +{ + struct ipu_csc_scaler_ctx *ctx = _ctx; + struct ipu_csc_scaler_priv *priv = ctx->priv; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct ipu_image_convert_run *run; + int ret; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + run = kzalloc(sizeof(*run), GFP_KERNEL); + if (!run) + goto err; + + run->ctx = ctx->icc; + run->in_phys = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + run->out_phys = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + + ret = ipu_image_convert_queue(run); + if (ret < 0) { + v4l2_err(ctx->priv->vdev.vfd->v4l2_dev, + "%s: failed to queue: %d\n", __func__, ret); + goto err; + } + + return; + +err: + v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); + v4l2_m2m_job_finish(priv->m2m_dev, ctx->fh.m2m_ctx); +} + +/* + * Video ioctls + */ +static int ipu_csc_scaler_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, "imx-media-csc-scaler", sizeof(cap->driver)); + strscpy(cap->card, "imx-media-csc-scaler", sizeof(cap->card)); + strscpy(cap->bus_info, "platform:imx-media-csc-scaler", + sizeof(cap->bus_info)); + + return 0; +} + +static int ipu_csc_scaler_enum_fmt(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + u32 fourcc; + int ret; + + ret = imx_media_enum_format(&fourcc, f->index, CS_SEL_ANY); + if (ret) + return ret; + + f->pixelformat = fourcc; + + return 0; +} + +static int ipu_csc_scaler_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); + struct ipu_csc_scaler_q_data *q_data; + + q_data = get_q_data(ctx, f->type); + + f->fmt.pix = q_data->cur_fmt; + + return 0; +} + +static int ipu_csc_scaler_try_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); + struct ipu_csc_scaler_q_data *q_data = get_q_data(ctx, f->type); + struct ipu_image test_in, test_out; + enum v4l2_field field; + + field = f->fmt.pix.field; + if (field == V4L2_FIELD_ANY) + field = V4L2_FIELD_NONE; + else if (field != V4L2_FIELD_NONE) + return -EINVAL; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + struct ipu_csc_scaler_q_data *q_data_in = + get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + + test_out.pix = f->fmt.pix; + test_in.pix = q_data_in->cur_fmt; + } else { + struct ipu_csc_scaler_q_data *q_data_out = + get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + test_in.pix = f->fmt.pix; + test_out.pix = q_data_out->cur_fmt; + } + + ipu_image_convert_adjust(&test_in, &test_out, ctx->rot_mode); + + f->fmt.pix = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? + test_out.pix : test_in.pix; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + f->fmt.pix.colorspace = q_data->cur_fmt.colorspace; + f->fmt.pix.ycbcr_enc = q_data->cur_fmt.ycbcr_enc; + f->fmt.pix.xfer_func = q_data->cur_fmt.xfer_func; + f->fmt.pix.quantization = q_data->cur_fmt.quantization; + } else if (f->fmt.pix.colorspace == V4L2_COLORSPACE_DEFAULT) { + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT; + } + + return 0; +} + +static int ipu_csc_scaler_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ipu_csc_scaler_q_data *q_data; + struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); + struct vb2_queue *vq; + int ret; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) { + v4l2_err(ctx->priv->vdev.vfd->v4l2_dev, "%s: queue busy\n", + __func__); + return -EBUSY; + } + + q_data = get_q_data(ctx, f->type); + + ret = ipu_csc_scaler_try_fmt(file, priv, f); + if (ret < 0) + return ret; + + q_data->cur_fmt.width = f->fmt.pix.width; + q_data->cur_fmt.height = f->fmt.pix.height; + q_data->cur_fmt.pixelformat = f->fmt.pix.pixelformat; + q_data->cur_fmt.field = f->fmt.pix.field; + q_data->cur_fmt.bytesperline = f->fmt.pix.bytesperline; + q_data->cur_fmt.sizeimage = f->fmt.pix.sizeimage; + + /* Reset cropping/composing rectangle */ + q_data->rect.left = 0; + q_data->rect.top = 0; + q_data->rect.width = q_data->cur_fmt.width; + q_data->rect.height = q_data->cur_fmt.height; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + /* Set colorimetry on the output queue */ + q_data->cur_fmt.colorspace = f->fmt.pix.colorspace; + q_data->cur_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc; + q_data->cur_fmt.xfer_func = f->fmt.pix.xfer_func; + q_data->cur_fmt.quantization = f->fmt.pix.quantization; + /* Propagate colorimetry to the capture queue */ + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + q_data->cur_fmt.colorspace = f->fmt.pix.colorspace; + q_data->cur_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc; + q_data->cur_fmt.xfer_func = f->fmt.pix.xfer_func; + q_data->cur_fmt.quantization = f->fmt.pix.quantization; + } + + /* + * TODO: Setting colorimetry on the capture queue is currently not + * supported by the V4L2 API + */ + + return 0; +} + +static int ipu_csc_scaler_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); + struct ipu_csc_scaler_q_data *q_data; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + break; + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + break; + default: + return -EINVAL; + } + + if (s->target == V4L2_SEL_TGT_CROP || + s->target == V4L2_SEL_TGT_COMPOSE) { + s->r = q_data->rect; + } else { + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->cur_fmt.width; + s->r.height = q_data->cur_fmt.height; + } + + return 0; +} + +static int ipu_csc_scaler_s_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); + struct ipu_csc_scaler_q_data *q_data; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + case V4L2_SEL_TGT_COMPOSE: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + default: + return -EINVAL; + } + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + q_data = get_q_data(ctx, s->type); + + /* The input's frame width to the IC must be a multiple of 8 pixels + * When performing resizing the frame width must be multiple of burst + * size - 8 or 16 pixels as defined by CB#_BURST_16 parameter. + */ + if (s->flags & V4L2_SEL_FLAG_GE) + s->r.width = round_up(s->r.width, 8); + if (s->flags & V4L2_SEL_FLAG_LE) + s->r.width = round_down(s->r.width, 8); + s->r.width = clamp_t(unsigned int, s->r.width, 8, + round_down(q_data->cur_fmt.width, 8)); + s->r.height = clamp_t(unsigned int, s->r.height, 1, + q_data->cur_fmt.height); + s->r.left = clamp_t(unsigned int, s->r.left, 0, + q_data->cur_fmt.width - s->r.width); + s->r.top = clamp_t(unsigned int, s->r.top, 0, + q_data->cur_fmt.height - s->r.height); + + /* V4L2_SEL_FLAG_KEEP_CONFIG is only valid for subdevices */ + q_data->rect = s->r; + + return 0; +} + +static const struct v4l2_ioctl_ops ipu_csc_scaler_ioctl_ops = { + .vidioc_querycap = ipu_csc_scaler_querycap, + + .vidioc_enum_fmt_vid_cap = ipu_csc_scaler_enum_fmt, + .vidioc_g_fmt_vid_cap = ipu_csc_scaler_g_fmt, + .vidioc_try_fmt_vid_cap = ipu_csc_scaler_try_fmt, + .vidioc_s_fmt_vid_cap = ipu_csc_scaler_s_fmt, + + .vidioc_enum_fmt_vid_out = ipu_csc_scaler_enum_fmt, + .vidioc_g_fmt_vid_out = ipu_csc_scaler_g_fmt, + .vidioc_try_fmt_vid_out = ipu_csc_scaler_try_fmt, + .vidioc_s_fmt_vid_out = ipu_csc_scaler_s_fmt, + + .vidioc_g_selection = ipu_csc_scaler_g_selection, + .vidioc_s_selection = ipu_csc_scaler_s_selection, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +/* + * Queue operations + */ + +static int ipu_csc_scaler_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(vq); + struct ipu_csc_scaler_q_data *q_data; + unsigned int size, count = *nbuffers; + + q_data = get_q_data(ctx, vq->type); + + size = q_data->cur_fmt.sizeimage; + + *nbuffers = count; + + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + + *nplanes = 1; + sizes[0] = size; + + dev_dbg(ctx->priv->dev, "get %d buffer(s) of size %d each.\n", + count, size); + + return 0; +} + +static int ipu_csc_scaler_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(vq); + struct ipu_csc_scaler_q_data *q_data; + unsigned long size; + + dev_dbg(ctx->priv->dev, "type: %d\n", vq->type); + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { + if (vbuf->field == V4L2_FIELD_ANY) + vbuf->field = V4L2_FIELD_NONE; + if (vbuf->field != V4L2_FIELD_NONE) { + dev_dbg(ctx->priv->dev, "%s: field isn't supported\n", + __func__); + return -EINVAL; + } + } + + q_data = get_q_data(ctx, vq->type); + size = q_data->cur_fmt.sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + dev_dbg(ctx->priv->dev, + "%s: data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void ipu_csc_scaler_buf_queue(struct vb2_buffer *vb) +{ + struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, to_vb2_v4l2_buffer(vb)); +} + +static void ipu_image_from_q_data(struct ipu_image *im, + struct ipu_csc_scaler_q_data *q_data) +{ + struct v4l2_pix_format *fmt = &q_data->cur_fmt; + + im->pix = *fmt; + if (fmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) + im->pix.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); + if (fmt->quantization == V4L2_QUANTIZATION_DEFAULT) + im->pix.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); + im->rect = q_data->rect; +} + +static int ipu_csc_scaler_start_streaming(struct vb2_queue *q, + unsigned int count) +{ + const enum ipu_ic_task ic_task = IC_TASK_POST_PROCESSOR; + struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(q); + struct ipu_csc_scaler_priv *priv = ctx->priv; + struct ipu_soc *ipu = priv->md->ipu[0]; + struct ipu_csc_scaler_q_data *q_data; + struct vb2_queue *other_q; + struct ipu_image in, out; + + other_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? + V4L2_BUF_TYPE_VIDEO_OUTPUT : + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!vb2_is_streaming(other_q)) + return 0; + + if (ctx->icc) { + v4l2_warn(ctx->priv->vdev.vfd->v4l2_dev, "removing old ICC\n"); + ipu_image_convert_unprepare(ctx->icc); + } + + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + ipu_image_from_q_data(&in, q_data); + + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + ipu_image_from_q_data(&out, q_data); + + ctx->icc = ipu_image_convert_prepare(ipu, ic_task, &in, &out, + ctx->rot_mode, + ipu_ic_pp_complete, ctx); + if (IS_ERR(ctx->icc)) { + struct vb2_v4l2_buffer *buf; + int ret = PTR_ERR(ctx->icc); + + ctx->icc = NULL; + v4l2_err(ctx->priv->vdev.vfd->v4l2_dev, "%s: error %d\n", + __func__, ret); + while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); + while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); + return ret; + } + + return 0; +} + +static void ipu_csc_scaler_stop_streaming(struct vb2_queue *q) +{ + struct ipu_csc_scaler_ctx *ctx = vb2_get_drv_priv(q); + struct vb2_v4l2_buffer *buf; + + if (ctx->icc) { + ipu_image_convert_unprepare(ctx->icc); + ctx->icc = NULL; + } + + ctx->sequence = 0; + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } else { + while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + } +} + +static const struct vb2_ops ipu_csc_scaler_qops = { + .queue_setup = ipu_csc_scaler_queue_setup, + .buf_prepare = ipu_csc_scaler_buf_prepare, + .buf_queue = ipu_csc_scaler_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = ipu_csc_scaler_start_streaming, + .stop_streaming = ipu_csc_scaler_stop_streaming, +}; + +static int ipu_csc_scaler_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct ipu_csc_scaler_ctx *ctx = priv; + int ret; + + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->ops = &ipu_csc_scaler_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->priv->mutex; + src_vq->dev = ctx->priv->dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->ops = &ipu_csc_scaler_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->priv->mutex; + dst_vq->dev = ctx->priv->dev; + + return vb2_queue_init(dst_vq); +} + +static int ipu_csc_scaler_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ipu_csc_scaler_ctx *ctx = container_of(ctrl->handler, + struct ipu_csc_scaler_ctx, + ctrl_hdlr); + enum ipu_rotate_mode rot_mode; + int rotate; + bool hflip, vflip; + int ret = 0; + + rotate = ctx->rotate; + hflip = ctx->hflip; + vflip = ctx->vflip; + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + hflip = ctrl->val; + break; + case V4L2_CID_VFLIP: + vflip = ctrl->val; + break; + case V4L2_CID_ROTATE: + rotate = ctrl->val; + break; + default: + return -EINVAL; + } + + ret = ipu_degrees_to_rot_mode(&rot_mode, rotate, hflip, vflip); + if (ret) + return ret; + + if (rot_mode != ctx->rot_mode) { + struct v4l2_pix_format *in_fmt, *out_fmt; + struct ipu_image test_in, test_out; + + in_fmt = &ctx->q_data[V4L2_M2M_SRC].cur_fmt; + out_fmt = &ctx->q_data[V4L2_M2M_DST].cur_fmt; + + test_in.pix = *in_fmt; + test_out.pix = *out_fmt; + + if (ipu_rot_mode_is_irt(rot_mode) != + ipu_rot_mode_is_irt(ctx->rot_mode)) { + /* Switch width & height to keep aspect ratio intact */ + test_out.pix.width = out_fmt->height; + test_out.pix.height = out_fmt->width; + } + + ipu_image_convert_adjust(&test_in, &test_out, ctx->rot_mode); + + /* Check if output format needs to be changed */ + if (test_in.pix.width != in_fmt->width || + test_in.pix.height != in_fmt->height || + test_in.pix.bytesperline != in_fmt->bytesperline || + test_in.pix.sizeimage != in_fmt->sizeimage) { + struct vb2_queue *out_q; + + out_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (vb2_is_busy(out_q)) + return -EBUSY; + } + + /* Check if capture format needs to be changed */ + if (test_out.pix.width != out_fmt->width || + test_out.pix.height != out_fmt->height || + test_out.pix.bytesperline != out_fmt->bytesperline || + test_out.pix.sizeimage != out_fmt->sizeimage) { + struct vb2_queue *cap_q; + + cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (vb2_is_busy(cap_q)) + return -EBUSY; + } + + *in_fmt = test_in.pix; + *out_fmt = test_out.pix; + + ctx->rot_mode = rot_mode; + ctx->rotate = rotate; + ctx->hflip = hflip; + ctx->vflip = vflip; + } + + return 0; +} + +static const struct v4l2_ctrl_ops ipu_csc_scaler_ctrl_ops = { + .s_ctrl = ipu_csc_scaler_s_ctrl, +}; + +static int ipu_csc_scaler_init_controls(struct ipu_csc_scaler_ctx *ctx) +{ + struct v4l2_ctrl_handler *hdlr = &ctx->ctrl_hdlr; + + v4l2_ctrl_handler_init(hdlr, 3); + + v4l2_ctrl_new_std(hdlr, &ipu_csc_scaler_ctrl_ops, V4L2_CID_HFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(hdlr, &ipu_csc_scaler_ctrl_ops, V4L2_CID_VFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(hdlr, &ipu_csc_scaler_ctrl_ops, V4L2_CID_ROTATE, + 0, 270, 90, 0); + + if (hdlr->error) { + v4l2_ctrl_handler_free(hdlr); + return hdlr->error; + } + + v4l2_ctrl_handler_setup(hdlr); + return 0; +} + +#define DEFAULT_WIDTH 720 +#define DEFAULT_HEIGHT 576 +static const struct ipu_csc_scaler_q_data ipu_csc_scaler_q_data_default = { + .cur_fmt = { + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + .pixelformat = V4L2_PIX_FMT_YUV420, + .field = V4L2_FIELD_NONE, + .bytesperline = DEFAULT_WIDTH, + .sizeimage = DEFAULT_WIDTH * DEFAULT_HEIGHT * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + }, + .rect = { + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + }, +}; + +/* + * File operations + */ +static int ipu_csc_scaler_open(struct file *file) +{ + struct ipu_csc_scaler_priv *priv = video_drvdata(file); + struct ipu_csc_scaler_ctx *ctx = NULL; + int ret; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->rot_mode = IPU_ROTATE_NONE; + + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + ctx->priv = priv; + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(priv->m2m_dev, ctx, + &ipu_csc_scaler_queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + goto err_ctx; + } + + ret = ipu_csc_scaler_init_controls(ctx); + if (ret) + goto err_ctrls; + + ctx->fh.ctrl_handler = &ctx->ctrl_hdlr; + + ctx->q_data[V4L2_M2M_SRC] = ipu_csc_scaler_q_data_default; + ctx->q_data[V4L2_M2M_DST] = ipu_csc_scaler_q_data_default; + + dev_dbg(priv->dev, "Created instance %p, m2m_ctx: %p\n", ctx, + ctx->fh.m2m_ctx); + + return 0; + +err_ctrls: + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); +err_ctx: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + return ret; +} + +static int ipu_csc_scaler_release(struct file *file) +{ + struct ipu_csc_scaler_priv *priv = video_drvdata(file); + struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(file->private_data); + + dev_dbg(priv->dev, "Releasing instance %p\n", ctx); + + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + + return 0; +} + +static const struct v4l2_file_operations ipu_csc_scaler_fops = { + .owner = THIS_MODULE, + .open = ipu_csc_scaler_open, + .release = ipu_csc_scaler_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static struct v4l2_m2m_ops m2m_ops = { + .device_run = device_run, + .job_abort = job_abort, +}; + +static void ipu_csc_scaler_video_device_release(struct video_device *vdev) +{ + struct ipu_csc_scaler_priv *priv = video_get_drvdata(vdev); + + v4l2_m2m_release(priv->m2m_dev); + video_device_release(vdev); + kfree(priv); +} + +static const struct video_device ipu_csc_scaler_videodev_template = { + .name = "ipu_ic_pp csc/scaler", + .fops = &ipu_csc_scaler_fops, + .ioctl_ops = &ipu_csc_scaler_ioctl_ops, + .minor = -1, + .release = ipu_csc_scaler_video_device_release, + .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, +}; + +int imx_media_csc_scaler_device_register(struct imx_media_video_dev *vdev) +{ + struct ipu_csc_scaler_priv *priv = vdev_to_priv(vdev); + struct video_device *vfd = vdev->vfd; + int ret; + + vfd->v4l2_dev = &priv->md->v4l2_dev; + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); + if (ret) { + v4l2_err(vfd->v4l2_dev, "Failed to register video device\n"); + return ret; + } + + v4l2_info(vfd->v4l2_dev, "Registered %s as /dev/%s\n", vfd->name, + video_device_node_name(vfd)); + + return 0; +} + +void imx_media_csc_scaler_device_unregister(struct imx_media_video_dev *vdev) +{ + struct ipu_csc_scaler_priv *priv = vdev_to_priv(vdev); + struct video_device *vfd = priv->vdev.vfd; + + mutex_lock(&priv->mutex); + + video_unregister_device(vfd); + + mutex_unlock(&priv->mutex); +} + +struct imx_media_video_dev * +imx_media_csc_scaler_device_init(struct imx_media_dev *md) +{ + struct ipu_csc_scaler_priv *priv; + struct video_device *vfd; + int ret; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return ERR_PTR(-ENOMEM); + + priv->md = md; + priv->dev = md->md.dev; + + mutex_init(&priv->mutex); + + vfd = video_device_alloc(); + if (!vfd) { + ret = -ENOMEM; + goto err_vfd; + } + + *vfd = ipu_csc_scaler_videodev_template; + vfd->lock = &priv->mutex; + priv->vdev.vfd = vfd; + + INIT_LIST_HEAD(&priv->vdev.list); + + video_set_drvdata(vfd, priv); + + priv->m2m_dev = v4l2_m2m_init(&m2m_ops); + if (IS_ERR(priv->m2m_dev)) { + ret = PTR_ERR(priv->m2m_dev); + v4l2_err(&md->v4l2_dev, "Failed to init mem2mem device: %d\n", + ret); + goto err_m2m; + } + + return &priv->vdev; + +err_m2m: + video_set_drvdata(vfd, NULL); +err_vfd: + kfree(priv); + return ERR_PTR(ret); +} + +MODULE_DESCRIPTION("i.MX IPUv3 mem2mem scaler/CSC driver"); +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c index 6ac371f6e971..2c3c2adca683 100644 --- a/drivers/staging/media/imx/imx-media-dev.c +++ b/drivers/staging/media/imx/imx-media-dev.c @@ -38,9 +38,34 @@ static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier, } /* async subdev complete notifier */ +static int imx6_media_probe_complete(struct v4l2_async_notifier *notifier) +{ + struct imx_media_dev *imxmd = notifier2dev(notifier); + int ret; + + /* call the imx5/6/7 common probe completion handler */ + ret = imx_media_probe_complete(notifier); + if (ret) + return ret; + + mutex_lock(&imxmd->mutex); + + imxmd->m2m_vdev = imx_media_csc_scaler_device_init(imxmd); + if (IS_ERR(imxmd->m2m_vdev)) { + ret = PTR_ERR(imxmd->m2m_vdev); + goto unlock; + } + + ret = imx_media_csc_scaler_device_register(imxmd->m2m_vdev); +unlock: + mutex_unlock(&imxmd->mutex); + return ret; +} + +/* async subdev complete notifier */ static const struct v4l2_async_notifier_operations imx_media_notifier_ops = { .bound = imx_media_subdev_bound, - .complete = imx_media_probe_complete, + .complete = imx6_media_probe_complete, }; static int imx_media_probe(struct platform_device *pdev) @@ -85,6 +110,7 @@ static int imx_media_remove(struct platform_device *pdev) v4l2_async_notifier_unregister(&imxmd->notifier); imx_media_unregister_ipu_internal_subdevs(imxmd); v4l2_async_notifier_cleanup(&imxmd->notifier); + imx_media_csc_scaler_device_unregister(imxmd->m2m_vdev); media_device_unregister(&imxmd->md); v4l2_device_unregister(&imxmd->v4l2_dev); media_device_cleanup(&imxmd->md); diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c index cb1e4cdd5079..d4237e1a4241 100644 --- a/drivers/staging/media/imx/imx-media-internal-sd.c +++ b/drivers/staging/media/imx/imx-media-internal-sd.c @@ -210,6 +210,10 @@ int imx_media_register_ipu_internal_subdevs(struct imx_media_dev *imxmd, mutex_lock(&imxmd->mutex); + /* record this IPU */ + if (!imxmd->ipu[ipu_id]) + imxmd->ipu[ipu_id] = ipu; + /* register the synchronous subdevs */ for (i = 0; i < NUM_IPU_SUBDEVS; i++) { intsd = &int_subdev[i]; diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index 9088c4b720a3..4cc6a7462ae2 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -841,7 +841,7 @@ find_pipeline_entity(struct media_entity *start, u32 grp_id, if (sd->grp_id & grp_id) return &sd->entity; } else if (buftype && is_media_entity_v4l2_video_device(start)) { - vfd = media_entity_to_video_device(pad->entity); + vfd = media_entity_to_video_device(start); if (buftype == vfd->queue->type) return &vfd->entity; } diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h index 4d124a86b358..11861191324a 100644 --- a/drivers/staging/media/imx/imx-media.h +++ b/drivers/staging/media/imx/imx-media.h @@ -136,9 +136,15 @@ struct imx_media_dev { /* master video device list */ struct list_head vdev_list; + /* IPUs this media driver control, valid after subdevs bound */ + struct ipu_soc *ipu[2]; + /* for async subdev registration */ struct v4l2_async_notifier notifier; + /* IC scaler/CSC mem2mem video device */ + struct imx_media_video_dev *m2m_vdev; + /* the IPU internal subdev's registered synchronously */ struct v4l2_subdev *sync_sd[2][NUM_IPU_SUBDEVS]; }; @@ -269,6 +275,12 @@ struct imx_media_buffer * imx_media_capture_device_next_buf(struct imx_media_video_dev *vdev); void imx_media_capture_device_error(struct imx_media_video_dev *vdev); +/* imx-media-csc-scaler.c */ +struct imx_media_video_dev * +imx_media_csc_scaler_device_init(struct imx_media_dev *dev); +int imx_media_csc_scaler_device_register(struct imx_media_video_dev *vdev); +void imx_media_csc_scaler_device_unregister(struct imx_media_video_dev *vdev); + /* subdev group ids */ #define IMX_MEDIA_GRP_ID_CSI2 BIT(8) #define IMX_MEDIA_GRP_ID_CSI BIT(9) diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c index f29e28df36ed..bfa4b254c4e4 100644 --- a/drivers/staging/media/imx/imx6-mipi-csi2.c +++ b/drivers/staging/media/imx/imx6-mipi-csi2.c @@ -243,7 +243,7 @@ static int __maybe_unused csi2_dphy_wait_ulp(struct csi2_dev *csi2) } /* Waits for low-power LP-11 state on data and clock lanes. */ -static int csi2_dphy_wait_stopstate(struct csi2_dev *csi2) +static void csi2_dphy_wait_stopstate(struct csi2_dev *csi2) { u32 mask, reg; int ret; @@ -254,11 +254,9 @@ static int csi2_dphy_wait_stopstate(struct csi2_dev *csi2) ret = readl_poll_timeout(csi2->base + CSI2_PHY_STATE, reg, (reg & mask) == mask, 0, 500000); if (ret) { - v4l2_err(&csi2->sd, "LP-11 timeout, phy_state = 0x%08x\n", reg); - return ret; + v4l2_warn(&csi2->sd, "LP-11 wait timeout, likely a sensor driver bug, expect capture failures.\n"); + v4l2_warn(&csi2->sd, "phy_state = 0x%08x\n", reg); } - - return 0; } /* Wait for active clock on the clock lane. */ @@ -316,9 +314,7 @@ static int csi2_start(struct csi2_dev *csi2) csi2_enable(csi2, true); /* Step 5 */ - ret = csi2_dphy_wait_stopstate(csi2); - if (ret) - goto err_assert_reset; + csi2_dphy_wait_stopstate(csi2); /* Step 6 */ ret = v4l2_subdev_call(csi2->src_sd, video, s_stream, 1); diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index 500b4c08d967..4ca79ff4c9b3 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * V4L2 Capture CSI Subdev for Freescale i.MX7 SOC + * V4L2 Capture CSI Subdev for Freescale i.MX6UL/L / i.MX7 SOC * * Copyright (c) 2019 Linaro Ltd * @@ -765,6 +765,7 @@ static int imx7_csi_configure(struct imx7_csi *csi) struct v4l2_pix_format *out_pix = &vdev->fmt.fmt.pix; __u32 in_code = csi->format_mbus[IMX7_CSI_PAD_SINK].code; u32 cr1, cr18; + int width = out_pix->width; if (out_pix->field == V4L2_FIELD_INTERLACED) { imx7_csi_deinterlace_enable(csi, true); @@ -774,15 +775,27 @@ static int imx7_csi_configure(struct imx7_csi *csi) imx7_csi_buf_stride_set(csi, 0); } - imx7_csi_set_imagpara(csi, out_pix->width, out_pix->height); + cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); + + if (!csi->is_csi2) { + if (out_pix->pixelformat == V4L2_PIX_FMT_UYVY || + out_pix->pixelformat == V4L2_PIX_FMT_YUYV) + width *= 2; + + imx7_csi_set_imagpara(csi, width, out_pix->height); + + cr18 |= (BIT_BASEADDR_SWITCH_EN | BIT_BASEADDR_SWITCH_SEL | + BIT_BASEADDR_CHG_ERR_EN); + imx7_csi_reg_write(csi, cr18, CSI_CSICR18); - if (!csi->is_csi2) return 0; + } + + imx7_csi_set_imagpara(csi, width, out_pix->height); cr1 = imx7_csi_reg_read(csi, CSI_CSICR1); cr1 &= ~BIT_GCLK_MODE; - cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); cr18 &= BIT_MIPI_DATA_FORMAT_MASK; cr18 |= BIT_DATA_FROM_MIPI; @@ -817,11 +830,9 @@ static void imx7_csi_enable(struct imx7_csi *csi) { imx7_csi_sw_reset(csi); - if (csi->is_csi2) { - imx7_csi_dmareq_rff_enable(csi); - imx7_csi_hw_enable_irq(csi); - imx7_csi_hw_enable(csi); - } + imx7_csi_dmareq_rff_enable(csi); + imx7_csi_hw_enable_irq(csi); + imx7_csi_hw_enable(csi); } static void imx7_csi_disable(struct imx7_csi *csi) @@ -1302,6 +1313,7 @@ static int imx7_csi_remove(struct platform_device *pdev) static const struct of_device_id imx7_csi_of_match[] = { { .compatible = "fsl,imx7-csi" }, + { .compatible = "fsl,imx6ul-csi" }, { }, }; MODULE_DEVICE_TABLE(of, imx7_csi_of_match); diff --git a/drivers/staging/media/ipu3/ipu3-tables.h b/drivers/staging/media/ipu3/ipu3-tables.h index a1bf3286f380..9f719c48b432 100644 --- a/drivers/staging/media/ipu3/ipu3-tables.h +++ b/drivers/staging/media/ipu3/ipu3-tables.h @@ -4,6 +4,8 @@ #ifndef __IPU3_TABLES_H #define __IPU3_TABLES_H +#include <linux/bitops.h> + #include "ipu3-abi.h" #define IMGU_BDS_GRANULARITY 32 /* Downscaling granularity */ @@ -12,7 +14,7 @@ #define IMGU_SCALER_DOWNSCALE_4TAPS_LEN 128 #define IMGU_SCALER_DOWNSCALE_2TAPS_LEN 64 -#define IMGU_SCALER_FP ((u32)1 << 31) /* 1.0 in fixed point */ +#define IMGU_SCALER_FP BIT(31) /* 1.0 in fixed point */ #define IMGU_XNR3_VMEM_LUT_LEN 16 diff --git a/drivers/staging/media/ipu3/ipu3.c b/drivers/staging/media/ipu3/ipu3.c index a7372395a101..06a61f31ca50 100644 --- a/drivers/staging/media/ipu3/ipu3.c +++ b/drivers/staging/media/ipu3/ipu3.c @@ -778,8 +778,7 @@ out: static int __maybe_unused imgu_resume(struct device *dev) { - struct pci_dev *pci_dev = to_pci_dev(dev); - struct imgu_device *imgu = pci_get_drvdata(pci_dev); + struct imgu_device *imgu = dev_get_drvdata(dev); int r = 0; unsigned int pipe; diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index c307707480f7..54144dc9f509 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -31,61 +31,61 @@ static struct iss_format_info formats[] = { { MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, - V4L2_PIX_FMT_GREY, 8, "Greyscale 8 bpp", }, + V4L2_PIX_FMT_GREY, 8, }, { MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y8_1X8, - V4L2_PIX_FMT_Y10, 10, "Greyscale 10 bpp", }, + V4L2_PIX_FMT_Y10, 10, }, { MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y8_1X8, - V4L2_PIX_FMT_Y12, 12, "Greyscale 12 bpp", }, + V4L2_PIX_FMT_Y12, 12, }, { MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, - V4L2_PIX_FMT_SBGGR8, 8, "BGGR Bayer 8 bpp", }, + V4L2_PIX_FMT_SBGGR8, 8, }, { MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, - V4L2_PIX_FMT_SGBRG8, 8, "GBRG Bayer 8 bpp", }, + V4L2_PIX_FMT_SGBRG8, 8, }, { MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, - V4L2_PIX_FMT_SGRBG8, 8, "GRBG Bayer 8 bpp", }, + V4L2_PIX_FMT_SGRBG8, 8, }, { MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, - V4L2_PIX_FMT_SRGGB8, 8, "RGGB Bayer 8 bpp", }, + V4L2_PIX_FMT_SRGGB8, 8, }, { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_1X10, 0, - V4L2_PIX_FMT_SGRBG10DPCM8, 8, "GRBG Bayer 10 bpp DPCM8", }, + V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR8_1X8, - V4L2_PIX_FMT_SBGGR10, 10, "BGGR Bayer 10 bpp", }, + V4L2_PIX_FMT_SBGGR10, 10, }, { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG8_1X8, - V4L2_PIX_FMT_SGBRG10, 10, "GBRG Bayer 10 bpp", }, + V4L2_PIX_FMT_SGBRG10, 10, }, { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG8_1X8, - V4L2_PIX_FMT_SGRBG10, 10, "GRBG Bayer 10 bpp", }, + V4L2_PIX_FMT_SGRBG10, 10, }, { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB8_1X8, - V4L2_PIX_FMT_SRGGB10, 10, "RGGB Bayer 10 bpp", }, + V4L2_PIX_FMT_SRGGB10, 10, }, { MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR8_1X8, - V4L2_PIX_FMT_SBGGR12, 12, "BGGR Bayer 12 bpp", }, + V4L2_PIX_FMT_SBGGR12, 12, }, { MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG8_1X8, - V4L2_PIX_FMT_SGBRG12, 12, "GBRG Bayer 12 bpp", }, + V4L2_PIX_FMT_SGBRG12, 12, }, { MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG8_1X8, - V4L2_PIX_FMT_SGRBG12, 12, "GRBG Bayer 12 bpp", }, + V4L2_PIX_FMT_SGRBG12, 12, }, { MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB8_1X8, - V4L2_PIX_FMT_SRGGB12, 12, "RGGB Bayer 12 bpp", }, + V4L2_PIX_FMT_SRGGB12, 12, }, { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16, 0, - V4L2_PIX_FMT_UYVY, 16, "YUV 4:2:2 (UYVY)", }, + V4L2_PIX_FMT_UYVY, 16, }, { MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16, 0, - V4L2_PIX_FMT_YUYV, 16, "YUV 4:2:2 (YUYV)", }, + V4L2_PIX_FMT_YUYV, 16, }, { MEDIA_BUS_FMT_YUYV8_1_5X8, MEDIA_BUS_FMT_YUYV8_1_5X8, MEDIA_BUS_FMT_YUYV8_1_5X8, 0, - V4L2_PIX_FMT_NV12, 8, "YUV 4:2:0 (NV12)", }, + V4L2_PIX_FMT_NV12, 8, }, }; const struct iss_format_info * @@ -563,8 +563,6 @@ iss_video_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) if (index == 0) { f->pixelformat = info->pixelformat; - strscpy(f->description, info->description, - sizeof(f->description)); return 0; } diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h index f22489edb562..8b3dd92021e1 100644 --- a/drivers/staging/media/omap4iss/iss_video.h +++ b/drivers/staging/media/omap4iss/iss_video.h @@ -36,7 +36,6 @@ struct v4l2_pix_format; * shifted to be 8 bits per pixel. =0 if format is not shiftable. * @pixelformat: V4L2 pixel format FCC identifier * @bpp: Bits per pixel - * @description: Human-readable format description */ struct iss_format_info { u32 code; @@ -45,7 +44,6 @@ struct iss_format_info { u32 flavor; u32 pixelformat; unsigned int bpp; - const char *description; }; enum iss_pipeline_stream_state { diff --git a/drivers/staging/media/soc_camera/soc_camera.c b/drivers/staging/media/soc_camera/soc_camera.c index a6232dcd59bc..7b9448e3c9ba 100644 --- a/drivers/staging/media/soc_camera/soc_camera.c +++ b/drivers/staging/media/soc_camera/soc_camera.c @@ -869,8 +869,6 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, format = icd->user_formats[f->index].host_fmt; - if (format->name) - strscpy(f->description, format->name, sizeof(f->description)); f->pixelformat = format->fourcc; return 0; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 370937edfc14..2d3ea8b74dfd 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -29,47 +29,72 @@ static const struct cedrus_control cedrus_controls[] = { { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, - .elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, + }, .codec = CEDRUS_CODEC_MPEG2, .required = true, }, { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, - .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, + }, .codec = CEDRUS_CODEC_MPEG2, .required = false, }, { - .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, - .elem_size = sizeof(struct v4l2_ctrl_h264_decode_params), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + }, .codec = CEDRUS_CODEC_H264, .required = true, }, { - .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, - .elem_size = sizeof(struct v4l2_ctrl_h264_slice_params), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, + }, .codec = CEDRUS_CODEC_H264, .required = true, }, { - .id = V4L2_CID_MPEG_VIDEO_H264_SPS, - .elem_size = sizeof(struct v4l2_ctrl_h264_sps), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SPS, + }, .codec = CEDRUS_CODEC_H264, .required = true, }, { - .id = V4L2_CID_MPEG_VIDEO_H264_PPS, - .elem_size = sizeof(struct v4l2_ctrl_h264_pps), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_PPS, + }, .codec = CEDRUS_CODEC_H264, .required = true, }, { - .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, - .elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + }, .codec = CEDRUS_CODEC_H264, .required = true, }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, + .max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, + .def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, + }, + .codec = CEDRUS_CODEC_H264, + .required = false, + }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_START_CODE, + .max = V4L2_MPEG_VIDEO_H264_START_CODE_NONE, + .def = V4L2_MPEG_VIDEO_H264_START_CODE_NONE, + }, + .codec = CEDRUS_CODEC_H264, + .required = false, + }, }; #define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls) @@ -106,12 +131,8 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx) return -ENOMEM; for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) { - struct v4l2_ctrl_config cfg = {}; - - cfg.elem_size = cedrus_controls[i].elem_size; - cfg.id = cedrus_controls[i].id; - - ctrl = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + ctrl = v4l2_ctrl_new_custom(hdl, &cedrus_controls[i].cfg, + NULL); if (hdl->error) { v4l2_err(&dev->v4l2_dev, "Failed to create new custom control\n"); @@ -178,7 +199,7 @@ static int cedrus_request_validate(struct media_request *req) continue; ctrl_test = v4l2_ctrl_request_hdl_ctrl_find(hdl, - cedrus_controls[i].id); + cedrus_controls[i].cfg.id); if (!ctrl_test) { v4l2_info(&ctx->dev->v4l2_dev, "Missing required codec control\n"); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 3f476d0fd981..2f017a651848 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -49,8 +49,7 @@ enum cedrus_h264_pic_type { }; struct cedrus_control { - u32 id; - u32 elem_size; + struct v4l2_ctrl_config cfg; enum cedrus_codec codec; unsigned char required:1; }; @@ -100,8 +99,6 @@ struct cedrus_ctx { struct v4l2_ctrl_handler hdl; struct v4l2_ctrl **ctrls; - struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME]; - union { struct { void *mv_col_buf; @@ -187,7 +184,7 @@ static inline dma_addr_t cedrus_dst_buf_addr(struct cedrus_ctx *ctx, if (index < 0) return 0; - buf = ctx->dst_bufs[index]; + buf = ctx->fh.m2m_ctx->cap_q_ctx.q.bufs[index]; return buf ? cedrus_buf_addr(buf, &ctx->dst_fmt, plane) : 0; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index bdad87eb9d79..56ca4c9ad01c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -46,7 +46,7 @@ void cedrus_device_run(void *priv) V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); break; - case V4L2_PIX_FMT_H264_SLICE_RAW: + case V4L2_PIX_FMT_H264_SLICE: run.h264.decode_params = cedrus_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS); run.h264.pps = cedrus_find_control_data(ctx, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index a30bb283f69f..d6a782703c9b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -118,7 +118,7 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, if (buf_idx < 0) continue; - cedrus_buf = vb2_to_cedrus_buffer(ctx->dst_bufs[buf_idx]); + cedrus_buf = vb2_to_cedrus_buffer(cap_q->bufs[buf_idx]); position = cedrus_buf->codec.h264.position; used_dpbs |= BIT(position); @@ -193,7 +193,7 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, if (buf_idx < 0) continue; - ref_buf = to_vb2_v4l2_buffer(ctx->dst_bufs[buf_idx]); + ref_buf = to_vb2_v4l2_buffer(cap_q->bufs[buf_idx]); cedrus_buf = vb2_v4l2_to_cedrus_buffer(ref_buf); position = cedrus_buf->codec.h264.position; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index c34aec7c6e40..fc8579b90dab 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -79,9 +79,6 @@ void cedrus_dst_format_set(struct cedrus_dev *dev, reg = VE_PRIMARY_OUT_FMT_NV12; cedrus_write(dev, VE_PRIMARY_OUT_FMT, reg); - reg = VE_CHROMA_BUF_LEN_SDRT(chroma_size / 2); - cedrus_write(dev, VE_CHROMA_BUF_LEN, reg); - reg = chroma_size / 2; cedrus_write(dev, VE_PRIMARY_CHROMA_BUF_LEN, reg); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h index 3e9931416e45..ddd29788d685 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h @@ -110,7 +110,7 @@ #define VE_DEC_MPEG_MBADDR (VE_ENGINE_DEC_MPEG + 0x10) #define VE_DEC_MPEG_MBADDR_X(w) (((w) << 8) & GENMASK(15, 8)) -#define VE_DEC_MPEG_MBADDR_Y(h) (((h) << 0) & GENMASK(0, 7)) +#define VE_DEC_MPEG_MBADDR_Y(h) (((h) << 0) & GENMASK(7, 0)) #define VE_DEC_MPEG_CTRL (VE_ENGINE_DEC_MPEG + 0x14) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index e2b530b1a956..eeee3efd247b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -38,7 +38,7 @@ static struct cedrus_format cedrus_formats[] = { .directions = CEDRUS_DECODE_SRC, }, { - .pixelformat = V4L2_PIX_FMT_H264_SLICE_RAW, + .pixelformat = V4L2_PIX_FMT_H264_SLICE, .directions = CEDRUS_DECODE_SRC, }, { @@ -104,7 +104,7 @@ static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) switch (pix_fmt->pixelformat) { case V4L2_PIX_FMT_MPEG2_SLICE: - case V4L2_PIX_FMT_H264_SLICE_RAW: + case V4L2_PIX_FMT_H264_SLICE: /* Zero bytes per line for encoded source. */ bytesperline = 0; @@ -411,26 +411,6 @@ static void cedrus_queue_cleanup(struct vb2_queue *vq, u32 state) } } -static int cedrus_buf_init(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct cedrus_ctx *ctx = vb2_get_drv_priv(vq); - - if (!V4L2_TYPE_IS_OUTPUT(vq->type)) - ctx->dst_bufs[vb->index] = vb; - - return 0; -} - -static void cedrus_buf_cleanup(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct cedrus_ctx *ctx = vb2_get_drv_priv(vq); - - if (!V4L2_TYPE_IS_OUTPUT(vq->type)) - ctx->dst_bufs[vb->index] = NULL; -} - static int cedrus_buf_out_validate(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -469,7 +449,7 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) ctx->current_codec = CEDRUS_CODEC_MPEG2; break; - case V4L2_PIX_FMT_H264_SLICE_RAW: + case V4L2_PIX_FMT_H264_SLICE: ctx->current_codec = CEDRUS_CODEC_H264; break; @@ -517,8 +497,6 @@ static void cedrus_buf_request_complete(struct vb2_buffer *vb) static struct vb2_ops cedrus_qops = { .queue_setup = cedrus_queue_setup, .buf_prepare = cedrus_buf_prepare, - .buf_init = cedrus_buf_init, - .buf_cleanup = cedrus_buf_cleanup, .buf_queue = cedrus_buf_queue, .buf_out_validate = cedrus_buf_out_validate, .buf_request_complete = cedrus_buf_request_complete, diff --git a/drivers/staging/media/tegra-vde/Kconfig b/drivers/staging/media/tegra-vde/Kconfig index 2e7f644ae591..ba49ea50b8c0 100644 --- a/drivers/staging/media/tegra-vde/Kconfig +++ b/drivers/staging/media/tegra-vde/Kconfig @@ -3,7 +3,7 @@ config TEGRA_VDE tristate "NVIDIA Tegra Video Decoder Engine driver" depends on ARCH_TEGRA || COMPILE_TEST select DMA_SHARED_BUFFER - select IOMMU_IOVA if IOMMU_SUPPORT + select IOMMU_IOVA if (IOMMU_SUPPORT || COMPILE_TEST) select SRAM help Say Y here to enable support for the NVIDIA Tegra video decoder diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index ea54cc27e645..d4d1e44b16b2 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -75,34 +75,27 @@ static const struct v4l2_fract /* video formats */ static struct mmal_fmt formats[] = { { - .name = "4:2:0, planar, YUV", .fourcc = V4L2_PIX_FMT_YUV420, - .flags = 0, .mmal = MMAL_ENCODING_I420, .depth = 12, .mmal_component = COMP_CAMERA, .ybbp = 1, .remove_padding = 1, }, { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, - .flags = 0, .mmal = MMAL_ENCODING_YUYV, .depth = 16, .mmal_component = COMP_CAMERA, .ybbp = 2, .remove_padding = 0, }, { - .name = "RGB24 (LE)", .fourcc = V4L2_PIX_FMT_RGB24, - .flags = 0, .mmal = MMAL_ENCODING_RGB24, .depth = 24, .mmal_component = COMP_CAMERA, .ybbp = 3, .remove_padding = 0, }, { - .name = "JPEG", .fourcc = V4L2_PIX_FMT_JPEG, .flags = V4L2_FMT_FLAG_COMPRESSED, .mmal = MMAL_ENCODING_JPEG, @@ -111,7 +104,6 @@ static struct mmal_fmt formats[] = { .ybbp = 0, .remove_padding = 0, }, { - .name = "H264", .fourcc = V4L2_PIX_FMT_H264, .flags = V4L2_FMT_FLAG_COMPRESSED, .mmal = MMAL_ENCODING_H264, @@ -120,7 +112,6 @@ static struct mmal_fmt formats[] = { .ybbp = 0, .remove_padding = 0, }, { - .name = "MJPEG", .fourcc = V4L2_PIX_FMT_MJPEG, .flags = V4L2_FMT_FLAG_COMPRESSED, .mmal = MMAL_ENCODING_MJPEG, @@ -129,72 +120,56 @@ static struct mmal_fmt formats[] = { .ybbp = 0, .remove_padding = 0, }, { - .name = "4:2:2, packed, YVYU", .fourcc = V4L2_PIX_FMT_YVYU, - .flags = 0, .mmal = MMAL_ENCODING_YVYU, .depth = 16, .mmal_component = COMP_CAMERA, .ybbp = 2, .remove_padding = 0, }, { - .name = "4:2:2, packed, VYUY", .fourcc = V4L2_PIX_FMT_VYUY, - .flags = 0, .mmal = MMAL_ENCODING_VYUY, .depth = 16, .mmal_component = COMP_CAMERA, .ybbp = 2, .remove_padding = 0, }, { - .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, - .flags = 0, .mmal = MMAL_ENCODING_UYVY, .depth = 16, .mmal_component = COMP_CAMERA, .ybbp = 2, .remove_padding = 0, }, { - .name = "4:2:0, planar, NV12", .fourcc = V4L2_PIX_FMT_NV12, - .flags = 0, .mmal = MMAL_ENCODING_NV12, .depth = 12, .mmal_component = COMP_CAMERA, .ybbp = 1, .remove_padding = 1, }, { - .name = "RGB24 (BE)", .fourcc = V4L2_PIX_FMT_BGR24, - .flags = 0, .mmal = MMAL_ENCODING_BGR24, .depth = 24, .mmal_component = COMP_CAMERA, .ybbp = 3, .remove_padding = 0, }, { - .name = "4:2:0, planar, YVU", .fourcc = V4L2_PIX_FMT_YVU420, - .flags = 0, .mmal = MMAL_ENCODING_YV12, .depth = 12, .mmal_component = COMP_CAMERA, .ybbp = 1, .remove_padding = 1, }, { - .name = "4:2:0, planar, NV21", .fourcc = V4L2_PIX_FMT_NV21, - .flags = 0, .mmal = MMAL_ENCODING_NV21, .depth = 12, .mmal_component = COMP_CAMERA, .ybbp = 1, .remove_padding = 1, }, { - .name = "RGB32 (BE)", .fourcc = V4L2_PIX_FMT_BGR32, - .flags = 0, .mmal = MMAL_ENCODING_BGRA, .depth = 32, .mmal_component = COMP_CAMERA, @@ -716,9 +691,7 @@ static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, fmt = &formats[f->index]; - strlcpy((char *)f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; - f->flags = fmt->flags; return 0; } @@ -919,9 +892,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, fmt = &formats[f->index]; - strlcpy((char *)f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; - f->flags = fmt->flags; return 0; } diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h index 6f56c517d850..ff5398737b4a 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h +++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h @@ -26,7 +26,6 @@ struct mmal_msg_context; /* mapping between v4l and mmal video modes */ struct mmal_fmt { - char *name; u32 fourcc; /* v4l2 format id */ int flags; /* v4l2 flags field */ u32 mmal; |