diff options
Diffstat (limited to 'drivers/media')
390 files changed, 8438 insertions, 2725 deletions
diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index 48282d272fe6..ca0db8d457b4 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -438,6 +438,6 @@ static void __exit cec_devnode_exit(void) subsys_initcall(cec_devnode_init); module_exit(cec_devnode_exit) -MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>"); MODULE_DESCRIPTION("Device node registration for cec drivers"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/cec/platform/Kconfig b/drivers/media/cec/platform/Kconfig index ede81fe331b0..e40413609f53 100644 --- a/drivers/media/cec/platform/Kconfig +++ b/drivers/media/cec/platform/Kconfig @@ -99,7 +99,7 @@ config CEC_TEGRA config CEC_SECO tristate "SECO Boards HDMI CEC driver" - depends on X86 || COMPILE_TEST + depends on X86 || (COMPILE_TEST && HAS_IOPORT) depends on PCI && DMI select CEC_CORE select CEC_NOTIFIER diff --git a/drivers/media/cec/platform/cec-gpio/cec-gpio.c b/drivers/media/cec/platform/cec-gpio/cec-gpio.c index 98dacb0919b6..cf64e8871fe5 100644 --- a/drivers/media/cec/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/cec/platform/cec-gpio/cec-gpio.c @@ -279,7 +279,7 @@ MODULE_DEVICE_TABLE(of, cec_gpio_match); static struct platform_driver cec_gpio_pdrv = { .probe = cec_gpio_probe, - .remove_new = cec_gpio_remove, + .remove = cec_gpio_remove, .driver = { .name = "cec-gpio", .of_match_table = cec_gpio_match, @@ -288,6 +288,6 @@ static struct platform_driver cec_gpio_pdrv = { module_platform_driver(cec_gpio_pdrv); -MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("CEC GPIO driver"); diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 8fbbb4091455..12b73ea0f31d 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -582,7 +582,7 @@ MODULE_DEVICE_TABLE(platform, cros_ec_cec_id); static struct platform_driver cros_ec_cec_driver = { .probe = cros_ec_cec_probe, - .remove_new = cros_ec_cec_remove, + .remove = cros_ec_cec_remove, .driver = { .name = DRV_NAME, .pm = &cros_ec_cec_pm_ops, diff --git a/drivers/media/cec/platform/meson/ao-cec-g12a.c b/drivers/media/cec/platform/meson/ao-cec-g12a.c index 51294b9b6cd5..41f5b8669cb0 100644 --- a/drivers/media/cec/platform/meson/ao-cec-g12a.c +++ b/drivers/media/cec/platform/meson/ao-cec-g12a.c @@ -778,7 +778,7 @@ MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); static struct platform_driver meson_ao_cec_g12a_driver = { .probe = meson_ao_cec_g12a_probe, - .remove_new = meson_ao_cec_g12a_remove, + .remove = meson_ao_cec_g12a_remove, .driver = { .name = "meson-ao-cec-g12a", .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match), diff --git a/drivers/media/cec/platform/meson/ao-cec.c b/drivers/media/cec/platform/meson/ao-cec.c index 494738daf09a..145efd9af6ac 100644 --- a/drivers/media/cec/platform/meson/ao-cec.c +++ b/drivers/media/cec/platform/meson/ao-cec.c @@ -714,7 +714,7 @@ MODULE_DEVICE_TABLE(of, meson_ao_cec_of_match); static struct platform_driver meson_ao_cec_driver = { .probe = meson_ao_cec_probe, - .remove_new = meson_ao_cec_remove, + .remove = meson_ao_cec_remove, .driver = { .name = "meson-ao-cec", .of_match_table = meson_ao_cec_of_match, diff --git a/drivers/media/cec/platform/s5p/s5p_cec.c b/drivers/media/cec/platform/s5p/s5p_cec.c index 51ab4a80aafe..4a92d3230f66 100644 --- a/drivers/media/cec/platform/s5p/s5p_cec.c +++ b/drivers/media/cec/platform/s5p/s5p_cec.c @@ -294,7 +294,7 @@ MODULE_DEVICE_TABLE(of, s5p_cec_match); static struct platform_driver s5p_cec_pdrv = { .probe = s5p_cec_probe, - .remove_new = s5p_cec_remove, + .remove = s5p_cec_remove, .driver = { .name = CEC_NAME, .of_match_table = s5p_cec_match, diff --git a/drivers/media/cec/platform/seco/seco-cec.c b/drivers/media/cec/platform/seco/seco-cec.c index 5d4c5a2cae09..b7bb49f02395 100644 --- a/drivers/media/cec/platform/seco/seco-cec.c +++ b/drivers/media/cec/platform/seco/seco-cec.c @@ -778,7 +778,7 @@ static struct platform_driver secocec_driver = { .pm = SECOCEC_PM_OPS, }, .probe = secocec_probe, - .remove_new = secocec_remove, + .remove = secocec_remove, }; module_platform_driver(secocec_driver); diff --git a/drivers/media/cec/platform/sti/stih-cec.c b/drivers/media/cec/platform/sti/stih-cec.c index 99978a7c8d9b..49843d576c7c 100644 --- a/drivers/media/cec/platform/sti/stih-cec.c +++ b/drivers/media/cec/platform/sti/stih-cec.c @@ -383,7 +383,7 @@ MODULE_DEVICE_TABLE(of, stih_cec_match); static struct platform_driver stih_cec_pdrv = { .probe = stih_cec_probe, - .remove_new = stih_cec_remove, + .remove = stih_cec_remove, .driver = { .name = CEC_NAME, .of_match_table = stih_cec_match, diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c index bda9d254041a..fea2d65acffc 100644 --- a/drivers/media/cec/platform/stm32/stm32-cec.c +++ b/drivers/media/cec/platform/stm32/stm32-cec.c @@ -361,7 +361,7 @@ MODULE_DEVICE_TABLE(of, stm32_cec_of_match); static struct platform_driver stm32_cec_driver = { .probe = stm32_cec_probe, - .remove_new = stm32_cec_remove, + .remove = stm32_cec_remove, .driver = { .name = CEC_NAME, .of_match_table = stm32_cec_of_match, diff --git a/drivers/media/cec/platform/tegra/tegra_cec.c b/drivers/media/cec/platform/tegra/tegra_cec.c index 7c1022cee1e8..3ed50097262f 100644 --- a/drivers/media/cec/platform/tegra/tegra_cec.c +++ b/drivers/media/cec/platform/tegra/tegra_cec.c @@ -465,7 +465,7 @@ static struct platform_driver tegra_cec_driver = { .of_match_table = tegra_cec_of_match, }, .probe = tegra_cec_probe, - .remove_new = tegra_cec_remove, + .remove = tegra_cec_remove, #ifdef CONFIG_PM .suspend = tegra_cec_suspend, diff --git a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c index 8526f613a40e..cfbfc4c1b2e6 100644 --- a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c +++ b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c @@ -348,12 +348,12 @@ static int get_edid_tag_location(const u8 *edid, unsigned int size, /* Return if not a CTA-861 extension block */ if (size < 256 || edid[0] != 0x02 || edid[1] != 0x03) - return -1; + return -ENOENT; /* search tag */ d = edid[0x02] & 0x7f; if (d <= 4) - return -1; + return -ENOENT; i = 0x04; end = 0x00 + d; @@ -371,7 +371,7 @@ static int get_edid_tag_location(const u8 *edid, unsigned int size, return offset + i; i += len + 1; } while (i < end); - return -1; + return -ENOENT; } static void extron_edid_crc(u8 *edid) diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c index ba67587bd43e..171366fe3544 100644 --- a/drivers/media/cec/usb/pulse8/pulse8-cec.c +++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c @@ -685,7 +685,7 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio, err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 4); if (err) return err; - date = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + date = ((unsigned)data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; dev_info(pulse8->dev, "Firmware build date %ptT\n", &date); dev_dbg(pulse8->dev, "Persistent config:\n"); diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index bb7d81f7eba6..a1854b3dd004 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -407,8 +407,6 @@ const struct vb2_ops vbi_qops = { .buf_cleanup = buf_cleanup, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 040489e15ea0..94e1cd4eaedb 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -681,8 +681,6 @@ const struct vb2_ops video_qops = { .buf_cleanup = buf_cleanup, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /********************************************************************************/ diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index 73990e469df9..d14ba271db50 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -398,8 +398,6 @@ void smsdvb_debugfs_release(struct smsdvb_client_t *client) void smsdvb_debugfs_register(void) { - struct dentry *d; - /* * FIXME: This was written to debug Siano USB devices. So, it creates * the debugfs node under <debugfs>/usb. @@ -410,12 +408,7 @@ void smsdvb_debugfs_register(void) * node for sdio-based boards, but this may need some logic at sdio * subsystem. */ - d = debugfs_create_dir("smsdvb", usb_debug_root); - if (IS_ERR_OR_NULL(d)) { - pr_err("Couldn't create sysfs node for smsdvb\n"); - return; - } - smsdvb_debugfs_usb_root = d; + smsdvb_debugfs_usb_root = debugfs_create_dir("smsdvb", usb_debug_root); } void smsdvb_debugfs_unregister(void) diff --git a/drivers/media/common/uvc.c b/drivers/media/common/uvc.c index c54c2268fee6..1ad4604474ac 100644 --- a/drivers/media/common/uvc.c +++ b/drivers/media/common/uvc.c @@ -97,6 +97,10 @@ static const struct uvc_format_desc uvc_fmts[] = { .fcc = V4L2_PIX_FMT_RGB565, }, { + .guid = UVC_GUID_FORMAT_D3DFMT_R5G6B5, + .fcc = V4L2_PIX_FMT_RGB565, + }, + { .guid = UVC_GUID_FORMAT_BGR3, .fcc = V4L2_PIX_FMT_BGR24, }, @@ -121,6 +125,10 @@ static const struct uvc_format_desc uvc_fmts[] = { .fcc = V4L2_PIX_FMT_Y12I, }, { + .guid = UVC_GUID_FORMAT_Y16I, + .fcc = V4L2_PIX_FMT_Y16I, + }, + { .guid = UVC_GUID_FORMAT_Z16, .fcc = V4L2_PIX_FMT_Z16, }, diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 642c48e8c1f5..ded11cd8dbf7 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -1795,6 +1795,9 @@ static void tpg_precalculate_line(struct tpg_data *tpg) unsigned p; unsigned x; + if (WARN_ON_ONCE(!tpg->src_width || !tpg->scaled_width)) + return; + switch (tpg->pattern) { case TPG_PAT_GREEN: contrast = TPG_COLOR_100_RED; diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 29a8d876e6c2..c0cc441b5164 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -1482,18 +1482,23 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) } vb->planes[plane].dbuf_mapped = 1; } + } else { + for (plane = 0; plane < vb->num_planes; ++plane) + dma_buf_put(planes[plane].dbuf); + } - /* - * Now that everything is in order, copy relevant information - * provided by userspace. - */ - for (plane = 0; plane < vb->num_planes; ++plane) { - vb->planes[plane].bytesused = planes[plane].bytesused; - vb->planes[plane].length = planes[plane].length; - vb->planes[plane].m.fd = planes[plane].m.fd; - vb->planes[plane].data_offset = planes[plane].data_offset; - } + /* + * Now that everything is in order, copy relevant information + * provided by userspace. + */ + for (plane = 0; plane < vb->num_planes; ++plane) { + vb->planes[plane].bytesused = planes[plane].bytesused; + vb->planes[plane].length = planes[plane].length; + vb->planes[plane].m.fd = planes[plane].m.fd; + vb->planes[plane].data_offset = planes[plane].data_offset; + } + if (reacquired) { /* * Call driver-specific initialization on the newly acquired buffer, * if provided. @@ -1503,9 +1508,6 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) dprintk(q, 1, "buffer initialization failed\n"); goto err_put_vb2_buf; } - } else { - for (plane = 0; plane < vb->num_planes; ++plane) - dma_buf_put(planes[plane].dbuf); } ret = call_vb_qop(vb, buf_prepare, vb); @@ -2035,7 +2037,10 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) * become ready or for streamoff. Driver's lock is released to * allow streamoff or qbuf to be called while waiting. */ - call_void_qop(q, wait_prepare, q); + if (q->ops->wait_prepare) + call_void_qop(q, wait_prepare, q); + else if (q->lock) + mutex_unlock(q->lock); /* * All locks have been released, it is safe to sleep now. @@ -2045,12 +2050,16 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) !list_empty(&q->done_list) || !q->streaming || q->error); + if (q->ops->wait_finish) + call_void_qop(q, wait_finish, q); + else if (q->lock) + mutex_lock(q->lock); + + q->waiting_in_dqbuf = 0; /* * We need to reevaluate both conditions again after reacquiring * the locks or return an error if one occurred. */ - call_void_qop(q, wait_finish, q); - q->waiting_in_dqbuf = 0; if (ret) { dprintk(q, 1, "sleep was interrupted\n"); return ret; @@ -2322,7 +2331,7 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type) } if (q_num_bufs < q->min_queued_buffers) { - dprintk(q, 1, "need at least %u queued buffers\n", + dprintk(q, 1, "need at least %u allocated buffers\n", q->min_queued_buffers); return -EINVAL; } @@ -2644,6 +2653,14 @@ int vb2_core_queue_init(struct vb2_queue *q) if (WARN_ON(q->min_reqbufs_allocation > q->max_num_buffers)) return -EINVAL; + /* Either both or none are set */ + if (WARN_ON(!q->ops->wait_prepare ^ !q->ops->wait_finish)) + return -EINVAL; + + /* Warn if q->lock is NULL and no custom wait_prepare is provided */ + if (WARN_ON(!q->lock && !q->ops->wait_prepare)) + return -EINVAL; + INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); @@ -3203,10 +3220,17 @@ static int vb2_thread(void *data) continue; prequeue--; } else { - call_void_qop(q, wait_finish, q); - if (!threadio->stop) + if (!threadio->stop) { + if (q->ops->wait_finish) + call_void_qop(q, wait_finish, q); + else if (q->lock) + mutex_lock(q->lock); ret = vb2_core_dqbuf(q, &index, NULL, 0); - call_void_qop(q, wait_prepare, q); + if (q->ops->wait_prepare) + call_void_qop(q, wait_prepare, q); + else if (q->lock) + mutex_unlock(q->lock); + } dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret); if (!ret) vb = vb2_get_buffer(q, index); @@ -3218,12 +3242,19 @@ static int vb2_thread(void *data) if (vb->state != VB2_BUF_STATE_ERROR) if (threadio->fnc(vb, threadio->priv)) break; - call_void_qop(q, wait_finish, q); if (copy_timestamp) vb->timestamp = ktime_get_ns(); - if (!threadio->stop) + if (!threadio->stop) { + if (q->ops->wait_finish) + call_void_qop(q, wait_finish, q); + else if (q->lock) + mutex_lock(q->lock); ret = vb2_core_qbuf(q, vb, NULL, NULL); - call_void_qop(q, wait_prepare, q); + if (q->ops->wait_prepare) + call_void_qop(q, wait_prepare, q); + else if (q->lock) + mutex_unlock(q->lock); + } if (ret || threadio->stop) break; } diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 293f3d5f1c4e..9201d854dbcc 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -231,7 +231,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b break; } - /* Fill in driver-provided information for OUTPUT types */ + /* Fill in user-provided information for OUTPUT types */ if (V4L2_TYPE_IS_OUTPUT(b->type)) { /* * Will have to go up to b->length when API starts diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 4f78f30b3646..a05aa271a1ba 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -443,8 +443,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra default: fepriv->auto_step++; - fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */ - break; + fepriv->auto_sub_step = 0; + continue; } if (!ready) fepriv->auto_sub_step++; diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c index 192a8230c4aa..29edaaff7a5c 100644 --- a/drivers/media/dvb-core/dvb_vb2.c +++ b/drivers/media/dvb-core/dvb_vb2.c @@ -366,9 +366,15 @@ int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b) int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp) { struct vb2_queue *q = &ctx->vb_q; + struct vb2_buffer *vb2 = vb2_get_buffer(q, exp->index); int ret; - ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, q->bufs[exp->index], + if (!vb2) { + dprintk(1, "[%s] invalid buffer index\n", ctx->name); + return -EINVAL; + } + + ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, vb2, 0, exp->flags); if (ret) { dprintk(1, "[%s] index=%d errno=%d\n", ctx->name, diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index b43695bc51e7..9df7c213716a 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -86,10 +86,15 @@ static DECLARE_RWSEM(minor_rwsem); static int dvb_device_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev; + unsigned int minor = iminor(inode); + + if (minor >= MAX_DVB_MINORS) + return -ENODEV; mutex_lock(&dvbdev_mutex); down_read(&minor_rwsem); - dvbdev = dvb_minors[iminor(inode)]; + + dvbdev = dvb_minors[minor]; if (dvbdev && dvbdev->fops) { int err = 0; @@ -525,7 +530,10 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, for (minor = 0; minor < MAX_DVB_MINORS; minor++) if (!dvb_minors[minor]) break; - if (minor == MAX_DVB_MINORS) { +#else + minor = nums2minor(adap->num, type, id); +#endif + if (minor >= MAX_DVB_MINORS) { if (new_node) { list_del(&new_node->list_head); kfree(dvbdevfops); @@ -538,9 +546,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, mutex_unlock(&dvbdev_register_lock); return -EINVAL; } -#else - minor = nums2minor(adap->num, type, id); -#endif + dvbdev->minor = minor; dvb_minors[minor] = dvb_device_get(dvbdev); up_write(&minor_rwsem); diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c index 27f1de21f571..d935fb10e620 100644 --- a/drivers/media/dvb-frontends/bcm3510.c +++ b/drivers/media/dvb-frontends/bcm3510.c @@ -729,7 +729,7 @@ static int bcm3510_init_cold(struct bcm3510_state *st) int ret; bcm3510_register_value v; - /* read Acquisation Processor status register and check it is not in RUN mode */ + /* read Acquisition Processor status register and check it is not in RUN mode */ if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) return ret; if (v.APSTAT1_a2.RUN) { diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c index 8b978a9f74a4..f5dd3a81725a 100644 --- a/drivers/media/dvb-frontends/cx24116.c +++ b/drivers/media/dvb-frontends/cx24116.c @@ -741,6 +741,7 @@ static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr) { struct cx24116_state *state = fe->demodulator_priv; u8 snr_reading; + int ret; static const u32 snr_tab[] = { /* 10 x Table (rounded up) */ 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667, 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667, @@ -749,7 +750,11 @@ static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr) dprintk("%s()\n", __func__); - snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0); + ret = cx24116_readreg(state, CX24116_REG_QUALITY0); + if (ret < 0) + return ret; + + snr_reading = ret; if (snr_reading >= 0xa0 /* 100% */) *snr = 0xffff; diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index c958bcff026e..6cbbb351d545 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -78,7 +78,7 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); #define SOC_8090_P1G_11R1 0x86 #define SOC_8090_P1G_21R1 0x8e -/* else use thos ones to check */ +/* else use those ones to check */ #define P1A_B 0x0 #define P1C 0x1 #define P1D_E_F 0x3 @@ -1574,7 +1574,7 @@ static int dib0090_reset(struct dvb_frontend *fe) if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc)) dib0090_set_EFUSE(state); - /* Congigure in function of the crystal */ + /* Configure in function of the crystal */ if (state->config->force_crystal_mode != 0) dib0090_write_reg(state, 0x14, state->config->force_crystal_mode & 3); diff --git a/drivers/media/dvb-frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c index c598b2a63325..822639f11c04 100644 --- a/drivers/media/dvb-frontends/dib3000mb.c +++ b/drivers/media/dvb-frontends/dib3000mb.c @@ -640,7 +640,7 @@ static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber) return 0; } -/* see dib3000-watch dvb-apps for exact calcuations of signal_strength and snr */ +/* see dib3000-watch dvb-apps for exact calculations of signal_strength and snr */ static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength) { struct dib3000_state* state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 023db6e793f8..05254d8717db 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -947,8 +947,6 @@ static const struct vb2_ops rtl2832_sdr_vb2_ops = { .buf_queue = rtl2832_sdr_buf_queue, .start_streaming = rtl2832_sdr_start_streaming, .stop_streaming = rtl2832_sdr_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int rtl2832_sdr_g_tuner(struct file *file, void *priv, @@ -1487,7 +1485,7 @@ static struct platform_driver rtl2832_sdr_driver = { .name = "rtl2832_sdr", }, .probe = rtl2832_sdr_probe, - .remove_new = rtl2832_sdr_remove, + .remove = rtl2832_sdr_remove, }; module_platform_driver(rtl2832_sdr_driver); diff --git a/drivers/media/dvb-frontends/stb0899_algo.c b/drivers/media/dvb-frontends/stb0899_algo.c index df89c33dac23..40537c4ccb0d 100644 --- a/drivers/media/dvb-frontends/stb0899_algo.c +++ b/drivers/media/dvb-frontends/stb0899_algo.c @@ -269,7 +269,7 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state) short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3; int index = 0; - u8 cfr[2]; + u8 cfr[2] = {0}; u8 reg; internal->status = NOCARRIER; diff --git a/drivers/media/dvb-frontends/stv6111.c b/drivers/media/dvb-frontends/stv6111.c index 2d0adb6fcb08..0ac15273922d 100644 --- a/drivers/media/dvb-frontends/stv6111.c +++ b/drivers/media/dvb-frontends/stv6111.c @@ -161,7 +161,7 @@ static const struct slookup gain_rfagc_lookup[] = { }; /* - * This table is 6 dB too low comapred to the others (probably created with + * This table is 6 dB too low compared to the others (probably created with * a different BB_MAG setting) */ static const struct slookup gain_channel_agc_nf_lookup[] = { diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c index fd928787207e..c11563853c07 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.c +++ b/drivers/media/dvb-frontends/tda18271c2dd.c @@ -954,7 +954,7 @@ static int RFTrackingFiltersCorrection(struct tda_state *state, Capprox = 255; - /* TODO Temperature compensation. There is defenitely a scale factor */ + /* TODO Temperature compensation. There is definitely a scale factor */ /* missing in the datasheet, so leave it out for now. */ state->m_Regs[EB14] = Capprox; diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c index a5baca2449c7..e25add6cc38e 100644 --- a/drivers/media/dvb-frontends/ts2020.c +++ b/drivers/media/dvb-frontends/ts2020.c @@ -553,13 +553,19 @@ static void ts2020_regmap_unlock(void *__dev) static int ts2020_probe(struct i2c_client *client) { struct ts2020_config *pdata = client->dev.platform_data; - struct dvb_frontend *fe = pdata->fe; + struct dvb_frontend *fe; struct ts2020_priv *dev; int ret; u8 u8tmp; unsigned int utmp; char *chip_str; + if (!pdata) { + dev_err(&client->dev, "platform data is mandatory\n"); + return -EINVAL; + } + + fe = pdata->fe; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { ret = -ENOMEM; diff --git a/drivers/media/dvb-frontends/zd1301_demod.c b/drivers/media/dvb-frontends/zd1301_demod.c index 17f6e373c13d..e8b9e67a8717 100644 --- a/drivers/media/dvb-frontends/zd1301_demod.c +++ b/drivers/media/dvb-frontends/zd1301_demod.c @@ -531,7 +531,7 @@ static struct platform_driver zd1301_demod_driver = { .suppress_bind_attrs = true, }, .probe = zd1301_demod_probe, - .remove_new = zd1301_demod_remove, + .remove = zd1301_demod_remove, }; module_platform_driver(zd1301_demod_driver); diff --git a/drivers/media/dvb-frontends/zl10036.c b/drivers/media/dvb-frontends/zl10036.c index 3df055be66d6..5ad987c6861b 100644 --- a/drivers/media/dvb-frontends/zl10036.c +++ b/drivers/media/dvb-frontends/zl10036.c @@ -89,7 +89,7 @@ static int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count) int ret; if (zl10036_debug & 0x02) { - /* every 8bit-value satisifes this! + /* every 8bit-value satisfies this! * so only check for debug log */ if ((buf[0] & 0x80) == 0x00) reg = 2; diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 819ff9f7c90f..ff7dfa0278a7 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1440,7 +1440,8 @@ static int adv7180_probe(struct i2c_client *client) return ret; } - if (of_property_read_bool(np, "adv,force-bt656-4")) + if (of_property_read_bool(np, "adv,force-bt656-4") || + of_property_read_bool(np, "adi,force-bt656-4")) state->force_bt656_4 = true; if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c index e9406d552699..4036972af3a6 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -116,6 +116,9 @@ struct adv7511_state { unsigned edid_detect_counter; struct workqueue_struct *work_queue; struct delayed_work edid_handler; /* work entry */ + + struct dentry *debugfs_dir; + struct v4l2_debugfs_if *infoframes; }; static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd); @@ -483,27 +486,25 @@ static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size) return 256 - csum; } -static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_infoframe *cri) +static int read_infoframe(struct v4l2_subdev *sd, + const struct adv7511_cfg_read_infoframe *cri, + u8 *buffer) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct device *dev = &client->dev; - union hdmi_infoframe frame; - u8 buffer[32]; u8 len; int i; if (!(adv7511_rd(sd, cri->present_reg) & cri->present_mask)) { v4l2_info(sd, "%s infoframe not transmitted\n", cri->desc); - return; + return 0; } memcpy(buffer, cri->header, sizeof(cri->header)); len = buffer[2]; - if (len + 4 > sizeof(buffer)) { + if (len + 4 > V4L2_DEBUGFS_IF_MAX_LEN) { v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len); - return; + return 0; } if (cri->payload_addr >= 0x100) { @@ -516,21 +517,38 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_ buffer[3] = 0; buffer[3] = hdmi_infoframe_checksum(buffer, len + 4); - if (hdmi_infoframe_unpack(&frame, buffer, len + 4) < 0) { - v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); + return len + 4; +} + +static void log_infoframe(struct v4l2_subdev *sd, + const struct adv7511_cfg_read_infoframe *cri) +{ + union hdmi_infoframe frame; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct device *dev = &client->dev; + u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + int len = read_infoframe(sd, cri, buffer); + + if (len <= 0) + return; + + if (hdmi_infoframe_unpack(&frame, buffer, len) < 0) { + v4l2_err(sd, "%s: unpack of %s infoframe failed\n", + __func__, cri->desc); return; } hdmi_infoframe_log(KERN_INFO, dev, &frame); } +static const struct adv7511_cfg_read_infoframe cri[] = { + { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 }, + { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 }, + { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 }, +}; + static void adv7511_log_infoframes(struct v4l2_subdev *sd) { - static const struct adv7511_cfg_read_infoframe cri[] = { - { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 }, - { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 }, - { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 }, - }; int i; for (i = 0; i < ARRAY_SIZE(cri); i++) @@ -1693,6 +1711,34 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd) return false; } +static ssize_t +adv7511_debugfs_if_read(u32 type, void *priv, + struct file *filp, char __user *ubuf, size_t count, loff_t *ppos) +{ + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + struct v4l2_subdev *sd = priv; + int index; + int len; + + switch (type) { + case V4L2_DEBUGFS_IF_AVI: + index = 0; + break; + case V4L2_DEBUGFS_IF_AUDIO: + index = 1; + break; + case V4L2_DEBUGFS_IF_SPD: + index = 2; + break; + default: + return 0; + } + len = read_infoframe(sd, &cri[index], buf); + if (len > 0) + len = simple_read_from_buffer(ubuf, count, ppos, buf, len); + return len < 0 ? 0 : len; +} + static int adv7511_registered(struct v4l2_subdev *sd) { struct adv7511_state *state = get_adv7511_state(sd); @@ -1700,9 +1746,16 @@ static int adv7511_registered(struct v4l2_subdev *sd) int err; err = cec_register_adapter(state->cec_adap, &client->dev); - if (err) + if (err) { cec_delete_adapter(state->cec_adap); - return err; + return err; + } + + state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root()); + state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir, + V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO | + V4L2_DEBUGFS_IF_SPD, sd, adv7511_debugfs_if_read); + return 0; } static void adv7511_unregistered(struct v4l2_subdev *sd) @@ -1710,6 +1763,10 @@ static void adv7511_unregistered(struct v4l2_subdev *sd) struct adv7511_state *state = get_adv7511_state(sd); cec_unregister_adapter(state->cec_adap); + v4l2_debugfs_if_free(state->infoframes); + state->infoframes = NULL; + debugfs_remove_recursive(state->debugfs_dir); + state->debugfs_dir = NULL; } static const struct v4l2_subdev_internal_ops adv7511_int_ops = { diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 48230d5109f0..e271782b7b70 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -42,7 +42,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); MODULE_DESCRIPTION("Analog Devices ADV7604/10/11/12 video decoder driver"); -MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>"); MODULE_AUTHOR("Mats Randgaard <mats.randgaard@cisco.com>"); MODULE_LICENSE("GPL"); @@ -193,6 +193,9 @@ struct adv76xx_state { struct delayed_work delayed_work_enable_hotplug; bool restart_stdi_once; + struct dentry *debugfs_dir; + struct v4l2_debugfs_if *infoframes; + /* CEC */ struct cec_adapter *cec_adap; u8 cec_addr[ADV76XX_MAX_ADDRS]; @@ -1405,12 +1408,13 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - false, timings)) + false, adv76xx_get_dv_timings_cap(sd, -1), timings)) return 0; if (v4l2_detect_gtf(stdi->lcf + 1, hfreq, stdi->lcvs, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - false, state->aspect_ratio, timings)) + false, state->aspect_ratio, + adv76xx_get_dv_timings_cap(sd, -1), timings)) return 0; v4l2_dbg(2, debug, sd, @@ -2458,10 +2462,9 @@ static const struct adv76xx_cfg_read_infoframe adv76xx_cri[] = { { "Vendor", 0x10, 0xec, 0x54 } }; -static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index, - union hdmi_infoframe *frame) +static int adv76xx_read_infoframe_buf(struct v4l2_subdev *sd, int index, + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN]) { - uint8_t buffer[32]; u8 len; int i; @@ -2472,27 +2475,20 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index, } for (i = 0; i < 3; i++) - buffer[i] = infoframe_read(sd, - adv76xx_cri[index].head_addr + i); + buf[i] = infoframe_read(sd, adv76xx_cri[index].head_addr + i); - len = buffer[2] + 1; + len = buf[2] + 1; - if (len + 3 > sizeof(buffer)) { + if (len + 3 > V4L2_DEBUGFS_IF_MAX_LEN) { v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, adv76xx_cri[index].desc, len); return -ENOENT; } for (i = 0; i < len; i++) - buffer[i + 3] = infoframe_read(sd, - adv76xx_cri[index].payload_addr + i); - - if (hdmi_infoframe_unpack(frame, buffer, len + 3) < 0) { - v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, - adv76xx_cri[index].desc); - return -ENOENT; - } - return 0; + buf[i + 3] = infoframe_read(sd, + adv76xx_cri[index].payload_addr + i); + return len + 3; } static void adv76xx_log_infoframes(struct v4l2_subdev *sd) @@ -2505,10 +2501,19 @@ static void adv76xx_log_infoframes(struct v4l2_subdev *sd) } for (i = 0; i < ARRAY_SIZE(adv76xx_cri); i++) { - union hdmi_infoframe frame; struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + union hdmi_infoframe frame; + int len; + + len = adv76xx_read_infoframe_buf(sd, i, buffer); + if (len < 0) + continue; - if (!adv76xx_read_infoframe(sd, i, &frame)) + if (hdmi_infoframe_unpack(&frame, buffer, len) < 0) + v4l2_err(sd, "%s: unpack of %s infoframe failed\n", + __func__, adv76xx_cri[i].desc); + else hdmi_infoframe_log(KERN_INFO, &client->dev, &frame); } } @@ -2519,10 +2524,10 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) const struct adv76xx_chip_info *info = state->info; struct v4l2_dv_timings timings; struct stdi_readback stdi; - u8 reg_io_0x02 = io_read(sd, 0x02); + int ret; + u8 reg_io_0x02; u8 edid_enabled; u8 cable_det; - static const char * const csc_coeff_sel_rb[16] = { "bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB", "reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709", @@ -2621,13 +2626,21 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "-----Color space-----\n"); v4l2_info(sd, "RGB quantization range ctrl: %s\n", rgb_quantization_range_txt[state->rgb_quantization_range]); - v4l2_info(sd, "Input color space: %s\n", - input_color_space_txt[reg_io_0x02 >> 4]); - v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n", - (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", - (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? - "(16-235)" : "(0-255)", - (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); + + ret = io_read(sd, 0x02); + if (ret < 0) { + v4l2_info(sd, "Can't read Input/Output color space\n"); + } else { + reg_io_0x02 = ret; + + v4l2_info(sd, "Input color space: %s\n", + input_color_space_txt[reg_io_0x02 >> 4]); + v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n", + (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", + (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? + "(16-235)" : "(0-255)", + (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); + } v4l2_info(sd, "Color space conversion: %s\n", csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]); @@ -2686,6 +2699,41 @@ static int adv76xx_subscribe_event(struct v4l2_subdev *sd, } } +static ssize_t +adv76xx_debugfs_if_read(u32 type, void *priv, struct file *filp, + char __user *ubuf, size_t count, loff_t *ppos) +{ + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + struct v4l2_subdev *sd = priv; + int index; + int len; + + if (!is_hdmi(sd)) + return 0; + + switch (type) { + case V4L2_DEBUGFS_IF_AVI: + index = 0; + break; + case V4L2_DEBUGFS_IF_AUDIO: + index = 1; + break; + case V4L2_DEBUGFS_IF_SPD: + index = 2; + break; + case V4L2_DEBUGFS_IF_HDMI: + index = 3; + break; + default: + return 0; + } + + len = adv76xx_read_infoframe_buf(sd, index, buf); + if (len > 0) + len = simple_read_from_buffer(ubuf, count, ppos, buf, len); + return len < 0 ? 0 : len; +} + static int adv76xx_registered(struct v4l2_subdev *sd) { struct adv76xx_state *state = to_state(sd); @@ -2693,9 +2741,16 @@ static int adv76xx_registered(struct v4l2_subdev *sd) int err; err = cec_register_adapter(state->cec_adap, &client->dev); - if (err) + if (err) { cec_delete_adapter(state->cec_adap); - return err; + return err; + } + state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root()); + state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir, + V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO | + V4L2_DEBUGFS_IF_SPD | V4L2_DEBUGFS_IF_HDMI, sd, + adv76xx_debugfs_if_read); + return 0; } static void adv76xx_unregistered(struct v4l2_subdev *sd) @@ -2703,6 +2758,10 @@ static void adv76xx_unregistered(struct v4l2_subdev *sd) struct adv76xx_state *state = to_state(sd); cec_unregister_adapter(state->cec_adap); + v4l2_debugfs_if_free(state->infoframes); + state->infoframes = NULL; + debugfs_remove_recursive(state->debugfs_dir); + state->debugfs_dir = NULL; } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 014fc913225c..5545cd23e113 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -38,7 +38,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); MODULE_DESCRIPTION("Analog Devices ADV7842 video decoder driver"); -MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>"); MODULE_AUTHOR("Martin Bugge <marbugge@cisco.com>"); MODULE_LICENSE("GPL"); @@ -114,6 +114,9 @@ struct adv7842_state { bool restart_stdi_once; bool hdmi_port_a; + struct dentry *debugfs_dir; + struct v4l2_debugfs_if *infoframes; + /* i2c clients */ struct i2c_client *i2c_sdp_io; struct i2c_client *i2c_sdp; @@ -1431,14 +1434,15 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, } if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0, - (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | - (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - false, timings)) + (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | + (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), + false, adv7842_get_dv_timings_cap(sd), timings)) return 0; if (v4l2_detect_gtf(stdi->lcf + 1, hfreq, stdi->lcvs, - (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | - (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - false, state->aspect_ratio, timings)) + (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | + (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), + false, state->aspect_ratio, + adv7842_get_dv_timings_cap(sd), timings)) return 0; v4l2_dbg(2, debug, sd, @@ -2565,58 +2569,65 @@ struct adv7842_cfg_read_infoframe { u8 payload_addr; }; -static void log_infoframe(struct v4l2_subdev *sd, const struct adv7842_cfg_read_infoframe *cri) +static const struct adv7842_cfg_read_infoframe adv7842_cri[] = { + { "AVI", 0x01, 0xe0, 0x00 }, + { "Audio", 0x02, 0xe3, 0x1c }, + { "SDP", 0x04, 0xe6, 0x2a }, + { "Vendor", 0x10, 0xec, 0x54 } +}; + +static int adv7842_read_infoframe_buf(struct v4l2_subdev *sd, int index, + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN]) { - int i; - u8 buffer[32]; - union hdmi_infoframe frame; - u8 len; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct device *dev = &client->dev; + const struct adv7842_cfg_read_infoframe *cri = &adv7842_cri[index]; + int len, i; if (!(io_read(sd, 0x60) & cri->present_mask)) { - v4l2_info(sd, "%s infoframe not received\n", cri->desc); - return; + v4l2_dbg(1, debug, sd, + "%s infoframe not received\n", cri->desc); + return -ENOENT; } for (i = 0; i < 3; i++) - buffer[i] = infoframe_read(sd, cri->head_addr + i); + buf[i] = infoframe_read(sd, cri->head_addr + i); - len = buffer[2] + 1; + len = buf[2] + 1; - if (len + 3 > sizeof(buffer)) { - v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len); - return; + if (len + 3 > V4L2_DEBUGFS_IF_MAX_LEN) { + v4l2_err(sd, "%s: invalid %s infoframe length %d\n", + __func__, cri->desc, len); + return -ENOENT; } for (i = 0; i < len; i++) - buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i); - - if (hdmi_infoframe_unpack(&frame, buffer, len + 3) < 0) { - v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); - return; - } - - hdmi_infoframe_log(KERN_INFO, dev, &frame); + buf[i + 3] = infoframe_read(sd, cri->payload_addr + i); + return len + 3; } static void adv7842_log_infoframes(struct v4l2_subdev *sd) { - int i; - static const struct adv7842_cfg_read_infoframe cri[] = { - { "AVI", 0x01, 0xe0, 0x00 }, - { "Audio", 0x02, 0xe3, 0x1c }, - { "SDP", 0x04, 0xe6, 0x2a }, - { "Vendor", 0x10, 0xec, 0x54 } - }; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct device *dev = &client->dev; + union hdmi_infoframe frame; + u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + int len, i; if (!(hdmi_read(sd, 0x05) & 0x80)) { v4l2_info(sd, "receive DVI-D signal, no infoframes\n"); return; } - for (i = 0; i < ARRAY_SIZE(cri); i++) - log_infoframe(sd, &cri[i]); + for (i = 0; i < ARRAY_SIZE(adv7842_cri); i++) { + len = adv7842_read_infoframe_buf(sd, i, buffer); + if (len < 0) + continue; + + if (hdmi_infoframe_unpack(&frame, buffer, len) < 0) + v4l2_err(sd, "%s: unpack of %s infoframe failed\n", + __func__, adv7842_cri[i].desc); + else + hdmi_infoframe_log(KERN_INFO, dev, &frame); + } } #if 0 @@ -3263,6 +3274,41 @@ static int adv7842_subscribe_event(struct v4l2_subdev *sd, } } +static ssize_t +adv7842_debugfs_if_read(u32 type, void *priv, struct file *filp, + char __user *ubuf, size_t count, loff_t *ppos) +{ + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + struct v4l2_subdev *sd = priv; + int index; + int len; + + if (!is_hdmi(sd)) + return 0; + + switch (type) { + case V4L2_DEBUGFS_IF_AVI: + index = 0; + break; + case V4L2_DEBUGFS_IF_AUDIO: + index = 1; + break; + case V4L2_DEBUGFS_IF_SPD: + index = 2; + break; + case V4L2_DEBUGFS_IF_HDMI: + index = 3; + break; + default: + return 0; + } + + len = adv7842_read_infoframe_buf(sd, index, buf); + if (len > 0) + len = simple_read_from_buffer(ubuf, count, ppos, buf, len); + return len < 0 ? 0 : len; +} + static int adv7842_registered(struct v4l2_subdev *sd) { struct adv7842_state *state = to_state(sd); @@ -3270,8 +3316,15 @@ static int adv7842_registered(struct v4l2_subdev *sd) int err; err = cec_register_adapter(state->cec_adap, &client->dev); - if (err) + if (err) { cec_delete_adapter(state->cec_adap); + } else { + state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root()); + state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir, + V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO | + V4L2_DEBUGFS_IF_SPD | V4L2_DEBUGFS_IF_HDMI, sd, + adv7842_debugfs_if_read); + } return err; } @@ -3280,6 +3333,10 @@ static void adv7842_unregistered(struct v4l2_subdev *sd) struct adv7842_state *state = to_state(sd); cec_unregister_adapter(state->cec_adap); + v4l2_debugfs_if_free(state->infoframes); + state->infoframes = NULL; + debugfs_remove_recursive(state->debugfs_dir); + state->debugfs_dir = NULL; } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c index 5ddfd3dcb188..05b708bd0a64 100644 --- a/drivers/media/i2c/alvium-csi2.c +++ b/drivers/media/i2c/alvium-csi2.c @@ -16,7 +16,6 @@ #include <media/v4l2-async.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> @@ -2240,8 +2239,6 @@ free_ctrls: static const struct v4l2_subdev_core_ops alvium_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops alvium_video_ops = { @@ -2289,7 +2286,7 @@ static int alvium_subdev_init(struct alvium_dev *alvium) v4l2_i2c_subdev_init(sd, client, &alvium_subdev_ops); sd->internal_ops = &alvium_internal_ops; - sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; alvium->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c index fc27238dd4d3..24873149096c 100644 --- a/drivers/media/i2c/ar0521.c +++ b/drivers/media/i2c/ar0521.c @@ -255,10 +255,10 @@ static u32 calc_pll(struct ar0521_dev *sensor, u32 freq, u16 *pre_ptr, u16 *mult continue; /* Minimum value */ if (new_mult > 254) break; /* Maximum, larger pre won't work either */ - if (sensor->extclk_freq * (u64)new_mult < AR0521_PLL_MIN * + if (sensor->extclk_freq * (u64)new_mult < (u64)AR0521_PLL_MIN * new_pre) continue; - if (sensor->extclk_freq * (u64)new_mult > AR0521_PLL_MAX * + if (sensor->extclk_freq * (u64)new_mult > (u64)AR0521_PLL_MAX * new_pre) break; /* Larger pre won't work either */ new_pll = div64_round_up(sensor->extclk_freq * (u64)new_mult, diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index 16f88db14981..8b028a84f5bc 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -24,7 +24,6 @@ #include <media/i2c/ds90ub9xx.h> #include <media/v4l2-ctrls.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-mediabus.h> #include <media/v4l2-subdev.h> @@ -717,8 +716,6 @@ static const struct v4l2_subdev_pad_ops ub953_pad_ops = { static const struct v4l2_subdev_core_ops ub953_subdev_core_ops = { .log_status = ub953_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_ops ub953_subdev_ops = { @@ -1246,7 +1243,7 @@ static int ub953_subdev_init(struct ub953_data *priv) priv->sd.internal_ops = &ub953_internal_ops; priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS; + V4L2_SUBDEV_FL_STREAMS; priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; priv->sd.entity.ops = &ub953_entity_ops; diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index ffe5f25f8647..33f362a00875 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -48,7 +48,6 @@ #include <media/i2c/ds90ub9xx.h> #include <media/mipi-csi2.h> #include <media/v4l2-ctrls.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> @@ -1286,7 +1285,7 @@ static int ub960_rxport_get_strobe_pos(struct ub960_data *priv, clk_delay += v & UB960_IR_RX_ANA_STROBE_SET_CLK_DELAY_MASK; - ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_1, &v); + ret = ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_1, &v); if (ret) return ret; @@ -3085,8 +3084,6 @@ static int ub960_log_status(struct v4l2_subdev *sd) static const struct v4l2_subdev_core_ops ub960_subdev_core_ops = { .log_status = ub960_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_internal_ops ub960_internal_ops = { @@ -3667,7 +3664,7 @@ static int ub960_create_subdev(struct ub960_data *priv) } priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS; + V4L2_SUBDEV_FL_STREAMS; priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; priv->sd.entity.ops = &ub960_entity_ops; diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c index 18ef2b35c9aa..3a4d100b9199 100644 --- a/drivers/media/i2c/dw9768.c +++ b/drivers/media/i2c/dw9768.c @@ -374,7 +374,8 @@ static int dw9768_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static int dw9768_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - pm_runtime_put(sd->dev); + pm_runtime_mark_last_busy(sd->dev); + pm_runtime_put_autosuspend(sd->dev); return 0; } @@ -471,10 +472,9 @@ static int dw9768_probe(struct i2c_client *client) * to be powered on in an ACPI system. Similarly for power off in * remove. */ - pm_runtime_enable(dev); full_power = (is_acpi_node(dev_fwnode(dev)) && acpi_dev_state_d0(dev)) || - (is_of_node(dev_fwnode(dev)) && !pm_runtime_enabled(dev)); + (is_of_node(dev_fwnode(dev)) && !IS_ENABLED(CONFIG_PM)); if (full_power) { ret = dw9768_runtime_resume(dev); if (ret < 0) { @@ -484,23 +484,26 @@ static int dw9768_probe(struct i2c_client *client) pm_runtime_set_active(dev); } + pm_runtime_enable(dev); ret = v4l2_async_register_subdev(&dw9768->sd); if (ret < 0) { dev_err(dev, "failed to register V4L2 subdev: %d", ret); goto err_power_off; } + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); pm_runtime_idle(dev); return 0; err_power_off: + pm_runtime_disable(dev); if (full_power) { dw9768_runtime_suspend(dev); pm_runtime_set_suspended(dev); } err_clean_entity: - pm_runtime_disable(dev); media_entity_cleanup(&dw9768->sd.entity); err_free_handler: v4l2_ctrl_handler_free(&dw9768->ctrls); @@ -517,12 +520,12 @@ static void dw9768_remove(struct i2c_client *client) v4l2_async_unregister_subdev(&dw9768->sd); v4l2_ctrl_handler_free(&dw9768->ctrls); media_entity_cleanup(&dw9768->sd.entity); + pm_runtime_disable(dev); if ((is_acpi_node(dev_fwnode(dev)) && acpi_dev_state_d0(dev)) || - (is_of_node(dev_fwnode(dev)) && !pm_runtime_enabled(dev))) { + (is_of_node(dev_fwnode(dev)) && !IS_ENABLED(CONFIG_PM))) { dw9768_runtime_suspend(dev); pm_runtime_set_suspended(dev); } - pm_runtime_disable(dev); } static const struct of_device_id dw9768_of_table[] = { diff --git a/drivers/media/i2c/gc0308.c b/drivers/media/i2c/gc0308.c index fa754a8a39a6..069f42785b3c 100644 --- a/drivers/media/i2c/gc0308.c +++ b/drivers/media/i2c/gc0308.c @@ -18,7 +18,6 @@ #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> @@ -987,8 +986,6 @@ static const struct v4l2_ctrl_ops gc0308_ctrl_ops = { static const struct v4l2_subdev_core_ops gc0308_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = gc0308_g_register, .s_register = gc0308_s_register, @@ -1338,7 +1335,6 @@ static int gc0308_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&gc0308->sd, client, &gc0308_subdev_ops); gc0308->sd.internal_ops = &gc0308_internal_ops; gc0308->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - gc0308->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; ret = gc0308_init_controls(gc0308); if (ret) diff --git a/drivers/media/i2c/gc05a2.c b/drivers/media/i2c/gc05a2.c index 0413c557e594..3f7f3d5abeeb 100644 --- a/drivers/media/i2c/gc05a2.c +++ b/drivers/media/i2c/gc05a2.c @@ -24,7 +24,6 @@ #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> @@ -1059,13 +1058,7 @@ static const struct v4l2_subdev_pad_ops gc05a2_subdev_pad_ops = { .get_selection = gc05a2_get_selection, }; -static const struct v4l2_subdev_core_ops gc05a2_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_ops gc05a2_subdev_ops = { - .core = &gc05a2_core_ops, .video = &gc05a2_video_ops, .pad = &gc05a2_subdev_pad_ops, }; @@ -1271,8 +1264,7 @@ static int gc05a2_probe(struct i2c_client *client) return dev_err_probe(dev, ret, "failed to init controls\n"); - gc05a2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + gc05a2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; gc05a2->pad.flags = MEDIA_PAD_FL_SOURCE; gc05a2->sd.dev = &client->dev; gc05a2->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; diff --git a/drivers/media/i2c/gc08a3.c b/drivers/media/i2c/gc08a3.c index 84de5cff958d..938709a677b6 100644 --- a/drivers/media/i2c/gc08a3.c +++ b/drivers/media/i2c/gc08a3.c @@ -24,7 +24,6 @@ #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> @@ -1001,13 +1000,7 @@ static const struct v4l2_subdev_pad_ops gc08a3_subdev_pad_ops = { .get_selection = gc08a3_get_selection, }; -static const struct v4l2_subdev_core_ops gc08a3_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_ops gc08a3_subdev_ops = { - .core = &gc08a3_core_ops, .video = &gc08a3_video_ops, .pad = &gc08a3_subdev_pad_ops, }; @@ -1247,8 +1240,7 @@ static int gc08a3_probe(struct i2c_client *client) goto err_power_off; } - gc08a3->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + gc08a3->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; gc08a3->pad.flags = MEDIA_PAD_FL_SOURCE; gc08a3->sd.dev = &client->dev; gc08a3->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c index 667bb756d056..ba02161d46e7 100644 --- a/drivers/media/i2c/gc2145.c +++ b/drivers/media/i2c/gc2145.c @@ -21,7 +21,6 @@ #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-mediabus.h> @@ -899,9 +898,11 @@ static int gc2145_config_mipi_mode(struct gc2145 *gc2145, return ret; } -static int gc2145_start_streaming(struct gc2145 *gc2145, - struct v4l2_subdev_state *state) +static int gc2145_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { + struct gc2145 *gc2145 = to_gc2145(sd); struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd); const struct gc2145_format *gc2145_format; struct v4l2_mbus_framefmt *fmt; @@ -967,8 +968,11 @@ err_rpm_put: return ret; } -static void gc2145_stop_streaming(struct gc2145 *gc2145) +static int gc2145_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { + struct gc2145 *gc2145 = to_gc2145(sd); struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd); int ret = 0; @@ -983,22 +987,6 @@ static void gc2145_stop_streaming(struct gc2145 *gc2145) pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); -} - -static int gc2145_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct gc2145 *gc2145 = to_gc2145(sd); - struct v4l2_subdev_state *state; - int ret = 0; - - state = v4l2_subdev_lock_and_get_active_state(sd); - - if (enable) - ret = gc2145_start_streaming(gc2145, state); - else - gc2145_stop_streaming(gc2145); - - v4l2_subdev_unlock_state(state); return ret; } @@ -1123,13 +1111,8 @@ static const u8 test_pattern_val[] = { GC2145_TEST_UNIFORM | GC2145_TEST_BLACK, }; -static const struct v4l2_subdev_core_ops gc2145_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_video_ops gc2145_video_ops = { - .s_stream = gc2145_set_stream, + .s_stream = v4l2_subdev_s_stream_helper, }; static const struct v4l2_subdev_pad_ops gc2145_pad_ops = { @@ -1138,10 +1121,11 @@ static const struct v4l2_subdev_pad_ops gc2145_pad_ops = { .set_fmt = gc2145_set_pad_format, .get_selection = gc2145_get_selection, .enum_frame_size = gc2145_enum_frame_size, + .enable_streams = gc2145_enable_streams, + .disable_streams = gc2145_disable_streams, }; static const struct v4l2_subdev_ops gc2145_subdev_ops = { - .core = &gc2145_core_ops, .video = &gc2145_video_ops, .pad = &gc2145_pad_ops, }; @@ -1407,8 +1391,7 @@ static int gc2145_probe(struct i2c_client *client) goto error_power_off; /* Initialize subdev */ - gc2145->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + gc2145->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; gc2145->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; /* Initialize source pad */ diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index f31f9886c924..3ac42d1ab8b4 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -644,7 +644,7 @@ struct hi556 { /* Current mode */ const struct hi556_mode *cur_mode; - /* To serialize asynchronus callbacks */ + /* To serialize asynchronous callbacks */ struct mutex mutex; /* True if the device has been identified */ diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index e78a80b2bb2e..2d54cea113e1 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -26,7 +26,6 @@ #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-mediabus.h> @@ -922,11 +921,6 @@ static int imx219_init_state(struct v4l2_subdev *sd, return 0; } -static const struct v4l2_subdev_core_ops imx219_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_video_ops imx219_video_ops = { .s_stream = imx219_set_stream, }; @@ -940,7 +934,6 @@ static const struct v4l2_subdev_pad_ops imx219_pad_ops = { }; static const struct v4l2_subdev_ops imx219_subdev_ops = { - .core = &imx219_core_ops, .video = &imx219_video_ops, .pad = &imx219_pad_ops, }; @@ -1166,8 +1159,7 @@ static int imx219_probe(struct i2c_client *client) goto error_power_off; /* Initialize subdev */ - imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; /* Initialize source pad */ diff --git a/drivers/media/i2c/imx283.c b/drivers/media/i2c/imx283.c index 94276f4f2d83..f676faf4b301 100644 --- a/drivers/media/i2c/imx283.c +++ b/drivers/media/i2c/imx283.c @@ -32,7 +32,6 @@ #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-mediabus.h> @@ -1284,11 +1283,6 @@ static int imx283_get_selection(struct v4l2_subdev *sd, } } -static const struct v4l2_subdev_core_ops imx283_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_video_ops imx283_video_ops = { .s_stream = v4l2_subdev_s_stream_helper, }; @@ -1308,7 +1302,6 @@ static const struct v4l2_subdev_internal_ops imx283_internal_ops = { }; static const struct v4l2_subdev_ops imx283_subdev_ops = { - .core = &imx283_core_ops, .video = &imx283_video_ops, .pad = &imx283_pad_ops, }; @@ -1548,8 +1541,7 @@ static int imx283_probe(struct i2c_client *client) goto error_pm; /* Initialize subdev */ - imx283->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + imx283->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; imx283->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; imx283->sd.internal_ops = &imx283_internal_ops; diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 458905dfb3e1..f5ee6bd3b52d 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -24,7 +24,6 @@ #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> @@ -78,7 +77,6 @@ #define IMX290_ADBIT2 CCI_REG8(0x317c) #define IMX290_ADBIT2_10BIT 0x12 #define IMX290_ADBIT2_12BIT 0x00 -#define IMX290_CHIP_ID CCI_REG16_LE(0x319a) #define IMX290_ADBIT3 CCI_REG8(0x31ec) #define IMX290_ADBIT3_10BIT 0x37 #define IMX290_ADBIT3_12BIT 0x0e @@ -1211,11 +1209,6 @@ static int imx290_entity_init_state(struct v4l2_subdev *subdev, return 0; } -static const struct v4l2_subdev_core_ops imx290_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_video_ops imx290_video_ops = { .s_stream = imx290_set_stream, }; @@ -1229,7 +1222,6 @@ static const struct v4l2_subdev_pad_ops imx290_pad_ops = { }; static const struct v4l2_subdev_ops imx290_subdev_ops = { - .core = &imx290_core_ops, .video = &imx290_video_ops, .pad = &imx290_pad_ops, }; @@ -1250,11 +1242,20 @@ static int imx290_subdev_init(struct imx290 *imx290) imx290->current_mode = &imx290_modes_ptr(imx290)[0]; + /* + * After linking the subdev with the imx290 instance, we are allowed to + * use the pm_runtime functions. Decrease the PM usage count. The device + * will get suspended after the autosuspend delay, turning the power + * off. However, the communication happening in imx290_ctrl_update() + * will already be prevented even before the delay. + */ v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); - imx290->sd.internal_ops = &imx290_internal_ops; - imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; imx290->sd.dev = imx290->dev; + pm_runtime_mark_last_busy(imx290->dev); + pm_runtime_put_autosuspend(imx290->dev); + + imx290->sd.internal_ops = &imx290_internal_ops; + imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; imx290->sd.entity.ops = &imx290_subdev_entity_ops; imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; @@ -1580,6 +1581,16 @@ static int imx290_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); + /* + * Make sure the sensor is available, in STANDBY and not streaming + * before the V4L2 subdev is initialized. + */ + ret = imx290_stop_streaming(imx290); + if (ret) { + ret = dev_err_probe(dev, ret, "Could not initialize device\n"); + goto err_pm; + } + /* Initialize the V4L2 subdev. */ ret = imx290_subdev_init(imx290); if (ret) @@ -1599,13 +1610,6 @@ static int imx290_probe(struct i2c_client *client) goto err_subdev; } - /* - * Decrease the PM usage count. The device will get suspended after the - * autosuspend delay, turning the power off. - */ - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - return 0; err_subdev: diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index a20b0db330d3..3f7924aa1bd3 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -1113,8 +1113,7 @@ static int imx415_subdev_init(struct imx415 *sensor) if (ret) return ret; - sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sensor->pad.flags = MEDIA_PAD_FL_SOURCE; sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad); diff --git a/drivers/media/i2c/max96717.c b/drivers/media/i2c/max96717.c index 4e85b8eb1e77..9259d58ba734 100644 --- a/drivers/media/i2c/max96717.c +++ b/drivers/media/i2c/max96717.c @@ -697,8 +697,10 @@ static int max96717_subdev_init(struct max96717_priv *priv) priv->pads[MAX96717_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&priv->sd.entity, 2, priv->pads); - if (ret) - return dev_err_probe(dev, ret, "Failed to init pads\n"); + if (ret) { + dev_err_probe(dev, ret, "Failed to init pads\n"); + goto err_free_ctrl; + } ret = v4l2_subdev_init_finalize(&priv->sd); if (ret) { diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index d8735c246e52..4ef5fb06131d 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -17,14 +17,12 @@ #include <linux/log2.h> #include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of.h> -#include <linux/of_graph.h> #include <linux/pm.h> +#include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/videodev2.h> -#include <media/i2c/mt9p031.h> #include <media/v4l2-async.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -113,18 +111,25 @@ #define MT9P031_TEST_PATTERN_RED 0xa2 #define MT9P031_TEST_PATTERN_BLUE 0xa3 +struct mt9p031_model_info { + u32 code; +}; + struct mt9p031 { struct v4l2_subdev subdev; struct media_pad pad; struct v4l2_rect crop; /* Sensor window */ struct v4l2_mbus_framefmt format; - struct mt9p031_platform_data *pdata; struct mutex power_lock; /* lock to protect power_count */ int power_count; struct clk *clk; struct regulator_bulk_data regulators[3]; + unsigned int pixclk_pol:1; + int ext_freq; + int target_freq; + u32 code; struct aptina_pll pll; unsigned int clk_div; @@ -225,7 +230,6 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) }; struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); - struct mt9p031_platform_data *pdata = mt9p031->pdata; unsigned long ext_freq; int ret; @@ -233,7 +237,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) if (IS_ERR(mt9p031->clk)) return PTR_ERR(mt9p031->clk); - ret = clk_set_rate(mt9p031->clk, pdata->ext_freq); + ret = clk_set_rate(mt9p031->clk, mt9p031->ext_freq); if (ret < 0) return ret; @@ -245,7 +249,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) if (ext_freq > limits.ext_clock_max) { unsigned int div; - div = DIV_ROUND_UP(ext_freq, pdata->target_freq); + div = DIV_ROUND_UP(ext_freq, mt9p031->target_freq); div = roundup_pow_of_two(div) / 2; mt9p031->clk_div = min_t(unsigned int, div, 64); @@ -255,7 +259,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) } mt9p031->pll.ext_clock = ext_freq; - mt9p031->pll.pix_clock = pdata->target_freq; + mt9p031->pll.pix_clock = mt9p031->target_freq; mt9p031->use_pll = true; return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll); @@ -376,7 +380,7 @@ static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on) } /* Configure the pixel clock polarity */ - if (mt9p031->pdata && mt9p031->pdata->pixclk_pol) { + if (mt9p031->pixclk_pol) { ret = mt9p031_write(client, MT9P031_PIXEL_CLOCK_CONTROL, MT9P031_PIXEL_CLOCK_INVERT); if (ret < 0) @@ -1057,53 +1061,41 @@ static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = { * Driver initialization and probing */ -static struct mt9p031_platform_data * -mt9p031_get_pdata(struct i2c_client *client) +static int mt9p031_parse_properties(struct mt9p031 *mt9p031, struct device *dev) { - struct mt9p031_platform_data *pdata = NULL; - struct device_node *np; struct v4l2_fwnode_endpoint endpoint = { .bus_type = V4L2_MBUS_PARALLEL }; + struct fwnode_handle *np; + int ret; - if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) - return client->dev.platform_data; - - np = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1); + np = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); if (!np) - return NULL; - - if (v4l2_fwnode_endpoint_parse(of_fwnode_handle(np), &endpoint) < 0) - goto done; + return dev_err_probe(dev, -EINVAL, "endpoint node not found\n"); - pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - goto done; + ret = v4l2_fwnode_endpoint_parse(np, &endpoint); + fwnode_handle_put(np); + if (ret) + return dev_err_probe(dev, -EINVAL, "could not parse endpoint\n"); - of_property_read_u32(np, "input-clock-frequency", &pdata->ext_freq); - of_property_read_u32(np, "pixel-clock-frequency", &pdata->target_freq); + fwnode_property_read_u32(np, "input-clock-frequency", + &mt9p031->ext_freq); + fwnode_property_read_u32(np, "pixel-clock-frequency", + &mt9p031->target_freq); - pdata->pixclk_pol = !!(endpoint.bus.parallel.flags & - V4L2_MBUS_PCLK_SAMPLE_RISING); + mt9p031->pixclk_pol = !!(endpoint.bus.parallel.flags & + V4L2_MBUS_PCLK_SAMPLE_RISING); -done: - of_node_put(np); - return pdata; + return 0; } static int mt9p031_probe(struct i2c_client *client) { - struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client); struct i2c_adapter *adapter = client->adapter; struct mt9p031 *mt9p031; unsigned int i; int ret; - if (pdata == NULL) { - dev_err(&client->dev, "No platform data\n"); - return -EINVAL; - } - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { dev_warn(&client->dev, "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); @@ -1114,10 +1106,13 @@ static int mt9p031_probe(struct i2c_client *client) if (mt9p031 == NULL) return -ENOMEM; - mt9p031->pdata = pdata; + ret = mt9p031_parse_properties(mt9p031, &client->dev); + if (ret) + return ret; + mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF; mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC; - mt9p031->code = (uintptr_t)i2c_get_match_data(client); + mt9p031->code = (uintptr_t)device_get_match_data(&client->dev); mt9p031->regulators[0].supply = "vdd"; mt9p031->regulators[1].supply = "vdd_io"; @@ -1145,8 +1140,8 @@ static int mt9p031_probe(struct i2c_client *client) v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, - V4L2_CID_PIXEL_RATE, pdata->target_freq, - pdata->target_freq, 1, pdata->target_freq); + V4L2_CID_PIXEL_RATE, mt9p031->target_freq, + mt9p031->target_freq, 1, mt9p031->target_freq); v4l2_ctrl_new_std_menu_items(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_TEST_PATTERN, ARRAY_SIZE(mt9p031_test_pattern_menu) - 1, 0, @@ -1213,18 +1208,18 @@ static void mt9p031_remove(struct i2c_client *client) mutex_destroy(&mt9p031->power_lock); } -static const struct i2c_device_id mt9p031_id[] = { - { "mt9p006", MEDIA_BUS_FMT_SGRBG12_1X12 }, - { "mt9p031", MEDIA_BUS_FMT_SGRBG12_1X12 }, - { "mt9p031m", MEDIA_BUS_FMT_Y12_1X12 }, - { /* sentinel */ } +static const struct mt9p031_model_info mt9p031_models_bayer = { + .code = MEDIA_BUS_FMT_SGRBG12_1X12 +}; + +static const struct mt9p031_model_info mt9p031_models_mono = { + .code = MEDIA_BUS_FMT_Y12_1X12 }; -MODULE_DEVICE_TABLE(i2c, mt9p031_id); static const struct of_device_id mt9p031_of_match[] = { - { .compatible = "aptina,mt9p006", .data = (void *)MEDIA_BUS_FMT_SGRBG12_1X12 }, - { .compatible = "aptina,mt9p031", .data = (void *)MEDIA_BUS_FMT_SGRBG12_1X12 }, - { .compatible = "aptina,mt9p031m", .data = (void *)MEDIA_BUS_FMT_Y12_1X12 }, + { .compatible = "aptina,mt9p006", .data = &mt9p031_models_bayer }, + { .compatible = "aptina,mt9p031", .data = &mt9p031_models_bayer }, + { .compatible = "aptina,mt9p031m", .data = &mt9p031_models_mono }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mt9p031_of_match); @@ -1236,7 +1231,6 @@ static struct i2c_driver mt9p031_i2c_driver = { }, .probe = mt9p031_probe, .remove = mt9p031_remove, - .id_table = mt9p031_id, }; module_i2c_driver(mt9p031_i2c_driver); diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c index 0b9fb1ddbe59..141cb6f75b55 100644 --- a/drivers/media/i2c/ov01a10.c +++ b/drivers/media/i2c/ov01a10.c @@ -13,7 +13,6 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #define OV01A10_LINK_FREQ_400MHZ 400000000ULL @@ -804,8 +803,6 @@ static int ov01a10_get_selection(struct v4l2_subdev *sd, static const struct v4l2_subdev_core_ops ov01a10_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops ov01a10_video_ops = { @@ -892,8 +889,7 @@ static int ov01a10_probe(struct i2c_client *client) } ov01a10->sd.state_lock = ov01a10->ctrl_handler.lock; - ov01a10->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + ov01a10->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov01a10->sd.entity.ops = &ov01a10_subdev_entity_ops; ov01a10->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ov01a10->pad.flags = MEDIA_PAD_FL_SOURCE; diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c index 7ead3c720e0e..b9682264e2f5 100644 --- a/drivers/media/i2c/ov08x40.c +++ b/drivers/media/i2c/ov08x40.c @@ -3,10 +3,13 @@ #include <linux/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/i2c.h> +#include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -1215,7 +1218,7 @@ static const char * const ov08x40_test_pattern_menu[] = { /* Configurations for supported link frequencies */ #define OV08X40_LINK_FREQ_400MHZ 400000000ULL #define OV08X40_SCLK_96MHZ 96000000ULL -#define OV08X40_EXT_CLK 19200000 +#define OV08X40_XVCLK 19200000 #define OV08X40_DATA_LANES 4 /* @@ -1279,6 +1282,12 @@ static const struct ov08x40_mode supported_modes[] = { }, }; +static const char * const ov08x40_supply_names[] = { + "dovdd", /* Digital I/O power */ + "avdd", /* Analog power */ + "dvdd", /* Digital core power */ +}; + struct ov08x40 { struct v4l2_subdev sd; struct media_pad pad; @@ -1291,6 +1300,10 @@ struct ov08x40 { struct v4l2_ctrl *hblank; struct v4l2_ctrl *exposure; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(ov08x40_supply_names)]; + /* Current mode */ const struct ov08x40_mode *cur_mode; @@ -1303,6 +1316,61 @@ struct ov08x40 { #define to_ov08x40(_sd) container_of(_sd, struct ov08x40, sd) +static int ov08x40_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov08x40 *ov08x = to_ov08x40(sd); + int ret; + + if (is_acpi_node(dev_fwnode(dev))) + return 0; + + ret = clk_prepare_enable(ov08x->xvclk); + if (ret < 0) { + dev_err(dev, "failed to enable xvclk\n"); + return ret; + } + + if (ov08x->reset_gpio) { + gpiod_set_value_cansleep(ov08x->reset_gpio, 1); + usleep_range(1000, 2000); + } + + ret = regulator_bulk_enable(ARRAY_SIZE(ov08x40_supply_names), + ov08x->supplies); + if (ret < 0) { + dev_err(dev, "failed to enable regulators\n"); + goto disable_clk; + } + + gpiod_set_value_cansleep(ov08x->reset_gpio, 0); + usleep_range(1500, 1800); + + return 0; + +disable_clk: + gpiod_set_value_cansleep(ov08x->reset_gpio, 1); + clk_disable_unprepare(ov08x->xvclk); + + return ret; +} + +static int ov08x40_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov08x40 *ov08x = to_ov08x40(sd); + + if (is_acpi_node(dev_fwnode(dev))) + return 0; + + gpiod_set_value_cansleep(ov08x->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ov08x40_supply_names), + ov08x->supplies); + clk_disable_unprepare(ov08x->xvclk); + + return 0; +} + /* Read registers up to 4 at a time */ static int ov08x40_read_reg(struct ov08x40 *ov08x, u16 reg, u32 len, u32 *val) @@ -1339,15 +1407,13 @@ static int ov08x40_read_reg(struct ov08x40 *ov08x, return 0; } -static int ov08x40_burst_fill_regs(struct ov08x40 *ov08x, u16 first_reg, - u16 last_reg, u8 val) +static int __ov08x40_burst_fill_regs(struct i2c_client *client, u16 first_reg, + u16 last_reg, size_t num_regs, u8 val) { - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); struct i2c_msg msgs; - size_t i, num_regs; + size_t i; int ret; - num_regs = last_reg - first_reg + 1; msgs.addr = client->addr; msgs.flags = 0; msgs.len = 2 + num_regs; @@ -1373,6 +1439,31 @@ static int ov08x40_burst_fill_regs(struct ov08x40 *ov08x, u16 first_reg, return 0; } +static int ov08x40_burst_fill_regs(struct ov08x40 *ov08x, u16 first_reg, + u16 last_reg, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); + size_t num_regs, num_write_regs; + int ret; + + num_regs = last_reg - first_reg + 1; + num_write_regs = num_regs; + + if (client->adapter->quirks && client->adapter->quirks->max_write_len) + num_write_regs = client->adapter->quirks->max_write_len - 2; + + while (first_reg < last_reg) { + ret = __ov08x40_burst_fill_regs(client, first_reg, last_reg, + num_write_regs, val); + if (ret) + return ret; + + first_reg += num_write_regs; + } + + return 0; +} + /* Write registers up to 4 at a time */ static int ov08x40_write_reg(struct ov08x40 *ov08x, u16 reg, u32 len, u32 __val) @@ -2049,7 +2140,7 @@ static void ov08x40_free_controls(struct ov08x40 *ov08x) mutex_destroy(&ov08x->mutex); } -static int ov08x40_check_hwcfg(struct device *dev) +static int ov08x40_check_hwcfg(struct ov08x40 *ov08x, struct device *dev) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY @@ -2058,21 +2149,46 @@ static int ov08x40_check_hwcfg(struct device *dev) struct fwnode_handle *fwnode = dev_fwnode(dev); unsigned int i, j; int ret; - u32 ext_clk; + u32 xvclk_rate; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &ext_clk); - if (ret) { - dev_err(dev, "can't get clock frequency"); - return ret; + if (!is_acpi_node(fwnode)) { + ov08x->xvclk = devm_clk_get(dev, NULL); + if (IS_ERR(ov08x->xvclk)) { + dev_err(dev, "could not get xvclk clock (%pe)\n", + ov08x->xvclk); + return PTR_ERR(ov08x->xvclk); + } + + xvclk_rate = clk_get_rate(ov08x->xvclk); + + ov08x->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(ov08x->reset_gpio)) + return PTR_ERR(ov08x->reset_gpio); + + for (i = 0; i < ARRAY_SIZE(ov08x40_supply_names); i++) + ov08x->supplies[i].supply = ov08x40_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, + ARRAY_SIZE(ov08x40_supply_names), + ov08x->supplies); + if (ret) + return ret; + } else { + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &xvclk_rate); + if (ret) { + dev_err(dev, "can't get clock frequency"); + return ret; + } } - if (ext_clk != OV08X40_EXT_CLK) { + if (xvclk_rate != OV08X40_XVCLK) { dev_err(dev, "external clock %d is not supported", - ext_clk); + xvclk_rate); return -EINVAL; } @@ -2120,32 +2236,37 @@ out_err: } static int ov08x40_probe(struct i2c_client *client) -{ - struct ov08x40 *ov08x; +{ struct ov08x40 *ov08x; int ret; bool full_power; + ov08x = devm_kzalloc(&client->dev, sizeof(*ov08x), GFP_KERNEL); + if (!ov08x) + return -ENOMEM; + /* Check HW config */ - ret = ov08x40_check_hwcfg(&client->dev); + ret = ov08x40_check_hwcfg(ov08x, &client->dev); if (ret) { dev_err(&client->dev, "failed to check hwcfg: %d", ret); return ret; } - ov08x = devm_kzalloc(&client->dev, sizeof(*ov08x), GFP_KERNEL); - if (!ov08x) - return -ENOMEM; - /* Initialize subdev */ v4l2_i2c_subdev_init(&ov08x->sd, client, &ov08x40_subdev_ops); full_power = acpi_dev_state_d0(&client->dev); if (full_power) { + ret = ov08x40_power_on(&client->dev); + if (ret) { + dev_err(&client->dev, "failed to power on\n"); + return ret; + } + /* Check module identity */ ret = ov08x40_identify_module(ov08x); if (ret) { dev_err(&client->dev, "failed to find sensor: %d\n", ret); - return ret; + goto probe_power_off; } } @@ -2154,7 +2275,7 @@ static int ov08x40_probe(struct i2c_client *client) ret = ov08x40_init_controls(ov08x); if (ret) - return ret; + goto probe_power_off; /* Initialize subdev */ ov08x->sd.internal_ops = &ov08x40_internal_ops; @@ -2187,6 +2308,9 @@ error_media_entity: error_handler_free: ov08x40_free_controls(ov08x); +probe_power_off: + ov08x40_power_off(&client->dev); + return ret; } @@ -2201,6 +2325,8 @@ static void ov08x40_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); + + ov08x40_power_off(&client->dev); } #ifdef CONFIG_ACPI @@ -2212,10 +2338,17 @@ static const struct acpi_device_id ov08x40_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, ov08x40_acpi_ids); #endif +static const struct of_device_id ov08x40_of_match[] = { + { .compatible = "ovti,ov08x40" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ov08x40_of_match); + static struct i2c_driver ov08x40_i2c_driver = { .driver = { .name = "ov08x40", .acpi_match_table = ACPI_PTR(ov08x40_acpi_ids), + .of_match_table = ov08x40_of_match, }, .probe = ov08x40_probe, .remove = ov08x40_remove, diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index bd0b2f0f0d45..c484b753a718 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -530,7 +530,7 @@ struct ov2740 { /* Current mode */ const struct ov2740_mode *cur_mode; - /* NVM data inforamtion */ + /* NVM data information */ struct nvm_data *nvm; /* Supported modes */ @@ -1132,7 +1132,8 @@ static int ov2740_check_hwcfg(struct device *dev) */ ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) - return -EPROBE_DEFER; + return dev_err_probe(dev, -EPROBE_DEFER, + "waiting for fwnode graph endpoint\n"); ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); if (ret) { @@ -1330,7 +1331,7 @@ static int ov2740_probe(struct i2c_client *client) ret = ov2740_check_hwcfg(dev); if (ret) - return dev_err_probe(dev, ret, "failed to check HW configuration\n"); + return ret; ov2740->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ov2740->reset_gpio)) { diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index c1d3fce4a7d3..da5cb5f45a4f 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -377,7 +377,7 @@ struct reg_value { struct ov5640_timings { /* Analog crop rectangle. */ struct v4l2_rect analog_crop; - /* Visibile crop: from analog crop top-left corner. */ + /* Visible crop: from analog crop top-left corner. */ struct v4l2_rect crop; /* Total pixels per line: width + fixed hblank. */ u32 htot; diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index 0c32bd2940ec..004d0ee5c3f5 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -88,7 +88,6 @@ struct ov5645 { struct v4l2_subdev sd; struct media_pad pad; struct v4l2_fwnode_endpoint ep; - struct v4l2_mbus_framefmt fmt; struct v4l2_rect crop; struct clk *xclk; @@ -105,8 +104,6 @@ struct ov5645 { u8 timing_tc_reg20; u8 timing_tc_reg21; - struct mutex power_lock; /* lock to protect power state */ - struct gpio_desc *enable_gpio; struct gpio_desc *rst_gpio; }; @@ -781,11 +778,8 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl) struct ov5645, ctrls); int ret; - mutex_lock(&ov5645->power_lock); - if (!pm_runtime_get_if_in_use(ov5645->dev)) { - mutex_unlock(&ov5645->power_lock); + if (!pm_runtime_get_if_in_use(ov5645->dev)) return 0; - } switch (ctrl->id) { case V4L2_CID_SATURATION: @@ -816,7 +810,6 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl) pm_runtime_mark_last_busy(ov5645->dev); pm_runtime_put_autosuspend(ov5645->dev); - mutex_unlock(&ov5645->power_lock); return ret; } @@ -855,49 +848,6 @@ static int ov5645_enum_frame_size(struct v4l2_subdev *subdev, return 0; } -static struct v4l2_mbus_framefmt * -__ov5645_get_pad_format(struct ov5645 *ov5645, - struct v4l2_subdev_state *sd_state, - unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - switch (which) { - case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_state_get_format(sd_state, pad); - case V4L2_SUBDEV_FORMAT_ACTIVE: - return &ov5645->fmt; - default: - return NULL; - } -} - -static int ov5645_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct ov5645 *ov5645 = to_ov5645(sd); - - format->format = *__ov5645_get_pad_format(ov5645, sd_state, - format->pad, - format->which); - return 0; -} - -static struct v4l2_rect * -__ov5645_get_pad_crop(struct ov5645 *ov5645, - struct v4l2_subdev_state *sd_state, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - switch (which) { - case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_state_get_crop(sd_state, pad); - case V4L2_SUBDEV_FORMAT_ACTIVE: - return &ov5645->crop; - default: - return NULL; - } -} - static int ov5645_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) @@ -908,33 +858,30 @@ static int ov5645_set_format(struct v4l2_subdev *sd, const struct ov5645_mode_info *new_mode; int ret; - __crop = __ov5645_get_pad_crop(ov5645, sd_state, format->pad, - format->which); - + __crop = v4l2_subdev_state_get_crop(sd_state, 0); new_mode = v4l2_find_nearest_size(ov5645_mode_info_data, - ARRAY_SIZE(ov5645_mode_info_data), - width, height, - format->format.width, format->format.height); + ARRAY_SIZE(ov5645_mode_info_data), + width, height, format->format.width, + format->format.height); __crop->width = new_mode->width; __crop->height = new_mode->height; if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - ret = v4l2_ctrl_s_ctrl_int64(ov5645->pixel_clock, - new_mode->pixel_clock); + ret = __v4l2_ctrl_s_ctrl_int64(ov5645->pixel_clock, + new_mode->pixel_clock); if (ret < 0) return ret; - ret = v4l2_ctrl_s_ctrl(ov5645->link_freq, - new_mode->link_freq); + ret = __v4l2_ctrl_s_ctrl(ov5645->link_freq, + new_mode->link_freq); if (ret < 0) return ret; ov5645->current_mode = new_mode; } - __format = __ov5645_get_pad_format(ov5645, sd_state, format->pad, - format->which); + __format = v4l2_subdev_state_get_format(sd_state, 0); __format->width = __crop->width; __format->height = __crop->height; __format->code = MEDIA_BUS_FMT_UYVY8_1X16; @@ -949,11 +896,15 @@ static int ov5645_set_format(struct v4l2_subdev *sd, static int ov5645_init_state(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state) { - struct v4l2_subdev_format fmt = { 0 }; - - fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - fmt.format.width = 1920; - fmt.format.height = 1080; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .pad = 0, + .format = { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .width = ov5645_mode_info_data[1].width, + .height = ov5645_mode_info_data[1].height, + }, + }; ov5645_set_format(subdev, sd_state, &fmt); @@ -964,82 +915,88 @@ static int ov5645_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct ov5645 *ov5645 = to_ov5645(sd); - if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - sel->r = *__ov5645_get_pad_crop(ov5645, sd_state, sel->pad, - sel->which); + sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); return 0; } -static int ov5645_s_stream(struct v4l2_subdev *subdev, int enable) +static int ov5645_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { - struct ov5645 *ov5645 = to_ov5645(subdev); + struct ov5645 *ov5645 = to_ov5645(sd); int ret; - if (enable) { - ret = pm_runtime_resume_and_get(ov5645->dev); - if (ret < 0) - return ret; + ret = pm_runtime_resume_and_get(ov5645->dev); + if (ret < 0) + return ret; - ret = ov5645_set_register_array(ov5645, + ret = ov5645_set_register_array(ov5645, ov5645->current_mode->data, ov5645->current_mode->data_size); - if (ret < 0) { - dev_err(ov5645->dev, "could not set mode %dx%d\n", - ov5645->current_mode->width, - ov5645->current_mode->height); - goto err_rpm_put; - } - ret = v4l2_ctrl_handler_setup(&ov5645->ctrls); - if (ret < 0) { - dev_err(ov5645->dev, "could not sync v4l2 controls\n"); - goto err_rpm_put; - } - - ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x45); - if (ret < 0) - goto err_rpm_put; - - ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, - OV5645_SYSTEM_CTRL0_START); - if (ret < 0) - goto err_rpm_put; - } else { - ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x40); - if (ret < 0) - goto stream_off_rpm_put; + if (ret < 0) { + dev_err(ov5645->dev, "could not set mode %dx%d\n", + ov5645->current_mode->width, + ov5645->current_mode->height); + goto err_rpm_put; + } + ret = __v4l2_ctrl_handler_setup(&ov5645->ctrls); + if (ret < 0) { + dev_err(ov5645->dev, "could not sync v4l2 controls\n"); + goto err_rpm_put; + } - ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, - OV5645_SYSTEM_CTRL0_STOP); + ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x45); + if (ret < 0) + goto err_rpm_put; - goto stream_off_rpm_put; - } + ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, + OV5645_SYSTEM_CTRL0_START); + if (ret < 0) + goto err_rpm_put; return 0; err_rpm_put: pm_runtime_put_sync(ov5645->dev); return ret; +} + +static int ov5645_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct ov5645 *ov5645 = to_ov5645(sd); + int ret; + + ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x40); + if (ret < 0) + goto rpm_put; -stream_off_rpm_put: + ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, + OV5645_SYSTEM_CTRL0_STOP); + +rpm_put: pm_runtime_mark_last_busy(ov5645->dev); pm_runtime_put_autosuspend(ov5645->dev); + return ret; } static const struct v4l2_subdev_video_ops ov5645_video_ops = { - .s_stream = ov5645_s_stream, + .s_stream = v4l2_subdev_s_stream_helper, }; static const struct v4l2_subdev_pad_ops ov5645_subdev_pad_ops = { .enum_mbus_code = ov5645_enum_mbus_code, .enum_frame_size = ov5645_enum_frame_size, - .get_fmt = ov5645_get_format, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = ov5645_set_format, .get_selection = ov5645_get_selection, + .enable_streams = ov5645_enable_streams, + .disable_streams = ov5645_disable_streams, }; static const struct v4l2_subdev_ops ov5645_subdev_ops = { @@ -1069,51 +1026,44 @@ static int ov5645_probe(struct i2c_client *client) ov5645->dev = dev; endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); - if (!endpoint) { - dev_err(dev, "endpoint node not found\n"); - return -EINVAL; - } + if (!endpoint) + return dev_err_probe(dev, -EINVAL, + "endpoint node not found\n"); ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), &ov5645->ep); of_node_put(endpoint); - if (ret < 0) { - dev_err(dev, "parsing endpoint node failed\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, + "parsing endpoint node failed\n"); - if (ov5645->ep.bus_type != V4L2_MBUS_CSI2_DPHY) { - dev_err(dev, "invalid bus type, must be CSI2\n"); - return -EINVAL; - } + if (ov5645->ep.bus_type != V4L2_MBUS_CSI2_DPHY) + return dev_err_probe(dev, -EINVAL, + "invalid bus type, must be CSI2\n"); /* get system clock (xclk) */ ov5645->xclk = devm_clk_get(dev, NULL); - if (IS_ERR(ov5645->xclk)) { - dev_err(dev, "could not get xclk"); - return PTR_ERR(ov5645->xclk); - } + if (IS_ERR(ov5645->xclk)) + return dev_err_probe(dev, PTR_ERR(ov5645->xclk), + "could not get xclk"); ret = of_property_read_u32(dev->of_node, "clock-frequency", &xclk_freq); - if (ret) { - dev_err(dev, "could not get xclk frequency\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "could not get xclk frequency\n"); /* external clock must be 24MHz, allow 1% tolerance */ - if (xclk_freq < 23760000 || xclk_freq > 24240000) { - dev_err(dev, "external clock frequency %u is not supported\n", - xclk_freq); - return -EINVAL; - } + if (xclk_freq < 23760000 || xclk_freq > 24240000) + return dev_err_probe(dev, -EINVAL, + "unsupported xclk frequency %u\n", + xclk_freq); ret = clk_set_rate(ov5645->xclk, xclk_freq); - if (ret) { - dev_err(dev, "could not set xclk frequency\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "could not set xclk frequency\n"); for (i = 0; i < OV5645_NUM_SUPPLIES; i++) ov5645->supplies[i].supply = ov5645_supply_name[i]; @@ -1124,18 +1074,14 @@ static int ov5645_probe(struct i2c_client *client) return ret; ov5645->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); - if (IS_ERR(ov5645->enable_gpio)) { - dev_err(dev, "cannot get enable gpio\n"); - return PTR_ERR(ov5645->enable_gpio); - } + if (IS_ERR(ov5645->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(ov5645->enable_gpio), + "cannot get enable gpio\n"); ov5645->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(ov5645->rst_gpio)) { - dev_err(dev, "cannot get reset gpio\n"); - return PTR_ERR(ov5645->rst_gpio); - } - - mutex_init(&ov5645->power_lock); + if (IS_ERR(ov5645->rst_gpio)) + return dev_err_probe(dev, PTR_ERR(ov5645->rst_gpio), + "cannot get reset gpio\n"); v4l2_ctrl_handler_init(&ov5645->ctrls, 9); v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops, @@ -1170,9 +1116,8 @@ static int ov5645_probe(struct i2c_client *client) ov5645->sd.ctrl_handler = &ov5645->ctrls; if (ov5645->ctrls.error) { - dev_err(dev, "%s: control initialization error %d\n", - __func__, ov5645->ctrls.error); ret = ov5645->ctrls.error; + dev_err_probe(dev, ret, "failed to add controls\n"); goto free_ctrl; } @@ -1180,12 +1125,12 @@ static int ov5645_probe(struct i2c_client *client) ov5645->sd.internal_ops = &ov5645_internal_ops; ov5645->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov5645->pad.flags = MEDIA_PAD_FL_SOURCE; - ov5645->sd.dev = &client->dev; + ov5645->sd.dev = dev; ov5645->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&ov5645->sd.entity, 1, &ov5645->pad); if (ret < 0) { - dev_err(dev, "could not register media entity\n"); + dev_err_probe(dev, ret, "could not register media entity\n"); goto free_ctrl; } @@ -1195,14 +1140,14 @@ static int ov5645_probe(struct i2c_client *client) ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_HIGH, &chip_id_high); if (ret < 0 || chip_id_high != OV5645_CHIP_ID_HIGH_BYTE) { - dev_err(dev, "could not read ID high\n"); ret = -ENODEV; + dev_err_probe(dev, ret, "could not read ID high\n"); goto power_down; } ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_LOW, &chip_id_low); if (ret < 0 || chip_id_low != OV5645_CHIP_ID_LOW_BYTE) { - dev_err(dev, "could not read ID low\n"); ret = -ENODEV; + dev_err_probe(dev, ret, "could not read ID low\n"); goto power_down; } @@ -1211,24 +1156,31 @@ static int ov5645_probe(struct i2c_client *client) ret = ov5645_read_reg(ov5645, OV5645_AEC_PK_MANUAL, &ov5645->aec_pk_manual); if (ret < 0) { - dev_err(dev, "could not read AEC/AGC mode\n"); ret = -ENODEV; + dev_err_probe(dev, ret, "could not read AEC/AGC mode\n"); goto power_down; } ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG20, &ov5645->timing_tc_reg20); if (ret < 0) { - dev_err(dev, "could not read vflip value\n"); ret = -ENODEV; + dev_err_probe(dev, ret, "could not read vflip value\n"); goto power_down; } ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG21, &ov5645->timing_tc_reg21); if (ret < 0) { - dev_err(dev, "could not read hflip value\n"); ret = -ENODEV; + dev_err_probe(dev, ret, "could not read hflip value\n"); + goto power_down; + } + + ov5645->sd.state_lock = ov5645->ctrls.lock; + ret = v4l2_subdev_init_finalize(&ov5645->sd); + if (ret < 0) { + dev_err_probe(dev, ret, "subdev init error\n"); goto power_down; } @@ -1236,11 +1188,9 @@ static int ov5645_probe(struct i2c_client *client) pm_runtime_get_noresume(dev); pm_runtime_enable(dev); - ov5645_init_state(&ov5645->sd, NULL); - - ret = v4l2_async_register_subdev(&ov5645->sd); + ret = v4l2_async_register_subdev_sensor(&ov5645->sd); if (ret < 0) { - dev_err(dev, "could not register v4l2 device\n"); + dev_err_probe(dev, ret, "could not register v4l2 device\n"); goto err_pm_runtime; } @@ -1254,13 +1204,13 @@ static int ov5645_probe(struct i2c_client *client) err_pm_runtime: pm_runtime_disable(dev); pm_runtime_put_noidle(dev); + v4l2_subdev_cleanup(&ov5645->sd); power_down: ov5645_set_power_off(dev); free_entity: media_entity_cleanup(&ov5645->sd.entity); free_ctrl: v4l2_ctrl_handler_free(&ov5645->ctrls); - mutex_destroy(&ov5645->power_lock); return ret; } @@ -1271,13 +1221,13 @@ static void ov5645_remove(struct i2c_client *client) struct ov5645 *ov5645 = to_ov5645(sd); v4l2_async_unregister_subdev(&ov5645->sd); + v4l2_subdev_cleanup(sd); media_entity_cleanup(&ov5645->sd.entity); v4l2_ctrl_handler_free(&ov5645->ctrls); pm_runtime_disable(ov5645->dev); if (!pm_runtime_status_suspended(ov5645->dev)) ov5645_set_power_off(ov5645->dev); pm_runtime_set_suspended(ov5645->dev); - mutex_destroy(&ov5645->power_lock); } static const struct i2c_device_id ov5645_id[] = { diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index f051045d340f..c54bbc207189 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1879,7 +1879,7 @@ struct ov5670 { struct gpio_desc *pwdn_gpio; /* PWDNB pin. */ struct gpio_desc *reset_gpio; /* XSHUTDOWN pin. */ - /* To serialize asynchronus callbacks */ + /* To serialize asynchronous callbacks */ struct mutex mutex; /* True if the device has been identified */ diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index 2833b14ee139..c1081deffc2f 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -510,7 +510,7 @@ struct ov5675 { /* Current mode */ const struct ov5675_mode *cur_mode; - /* To serialize asynchronus callbacks */ + /* To serialize asynchronous callbacks */ struct mutex mutex; /* True if the device has been identified */ @@ -732,7 +732,7 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE: /* 4 least significant bits of expsoure are fractional part * val = val << 4 - * for ov5675, the unit of exposure is differnt from other + * for ov5675, the unit of exposure is different from other * OmniVision sensors, its exposure value is twice of the * register value, the exposure should be divided by 2 before * set register, e.g. val << 3. diff --git a/drivers/media/i2c/ov64a40.c b/drivers/media/i2c/ov64a40.c index 541bf74581d2..a5da4fe47e0b 100644 --- a/drivers/media/i2c/ov64a40.c +++ b/drivers/media/i2c/ov64a40.c @@ -18,7 +18,6 @@ #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-mediabus.h> #include <media/v4l2-subdev.h> @@ -3200,13 +3199,7 @@ static const struct v4l2_subdev_pad_ops ov64a40_pad_ops = { .get_selection = ov64a40_get_selection, }; -static const struct v4l2_subdev_core_ops ov64a40_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_ops ov64a40_subdev_ops = { - .core = &ov64a40_core_ops, .video = &ov64a40_video_ops, .pad = &ov64a40_pad_ops, }; @@ -3605,8 +3598,7 @@ static int ov64a40_probe(struct i2c_client *client) /* Initialize subdev */ ov64a40->sd.internal_ops = &ov64a40_internal_ops; - ov64a40->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE - | V4L2_SUBDEV_FL_HAS_EVENTS; + ov64a40->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ov64a40->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ov64a40->pad.flags = MEDIA_PAD_FL_SOURCE; diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 3b0fdb3c70c0..062e1023a411 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -269,7 +269,7 @@ #define AF_8x 0x08 /* Add frame when AGC reaches 8x gain */ #define AF_16x 0x0c /* Add frame when AGC reaches 16x gain */ /* AEC max step control */ -#define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */ +#define AEC_NO_LIMIT 0x01 /* 0 : AEC increase step has limit */ /* 1 : No limit to AEC increase step */ /* CLKRC */ /* Input clock divider register */ diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 0830676e5d5a..1f1c0de8e510 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -117,7 +117,7 @@ struct ov7740 { struct v4l2_ctrl *brightness; struct v4l2_ctrl *contrast; - struct mutex mutex; /* To serialize asynchronus callbacks */ + struct mutex mutex; /* To serialize asynchronous callbacks */ struct gpio_desc *resetb_gpio; struct gpio_desc *pwdn_gpio; diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index 3b94338f55ed..e6704d018248 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -1435,7 +1435,7 @@ struct ov8856 { /* Application specified mbus format */ u32 cur_mbus_index; - /* To serialize asynchronus callbacks */ + /* To serialize asynchronous callbacks */ struct mutex mutex; /* lanes index */ diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c index 326f50a5ab51..95f9ae794846 100644 --- a/drivers/media/i2c/ov8858.c +++ b/drivers/media/i2c/ov8858.c @@ -24,7 +24,6 @@ #include <media/v4l2-common.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-mediabus.h> #include <media/v4l2-subdev.h> @@ -1500,13 +1499,7 @@ static const struct v4l2_subdev_pad_ops ov8858_pad_ops = { .set_fmt = ov8858_set_fmt, }; -static const struct v4l2_subdev_core_ops ov8858_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_ops ov8858_subdev_ops = { - .core = &ov8858_core_ops, .video = &ov8858_video_ops, .pad = &ov8858_pad_ops, }; @@ -1917,7 +1910,7 @@ static int ov8858_probe(struct i2c_client *client) return ret; sd = &ov8858->subdev; - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov8858->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &ov8858->pad); diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 56df97c9886b..026ea34d6291 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -286,7 +286,7 @@ static const struct i2c_rv ov965x_init_regs[] = { { REG_COM5, 0x00 }, /* System clock options */ { REG_COM2, 0x01 }, /* Output drive, soft sleep mode */ { REG_COM10, 0x00 }, /* Slave mode, HREF vs HSYNC, signals negate */ - { REG_EDGE, 0xa6 }, /* Edge enhancement treshhold and factor */ + { REG_EDGE, 0xa6 }, /* Edge enhancement threshold and factor */ { REG_COM16, 0x02 }, /* Color matrix coeff double option */ { REG_COM17, 0x08 }, /* Single frame out, banding filter */ { 0x16, 0x06 }, diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index bf9e2adbff34..cae3aeefb616 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -335,7 +335,7 @@ struct ov9734 { /* Current mode */ const struct ov9734_mode *cur_mode; - /* To serialize asynchronus callbacks */ + /* To serialize asynchronous callbacks */ struct mutex mutex; }; diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index b947a55281f0..f08db3cfe076 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -14,6 +14,7 @@ #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include <linux/of_graph.h> #include <linux/regulator/consumer.h> #include <media/mipi-csi2.h> @@ -67,9 +68,6 @@ static const u32 mipid02_supported_fmt_codes[] = { MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YVYU8_1X16, MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_RGB565_1X16, MEDIA_BUS_FMT_BGR888_1X24, - MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, - MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8, MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_JPEG_1X8 }; @@ -100,6 +98,7 @@ struct mipid02_dev { /* remote source */ struct v4l2_async_notifier notifier; struct v4l2_subdev *s_subdev; + u16 s_subdev_pad_id; /* registers */ struct { u8 clk_lane_reg1; @@ -138,12 +137,6 @@ static int bpp_from_code(__u32 code) case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_VYUY8_1X16: case MEDIA_BUS_FMT_RGB565_1X16: - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YVYU8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_RGB565_2X8_LE: - case MEDIA_BUS_FMT_RGB565_2X8_BE: return 16; case MEDIA_BUS_FMT_BGR888_1X24: return 24; @@ -175,16 +168,10 @@ static u8 data_type_from_code(__u32 code) case MEDIA_BUS_FMT_YVYU8_1X16: case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_VYUY8_1X16: - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YVYU8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_VYUY8_2X8: return MIPI_CSI2_DT_YUV422_8B; case MEDIA_BUS_FMT_BGR888_1X24: return MIPI_CSI2_DT_RGB888; case MEDIA_BUS_FMT_RGB565_1X16: - case MEDIA_BUS_FMT_RGB565_2X8_LE: - case MEDIA_BUS_FMT_RGB565_2X8_BE: return MIPI_CSI2_DT_RGB565; default: return 0; @@ -248,8 +235,10 @@ static void mipid02_apply_reset(struct mipid02_dev *bridge) usleep_range(5000, 10000); } -static int mipid02_set_power_on(struct mipid02_dev *bridge) +static int mipid02_set_power_on(struct device *dev) { + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct mipid02_dev *bridge = to_mipid02_dev(sd); struct i2c_client *client = bridge->i2c_client; int ret; @@ -282,10 +271,15 @@ xclk_off: return ret; } -static void mipid02_set_power_off(struct mipid02_dev *bridge) +static int mipid02_set_power_off(struct device *dev) { + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct mipid02_dev *bridge = to_mipid02_dev(sd); + regulator_bulk_disable(MIPID02_NUM_SUPPLIES, bridge->supplies); clk_disable_unprepare(bridge->xclk); + + return 0; } static int mipid02_detect(struct mipid02_dev *bridge) @@ -447,15 +441,19 @@ static int mipid02_configure_from_code(struct mipid02_dev *bridge, return 0; } -static int mipid02_stream_disable(struct mipid02_dev *bridge) +static int mipid02_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { + struct mipid02_dev *bridge = to_mipid02_dev(sd); struct i2c_client *client = bridge->i2c_client; int ret = -EINVAL; if (!bridge->s_subdev) goto error; - ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 0); + ret = v4l2_subdev_disable_streams(bridge->s_subdev, + bridge->s_subdev_pad_id, BIT(0)); if (ret) goto error; @@ -465,6 +463,10 @@ static int mipid02_stream_disable(struct mipid02_dev *bridge) cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1, 0, &ret); if (ret) goto error; + + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + error: if (ret) dev_err(&client->dev, "failed to stream off %d", ret); @@ -472,33 +474,36 @@ error: return ret; } -static int mipid02_stream_enable(struct mipid02_dev *bridge) +static int mipid02_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { + struct mipid02_dev *bridge = to_mipid02_dev(sd); struct i2c_client *client = bridge->i2c_client; - struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *fmt; int ret = -EINVAL; if (!bridge->s_subdev) - goto error; + return ret; memset(&bridge->r, 0, sizeof(bridge->r)); - state = v4l2_subdev_lock_and_get_active_state(&bridge->sd); fmt = v4l2_subdev_state_get_format(state, MIPID02_SINK_0); /* build registers content */ ret = mipid02_configure_from_rx(bridge, fmt); if (ret) - goto error; + return ret; ret = mipid02_configure_from_tx(bridge); if (ret) - goto error; + return ret; ret = mipid02_configure_from_code(bridge, fmt); if (ret) - goto error; + return ret; - v4l2_subdev_unlock_state(state); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret < 0) + return ret; /* write mipi registers */ cci_write(bridge->regmap, MIPID02_CLK_LANE_REG1, @@ -524,33 +529,20 @@ static int mipid02_stream_enable(struct mipid02_dev *bridge) if (ret) goto error; - ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 1); + ret = v4l2_subdev_enable_streams(bridge->s_subdev, + bridge->s_subdev_pad_id, BIT(0)); if (ret) goto error; return 0; error: - dev_err(&client->dev, "failed to stream on %d", ret); - mipid02_stream_disable(bridge); - - return ret; -} - -static int mipid02_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct mipid02_dev *bridge = to_mipid02_dev(sd); - struct i2c_client *client = bridge->i2c_client; - int ret = 0; - - dev_dbg(&client->dev, "%s : requested %d\n", __func__, enable); - - ret = enable ? mipid02_stream_enable(bridge) : - mipid02_stream_disable(bridge); - if (ret) - dev_err(&client->dev, "failed to stream %s (%d)\n", - enable ? "enable" : "disable", ret); + cci_write(bridge->regmap, MIPID02_CLK_LANE_REG1, 0, &ret); + cci_write(bridge->regmap, MIPID02_DATA_LANE0_REG1, 0, &ret); + cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1, 0, &ret); + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); return ret; } @@ -640,13 +632,15 @@ static int mipid02_set_fmt(struct v4l2_subdev *sd, } static const struct v4l2_subdev_video_ops mipid02_video_ops = { - .s_stream = mipid02_s_stream, + .s_stream = v4l2_subdev_s_stream_helper, }; static const struct v4l2_subdev_pad_ops mipid02_pad_ops = { .enum_mbus_code = mipid02_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = mipid02_set_fmt, + .enable_streams = mipid02_enable_streams, + .disable_streams = mipid02_disable_streams, }; static const struct v4l2_subdev_ops mipid02_subdev_ops = { @@ -692,6 +686,7 @@ static int mipid02_async_bound(struct v4l2_async_notifier *notifier, } bridge->s_subdev = s_subdev; + bridge->s_subdev_pad_id = source_pad; return 0; } @@ -875,7 +870,7 @@ static int mipid02_probe(struct i2c_client *client) } /* enable clock, power and reset device if available */ - ret = mipid02_set_power_on(bridge); + ret = mipid02_set_power_on(&client->dev); if (ret) goto entity_cleanup; @@ -897,6 +892,15 @@ static int mipid02_probe(struct i2c_client *client) goto power_off; } + /* Enable runtime PM and turn off the device */ + pm_runtime_set_active(dev); + pm_runtime_get_noresume(&client->dev); + pm_runtime_enable(dev); + + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + ret = v4l2_async_register_subdev(&bridge->sd); if (ret < 0) { dev_err(&client->dev, "v4l2_async_register_subdev failed %d", @@ -911,8 +915,10 @@ static int mipid02_probe(struct i2c_client *client) unregister_notifier: v4l2_async_nf_unregister(&bridge->notifier); v4l2_async_nf_cleanup(&bridge->notifier); + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); power_off: - mipid02_set_power_off(bridge); + mipid02_set_power_off(&client->dev); entity_cleanup: media_entity_cleanup(&bridge->sd.entity); @@ -927,7 +933,11 @@ static void mipid02_remove(struct i2c_client *client) v4l2_async_nf_unregister(&bridge->notifier); v4l2_async_nf_cleanup(&bridge->notifier); v4l2_async_unregister_subdev(&bridge->sd); - mipid02_set_power_off(bridge); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + mipid02_set_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); media_entity_cleanup(&bridge->sd.entity); } @@ -937,10 +947,15 @@ static const struct of_device_id mipid02_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, mipid02_dt_ids); +static const struct dev_pm_ops mipid02_pm_ops = { + RUNTIME_PM_OPS(mipid02_set_power_off, mipid02_set_power_on, NULL) +}; + static struct i2c_driver mipid02_i2c_driver = { .driver = { .name = "st-mipid02", .of_match_table = mipid02_dt_ids, + .pm = pm_ptr(&mipid02_pm_ops), }, .probe = mipid02_probe, .remove = mipid02_remove, diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 65d58ddf0287..c50d4e85dfd1 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -87,6 +87,10 @@ struct tc358743_state { struct timer_list timer; struct work_struct work_i2c_poll; + /* debugfs */ + struct dentry *debugfs_dir; + struct v4l2_debugfs_if *infoframes; + /* edid */ u8 edid_blocks_written; @@ -430,12 +434,35 @@ static void tc358743_erase_bksv(struct v4l2_subdev *sd) /* --------------- AVI infoframe --------------- */ +static ssize_t +tc358743_debugfs_if_read(u32 type, void *priv, struct file *filp, + char __user *ubuf, size_t count, loff_t *ppos) +{ + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + struct v4l2_subdev *sd = priv; + int len; + + if (!is_hdmi(sd)) + return 0; + + if (type != V4L2_DEBUGFS_IF_AVI) + return 0; + + i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_16BYTE - PK_AVI_0HEAD + 1); + len = buf[2] + 4; + if (len > V4L2_DEBUGFS_IF_MAX_LEN) + len = -ENOENT; + if (len > 0) + len = simple_read_from_buffer(ubuf, count, ppos, buf, len); + return len < 0 ? 0 : len; +} + static void print_avi_infoframe(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct device *dev = &client->dev; union hdmi_infoframe frame; - u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; + u8 buffer[HDMI_INFOFRAME_SIZE(AVI)] = {}; if (!is_hdmi(sd)) { v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); @@ -2161,6 +2188,11 @@ static int tc358743_probe(struct i2c_client *client) if (err < 0) goto err_work_queues; + state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root()); + state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir, + V4L2_DEBUGFS_IF_AVI, sd, + tc358743_debugfs_if_read); + v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); @@ -2168,8 +2200,10 @@ static int tc358743_probe(struct i2c_client *client) err_work_queues: cec_unregister_adapter(state->cec_adap); - if (!state->i2c_client->irq) + if (!state->i2c_client->irq) { + del_timer(&state->timer); flush_work(&state->work_i2c_poll); + } cancel_delayed_work(&state->delayed_work_enable_hotplug); mutex_destroy(&state->confctl_mutex); err_hdl: @@ -2188,6 +2222,8 @@ static void tc358743_remove(struct i2c_client *client) flush_work(&state->work_i2c_poll); } cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); + v4l2_debugfs_if_free(state->infoframes); + debugfs_remove_recursive(state->debugfs_dir); cec_unregister_adapter(state->cec_adap); v4l2_async_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); diff --git a/drivers/media/i2c/thp7312.c b/drivers/media/i2c/thp7312.c index c77440ff098c..8852c56431fe 100644 --- a/drivers/media/i2c/thp7312.c +++ b/drivers/media/i2c/thp7312.c @@ -27,7 +27,6 @@ #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> @@ -879,8 +878,6 @@ static int thp7312_init_state(struct v4l2_subdev *sd, static const struct v4l2_subdev_core_ops thp7312_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops thp7312_video_ops = { @@ -2127,7 +2124,7 @@ static int thp7312_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&thp7312->sd, client, &thp7312_subdev_ops); thp7312->sd.internal_ops = &thp7312_internal_ops; - thp7312->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + thp7312->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; thp7312->pad.flags = MEDIA_PAD_FL_SOURCE; thp7312->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index 7526fabc7ee4..b7cedc5b3e8e 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -7,7 +7,7 @@ * Author: Chaithrika U S <chaithrika@ti.com> * * Contributors: - * Hans Verkuil <hans.verkuil@cisco.com> + * Hans Verkuil <hansverk@cisco.com> * Lad, Prabhakar <prabhakar.lad@ti.com> * Martin Bugge <marbugge@cisco.com> * diff --git a/drivers/media/i2c/vgxy61.c b/drivers/media/i2c/vgxy61.c index 409d2d4ffb4b..d77468c8587b 100644 --- a/drivers/media/i2c/vgxy61.c +++ b/drivers/media/i2c/vgxy61.c @@ -1617,7 +1617,7 @@ static int vgxy61_detect(struct vgxy61_dev *sensor) ret = cci_read(sensor->regmap, VGXY61_REG_NVM, &st, NULL); if (ret < 0) - return st; + return ret; if (st != VGXY61_NVM_OK) dev_warn(&client->dev, "Bad nvm state got %u\n", (u8)st); diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 56dbe07a1c99..036a6375627a 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -566,8 +566,6 @@ static const struct vb2_ops video_i2c_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int video_i2c_querycap(struct file *file, void *priv, @@ -798,13 +796,13 @@ static int video_i2c_probe(struct i2c_client *client) queue->min_queued_buffers = 1; queue->ops = &video_i2c_video_qops; queue->mem_ops = &vb2_vmalloc_memops; + queue->lock = &data->queue_lock; ret = vb2_queue_init(queue); if (ret < 0) goto error_unregister_device; data->vdev.queue = queue; - data->vdev.queue->lock = &data->queue_lock; snprintf(data->vdev.name, sizeof(data->vdev.name), "I2C %d-%d Transport Video", diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 96dd0f6ccd0d..045590905582 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -768,10 +768,10 @@ done: return ret; } -__must_check int __media_pipeline_start(struct media_pad *pad, +__must_check int __media_pipeline_start(struct media_pad *origin, struct media_pipeline *pipe) { - struct media_device *mdev = pad->graph_obj.mdev; + struct media_device *mdev = origin->graph_obj.mdev; struct media_pipeline_pad *err_ppad; struct media_pipeline_pad *ppad; int ret; @@ -782,7 +782,7 @@ __must_check int __media_pipeline_start(struct media_pad *pad, * If the pad is already part of a pipeline, that pipeline must be the * same as the pipe given to media_pipeline_start(). */ - if (WARN_ON(pad->pipe && pad->pipe != pipe)) + if (WARN_ON(origin->pipe && origin->pipe != pipe)) return -EINVAL; /* @@ -799,7 +799,7 @@ __must_check int __media_pipeline_start(struct media_pad *pad, * with media_pipeline_pad instances for each pad found during graph * walk. */ - ret = media_pipeline_populate(pipe, pad); + ret = media_pipeline_populate(pipe, origin); if (ret) return ret; @@ -914,14 +914,14 @@ error: } EXPORT_SYMBOL_GPL(__media_pipeline_start); -__must_check int media_pipeline_start(struct media_pad *pad, +__must_check int media_pipeline_start(struct media_pad *origin, struct media_pipeline *pipe) { - struct media_device *mdev = pad->graph_obj.mdev; + struct media_device *mdev = origin->graph_obj.mdev; int ret; mutex_lock(&mdev->graph_mutex); - ret = __media_pipeline_start(pad, pipe); + ret = __media_pipeline_start(origin, pipe); mutex_unlock(&mdev->graph_mutex); return ret; } diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c index e064914c476e..5edfc2791ce7 100644 --- a/drivers/media/mc/mc-request.c +++ b/drivers/media/mc/mc-request.c @@ -6,7 +6,7 @@ * Copyright (C) 2018 Intel Corporation * Copyright (C) 2018 Google, Inc. * - * Author: Hans Verkuil <hans.verkuil@cisco.com> + * Author: Hans Verkuil <hansverk@cisco.com> * Author: Sakari Ailus <sakari.ailus@linux.intel.com> */ @@ -246,22 +246,21 @@ static const struct file_operations request_fops = { struct media_request * media_request_get_by_fd(struct media_device *mdev, int request_fd) { - struct fd f; struct media_request *req; if (!mdev || !mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue) return ERR_PTR(-EBADR); - f = fdget(request_fd); - if (!fd_file(f)) - goto err_no_req_fd; + CLASS(fd, f)(request_fd); + if (fd_empty(f)) + goto err; if (fd_file(f)->f_op != &request_fops) - goto err_fput; + goto err; req = fd_file(f)->private_data; if (req->mdev != mdev) - goto err_fput; + goto err; /* * Note: as long as someone has an open filehandle of the request, @@ -272,14 +271,9 @@ media_request_get_by_fd(struct media_device *mdev, int request_fd) * before media_request_get() is called. */ media_request_get(req); - fdput(f); - return req; -err_fput: - fdput(f); - -err_no_req_fd: +err: dev_dbg(mdev->dev, "cannot find request_fd %d\n", request_fd); return ERR_PTR(-EINVAL); } diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 511f013cc338..2782832f5eb8 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1584,8 +1584,6 @@ static const struct vb2_ops bttv_video_qops = { .buf_cleanup = buf_cleanup, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static void radio_enable(struct bttv *btv) diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c index e489a3acb4b9..a71440611e46 100644 --- a/drivers/media/pci/bt8xx/bttv-vbi.c +++ b/drivers/media/pci/bt8xx/bttv-vbi.c @@ -170,8 +170,6 @@ const struct vb2_ops bttv_vbi_qops = { .buf_cleanup = buf_cleanup_vbi, .start_streaming = start_streaming_vbi, .stop_streaming = stop_streaming_vbi, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 6e1a0614e6d0..39e25cc53edb 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -44,7 +44,7 @@ module_param_named(ignore_err, cobalt_ignore_err, int, 0644); MODULE_PARM_DESC(ignore_err, "If set then ignore missing i2c adapters/receivers. Default: 0\n"); -MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com> & Morten Hestnes"); +MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com> & Morten Hestnes"); MODULE_DESCRIPTION("cobalt driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index d4d7b264c965..ae82427e3479 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -424,8 +424,6 @@ static const struct vb2_ops cobalt_qops = { .buf_queue = cobalt_buf_queue, .start_streaming = cobalt_start_streaming, .stop_streaming = cobalt_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* V4L2 ioctls */ diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index acc6418db425..42d6f7b90ede 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -229,8 +229,6 @@ static const struct vb2_ops cx18_vb2_qops = { .buf_prepare = cx18_buf_prepare, .start_streaming = cx18_start_streaming, .stop_streaming = cx18_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int cx18_stream_init(struct cx18 *cx, int type) diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index fdb96f80c036..219937a153b3 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1210,8 +1210,6 @@ static const struct vb2_ops cx23885_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = cx23885_start_streaming, .stop_streaming = cx23885_stop_streaming, }; diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 3d01cdc4c7f3..05a7859cbe57 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -170,8 +170,6 @@ static const struct vb2_ops dvb_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = cx23885_start_streaming, .stop_streaming = cx23885_stop_streaming, }; diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index 4bdd2bea3713..40817cc52fc1 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -249,8 +249,6 @@ const struct vb2_ops cx23885_vbi_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = cx23885_start_streaming, .stop_streaming = cx23885_stop_streaming, }; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 7d4a409c433e..35d58328db56 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -519,8 +519,6 @@ static const struct vb2_ops cx23885_video_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = cx23885_start_streaming, .stop_streaming = cx23885_stop_streaming, }; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 0bee4b728a60..84aa1209e717 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -295,8 +295,6 @@ static const struct vb2_ops cx25821_video_qops = { .buf_prepare = cx25821_buffer_prepare, .buf_finish = cx25821_buffer_finish, .buf_queue = cx25821_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = cx25821_start_streaming, .stop_streaming = cx25821_stop_streaming, }; diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index d55df8fdb3b6..13b8cc46835b 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -781,8 +781,6 @@ static const struct vb2_ops blackbird_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index b33b3a5e32ec..c9cfceed2f1b 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -152,8 +152,6 @@ static const struct vb2_ops dvb_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c index 469aeaa725ad..e3e379e6f620 100644 --- a/drivers/media/pci/cx88/cx88-vbi.c +++ b/drivers/media/pci/cx88/cx88-vbi.c @@ -228,8 +228,6 @@ const struct vb2_ops cx8800_vbi_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index cefb6b25e921..0c87327689d3 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -562,8 +562,6 @@ static const struct vb2_ops cx8800_video_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index dff853e73fdc..7bddcbba4cf1 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -222,8 +222,6 @@ static void dt3155_buf_queue(struct vb2_buffer *vb) static const struct vb2_ops q_ops = { .queue_setup = dt3155_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = dt3155_buf_prepare, .start_streaming = dt3155_start_streaming, .stop_streaming = dt3155_stop_streaming, diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 81ec8630453b..4e98f432ed55 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1045,8 +1045,6 @@ static const struct vb2_ops cio2_vb2_ops = { .queue_setup = cio2_vb2_queue_setup, .start_streaming = cio2_vb2_start_streaming, .stop_streaming = cio2_vb2_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /**************** V4L2 interface ****************/ diff --git a/drivers/media/pci/intel/ipu6/Kconfig b/drivers/media/pci/intel/ipu6/Kconfig index 49e4fb696573..1129e2beb4be 100644 --- a/drivers/media/pci/intel/ipu6/Kconfig +++ b/drivers/media/pci/intel/ipu6/Kconfig @@ -2,19 +2,13 @@ config VIDEO_INTEL_IPU6 tristate "Intel IPU6 driver" depends on ACPI || COMPILE_TEST depends on VIDEO_DEV - depends on X86 && X86_64 && HAS_DMA + depends on X86 && HAS_DMA depends on IPU_BRIDGE || !IPU_BRIDGE - # - # This driver incorrectly tries to override the dma_ops. It should - # never have done that, but for now keep it working on architectures - # that use dma ops - # - depends on ARCH_HAS_DMA_OPS select AUXILIARY_BUS select IOMMU_IOVA select VIDEO_V4L2_SUBDEV_API select MEDIA_CONTROLLER - select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_DMA_SG select V4L2_FWNODE help This is the 6th Gen Intel Image Processing Unit, found in Intel SoCs diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.c b/drivers/media/pci/intel/ipu6/ipu6-bus.c index 149ec098cdbf..37d88ddb6ee7 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-bus.c +++ b/drivers/media/pci/intel/ipu6/ipu6-bus.c @@ -94,8 +94,6 @@ ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent, if (!adev) return ERR_PTR(-ENOMEM); - adev->dma_mask = DMA_BIT_MASK(isp->secure_mode ? IPU6_MMU_ADDR_BITS : - IPU6_MMU_ADDR_BITS_NON_SECURE); adev->isp = isp; adev->ctrl = ctrl; adev->pdata = pdata; @@ -106,10 +104,6 @@ ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent, auxdev->dev.parent = parent; auxdev->dev.release = ipu6_bus_release; - auxdev->dev.dma_ops = &ipu6_dma_ops; - auxdev->dev.dma_mask = &adev->dma_mask; - auxdev->dev.dma_parms = pdev->dev.dma_parms; - auxdev->dev.coherent_dma_mask = adev->dma_mask; ret = auxiliary_device_init(auxdev); if (ret < 0) { diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c index e47f84c30e10..277e101da137 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c +++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c @@ -24,6 +24,7 @@ #include "ipu6.h" #include "ipu6-bus.h" +#include "ipu6-dma.h" #include "ipu6-buttress.h" #include "ipu6-platform-buttress-regs.h" @@ -214,20 +215,17 @@ static void ipu6_buttress_ipc_recv(struct ipu6_device *isp, } static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp, - enum ipu6_buttress_ipc_domain ipc_domain, struct ipu6_ipc_buttress_bulk_msg *msgs, u32 size) { unsigned long tx_timeout_jiffies, rx_timeout_jiffies; unsigned int i, retry = BUTTRESS_IPC_CMD_SEND_RETRY; struct ipu6_buttress *b = &isp->buttress; - struct ipu6_buttress_ipc *ipc; + struct ipu6_buttress_ipc *ipc = &b->cse; u32 val; int ret; int tout; - ipc = ipc_domain == IPU6_BUTTRESS_IPC_CSE ? &b->cse : &b->ish; - mutex_lock(&b->ipc_mutex); ret = ipu6_buttress_ipc_validity_open(isp, ipc); @@ -305,7 +303,6 @@ out: static int ipu6_buttress_ipc_send(struct ipu6_device *isp, - enum ipu6_buttress_ipc_domain ipc_domain, u32 ipc_msg, u32 size, bool require_resp, u32 expected_resp) { @@ -316,7 +313,7 @@ ipu6_buttress_ipc_send(struct ipu6_device *isp, .expected_resp = expected_resp, }; - return ipu6_buttress_ipc_send_bulk(isp, ipc_domain, &msg, 1); + return ipu6_buttress_ipc_send_bulk(isp, &msg, 1); } static irqreturn_t ipu6_buttress_call_isr(struct ipu6_bus_device *adev) @@ -345,12 +342,16 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr) u32 disable_irqs = 0; u32 irq_status; u32 i, count = 0; + int active; - pm_runtime_get_noresume(&isp->pdev->dev); + active = pm_runtime_get_if_active(&isp->pdev->dev); + if (!active) + return IRQ_NONE; irq_status = readl(isp->base + reg_irq_sts); - if (!irq_status) { - pm_runtime_put_noidle(&isp->pdev->dev); + if (irq_status == 0 || WARN_ON_ONCE(irq_status == 0xffffffffu)) { + if (active > 0) + pm_runtime_put_noidle(&isp->pdev->dev); return IRQ_NONE; } @@ -381,25 +382,12 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr) complete(&b->cse.recv_complete); } - if (irq_status & BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING) { - dev_dbg(&isp->pdev->dev, - "BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING\n"); - ipu6_buttress_ipc_recv(isp, &b->ish, &b->ish.recv_data); - complete(&b->ish.recv_complete); - } - if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE) { dev_dbg(&isp->pdev->dev, "BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n"); complete(&b->cse.send_complete); } - if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH) { - dev_dbg(&isp->pdev->dev, - "BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n"); - complete(&b->ish.send_complete); - } - if (irq_status & BUTTRESS_ISR_SAI_VIOLATION && ipu6_buttress_get_secure_mode(isp)) dev_err(&isp->pdev->dev, @@ -426,7 +414,8 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr) writel(BUTTRESS_IRQS & ~disable_irqs, isp->base + BUTTRESS_REG_ISR_ENABLE); - pm_runtime_put(&isp->pdev->dev); + if (active > 0) + pm_runtime_put(&isp->pdev->dev); return ret; } @@ -553,6 +542,7 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys, const struct firmware *fw, struct sg_table *sgt) { bool is_vmalloc = is_vmalloc_addr(fw->data); + struct pci_dev *pdev = sys->isp->pdev; struct page **pages; const void *addr; unsigned long n_pages; @@ -562,7 +552,7 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys, if (!is_vmalloc && !virt_addr_valid(fw->data)) return -EDOM; - n_pages = PHYS_PFN(PAGE_ALIGN(fw->size)); + n_pages = PFN_UP(fw->size); pages = kmalloc_array(n_pages, sizeof(*pages), GFP_KERNEL); if (!pages) @@ -588,14 +578,20 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys, goto out; } - ret = dma_map_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0); - if (ret < 0) { - ret = -ENOMEM; + ret = dma_map_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0); + if (ret) { + sg_free_table(sgt); + goto out; + } + + ret = ipu6_dma_map_sgtable(sys, sgt, DMA_TO_DEVICE, 0); + if (ret) { + dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0); sg_free_table(sgt); goto out; } - dma_sync_sgtable_for_device(&sys->auxdev.dev, sgt, DMA_TO_DEVICE); + ipu6_dma_sync_sgtable(sys, sgt); out: kfree(pages); @@ -607,7 +603,10 @@ EXPORT_SYMBOL_NS_GPL(ipu6_buttress_map_fw_image, INTEL_IPU6); void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys, struct sg_table *sgt) { - dma_unmap_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0); + struct pci_dev *pdev = sys->isp->pdev; + + ipu6_dma_unmap_sgtable(sys, sgt, DMA_TO_DEVICE, 0); + dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0); sg_free_table(sgt); } EXPORT_SYMBOL_NS_GPL(ipu6_buttress_unmap_fw_image, INTEL_IPU6); @@ -650,7 +649,7 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp) */ dev_info(&isp->pdev->dev, "Sending BOOT_LOAD to CSE\n"); - ret = ipu6_buttress_ipc_send(isp, IPU6_BUTTRESS_IPC_CSE, + ret = ipu6_buttress_ipc_send(isp, BUTTRESS_IU2CSEDATA0_IPC_BOOT_LOAD, 1, true, BUTTRESS_CSE2IUDATA0_IPC_BOOT_LOAD_DONE); @@ -692,7 +691,7 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp) * IU2CSEDB.IU2CSECMD and set IU2CSEDB.IU2CSEBUSY as */ dev_info(&isp->pdev->dev, "Sending AUTHENTICATE_RUN to CSE\n"); - ret = ipu6_buttress_ipc_send(isp, IPU6_BUTTRESS_IPC_CSE, + ret = ipu6_buttress_ipc_send(isp, BUTTRESS_IU2CSEDATA0_IPC_AUTH_RUN, 1, true, BUTTRESS_CSE2IUDATA0_IPC_AUTH_RUN_DONE); @@ -833,9 +832,7 @@ int ipu6_buttress_init(struct ipu6_device *isp) mutex_init(&b->auth_mutex); mutex_init(&b->cons_mutex); mutex_init(&b->ipc_mutex); - init_completion(&b->ish.send_complete); init_completion(&b->cse.send_complete); - init_completion(&b->ish.recv_complete); init_completion(&b->cse.recv_complete); b->cse.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK; @@ -847,8 +844,6 @@ int ipu6_buttress_init(struct ipu6_device *isp) b->cse.data0_in = BUTTRESS_REG_CSE2IUDATA0; b->cse.data0_out = BUTTRESS_REG_IU2CSEDATA0; - /* no ISH on IPU6 */ - memset(&b->ish, 0, sizeof(b->ish)); INIT_LIST_HEAD(&b->constraints); isp->secure_mode = ipu6_buttress_get_secure_mode(isp); diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h index 9b6f56958be7..482978c2a09d 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h +++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h @@ -46,18 +46,12 @@ struct ipu6_buttress_ipc { struct ipu6_buttress { struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex; struct ipu6_buttress_ipc cse; - struct ipu6_buttress_ipc ish; struct list_head constraints; u32 wdt_cached_value; bool force_suspend; u32 ref_clk; }; -enum ipu6_buttress_ipc_domain { - IPU6_BUTTRESS_IPC_CSE, - IPU6_BUTTRESS_IPC_ISH, -}; - struct ipu6_ipc_buttress_bulk_msg { u32 cmd; u32 expected_resp; diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.c b/drivers/media/pci/intel/ipu6/ipu6-cpd.c index 715b21ab4b8e..55ffd988ae4f 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-cpd.c +++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.c @@ -15,6 +15,7 @@ #include "ipu6.h" #include "ipu6-bus.h" #include "ipu6-cpd.h" +#include "ipu6-dma.h" /* 15 entries + header*/ #define MAX_PKG_DIR_ENT_CNT 16 @@ -43,9 +44,9 @@ * 63:56 55 54:48 47:32 31:24 23:0 * Rsvd Rsvd Type Version Rsvd Size */ -#define PKG_DIR_SIZE_MASK GENMASK(23, 0) -#define PKG_DIR_VERSION_MASK GENMASK(47, 32) -#define PKG_DIR_TYPE_MASK GENMASK(54, 48) +#define PKG_DIR_SIZE_MASK GENMASK_ULL(23, 0) +#define PKG_DIR_VERSION_MASK GENMASK_ULL(47, 32) +#define PKG_DIR_TYPE_MASK GENMASK_ULL(54, 48) static inline const struct ipu6_cpd_ent *ipu6_cpd_get_entry(const void *cpd, u8 idx) @@ -162,7 +163,6 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src) { dma_addr_t dma_addr_src = sg_dma_address(adev->fw_sgt.sgl); const struct ipu6_cpd_ent *ent, *man_ent, *met_ent; - struct device *dev = &adev->auxdev.dev; struct ipu6_device *isp = adev->isp; unsigned int man_sz, met_sz; void *pkg_dir_pos; @@ -175,8 +175,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src) met_sz = met_ent->len; adev->pkg_dir_size = PKG_DIR_SIZE + man_sz + met_sz; - adev->pkg_dir = dma_alloc_attrs(dev, adev->pkg_dir_size, - &adev->pkg_dir_dma_addr, GFP_KERNEL, 0); + adev->pkg_dir = ipu6_dma_alloc(adev, adev->pkg_dir_size, + &adev->pkg_dir_dma_addr, GFP_KERNEL, 0); if (!adev->pkg_dir) return -ENOMEM; @@ -198,8 +198,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src) met_ent->len); if (ret) { dev_err(&isp->pdev->dev, "Failed to parse module data\n"); - dma_free_attrs(dev, adev->pkg_dir_size, - adev->pkg_dir, adev->pkg_dir_dma_addr, 0); + ipu6_dma_free(adev, adev->pkg_dir_size, + adev->pkg_dir, adev->pkg_dir_dma_addr, 0); return ret; } @@ -211,8 +211,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src) pkg_dir_pos += man_sz; memcpy(pkg_dir_pos, src + met_ent->offset, met_sz); - dma_sync_single_range_for_device(dev, adev->pkg_dir_dma_addr, - 0, adev->pkg_dir_size, DMA_TO_DEVICE); + ipu6_dma_sync_single(adev, adev->pkg_dir_dma_addr, + adev->pkg_dir_size); return 0; } @@ -220,8 +220,8 @@ EXPORT_SYMBOL_NS_GPL(ipu6_cpd_create_pkg_dir, INTEL_IPU6); void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev) { - dma_free_attrs(&adev->auxdev.dev, adev->pkg_dir_size, adev->pkg_dir, - adev->pkg_dir_dma_addr, 0); + ipu6_dma_free(adev, adev->pkg_dir_size, adev->pkg_dir, + adev->pkg_dir_dma_addr, 0); } EXPORT_SYMBOL_NS_GPL(ipu6_cpd_free_pkg_dir, INTEL_IPU6); diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.c b/drivers/media/pci/intel/ipu6/ipu6-dma.c index 92530a1cc90f..287b77a6aeab 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-dma.c +++ b/drivers/media/pci/intel/ipu6/ipu6-dma.c @@ -39,8 +39,7 @@ static struct vm_info *get_vm_info(struct ipu6_mmu *mmu, dma_addr_t iova) return NULL; } -static void __dma_clear_buffer(struct page *page, size_t size, - unsigned long attrs) +static void __clear_buffer(struct page *page, size_t size, unsigned long attrs) { void *ptr; @@ -56,8 +55,7 @@ static void __dma_clear_buffer(struct page *page, size_t size, clflush_cache_range(ptr, size); } -static struct page **__dma_alloc_buffer(struct device *dev, size_t size, - gfp_t gfp, unsigned long attrs) +static struct page **__alloc_buffer(size_t size, gfp_t gfp, unsigned long attrs) { int count = PHYS_PFN(size); int array_size = count * sizeof(struct page *); @@ -86,7 +84,7 @@ static struct page **__dma_alloc_buffer(struct device *dev, size_t size, pages[i + j] = pages[i] + j; } - __dma_clear_buffer(pages[i], PAGE_SIZE << order, attrs); + __clear_buffer(pages[i], PAGE_SIZE << order, attrs); i += 1 << order; count -= 1 << order; } @@ -100,29 +98,26 @@ error: return NULL; } -static void __dma_free_buffer(struct device *dev, struct page **pages, - size_t size, unsigned long attrs) +static void __free_buffer(struct page **pages, size_t size, unsigned long attrs) { int count = PHYS_PFN(size); unsigned int i; for (i = 0; i < count && pages[i]; i++) { - __dma_clear_buffer(pages[i], PAGE_SIZE, attrs); + __clear_buffer(pages[i], PAGE_SIZE, attrs); __free_pages(pages[i], 0); } kvfree(pages); } -static void ipu6_dma_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, - size_t size, - enum dma_data_direction dir) +void ipu6_dma_sync_single(struct ipu6_bus_device *sys, dma_addr_t dma_handle, + size_t size) { void *vaddr; u32 offset; struct vm_info *info; - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; + struct ipu6_mmu *mmu = sys->mmu; info = get_vm_info(mmu, dma_handle); if (WARN_ON(!info)) @@ -135,25 +130,33 @@ static void ipu6_dma_sync_single_for_cpu(struct device *dev, vaddr = info->vaddr + offset; clflush_cache_range(vaddr, size); } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_single, INTEL_IPU6); -static void ipu6_dma_sync_sg_for_cpu(struct device *dev, - struct scatterlist *sglist, - int nents, enum dma_data_direction dir) +void ipu6_dma_sync_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents) { struct scatterlist *sg; int i; for_each_sg(sglist, sg, nents, i) - clflush_cache_range(page_to_virt(sg_page(sg)), sg->length); + clflush_cache_range(sg_virt(sg), sg->length); } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_sg, INTEL_IPU6); -static void *ipu6_dma_alloc(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp, - unsigned long attrs) +void ipu6_dma_sync_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt) { - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; - struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev; + ipu6_dma_sync_sg(sys, sgt->sgl, sgt->orig_nents); +} +EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_sgtable, INTEL_IPU6); + +void *ipu6_dma_alloc(struct ipu6_bus_device *sys, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, + unsigned long attrs) +{ + struct device *dev = &sys->auxdev.dev; + struct pci_dev *pdev = sys->isp->pdev; dma_addr_t pci_dma_addr, ipu6_iova; + struct ipu6_mmu *mmu = sys->mmu; struct vm_info *info; unsigned long count; struct page **pages; @@ -173,7 +176,7 @@ static void *ipu6_dma_alloc(struct device *dev, size_t size, if (!iova) goto out_kfree; - pages = __dma_alloc_buffer(dev, size, gfp, attrs); + pages = __alloc_buffer(size, gfp, attrs); if (!pages) goto out_free_iova; @@ -227,7 +230,7 @@ out_unmap: ipu6_mmu_unmap(mmu->dmap->mmu_info, ipu6_iova, PAGE_SIZE); } - __dma_free_buffer(dev, pages, size, attrs); + __free_buffer(pages, size, attrs); out_free_iova: __free_iova(&mmu->dmap->iovad, iova); @@ -236,13 +239,13 @@ out_kfree: return NULL; } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_alloc, INTEL_IPU6); -static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle, - unsigned long attrs) +void ipu6_dma_free(struct ipu6_bus_device *sys, size_t size, void *vaddr, + dma_addr_t dma_handle, unsigned long attrs) { - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; - struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev; + struct ipu6_mmu *mmu = sys->mmu; + struct pci_dev *pdev = sys->isp->pdev; struct iova *iova = find_iova(&mmu->dmap->iovad, PHYS_PFN(dma_handle)); dma_addr_t pci_dma_addr, ipu6_iova; struct vm_info *info; @@ -281,7 +284,7 @@ static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr, ipu6_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo), PFN_PHYS(iova_size(iova))); - __dma_free_buffer(dev, pages, size, attrs); + __free_buffer(pages, size, attrs); mmu->tlb_invalidate(mmu); @@ -289,13 +292,14 @@ static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr, kfree(info); } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_free, INTEL_IPU6); -static int ipu6_dma_mmap(struct device *dev, struct vm_area_struct *vma, - void *addr, dma_addr_t iova, size_t size, - unsigned long attrs) +int ipu6_dma_mmap(struct ipu6_bus_device *sys, struct vm_area_struct *vma, + void *addr, dma_addr_t iova, size_t size, + unsigned long attrs) { - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; - size_t count = PHYS_PFN(PAGE_ALIGN(size)); + struct ipu6_mmu *mmu = sys->mmu; + size_t count = PFN_UP(size); struct vm_info *info; size_t i; int ret; @@ -323,18 +327,17 @@ static int ipu6_dma_mmap(struct device *dev, struct vm_area_struct *vma, return 0; } -static void ipu6_dma_unmap_sg(struct device *dev, - struct scatterlist *sglist, - int nents, enum dma_data_direction dir, - unsigned long attrs) +void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs) { - struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev; - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; + struct device *dev = &sys->auxdev.dev; + struct ipu6_mmu *mmu = sys->mmu; struct iova *iova = find_iova(&mmu->dmap->iovad, PHYS_PFN(sg_dma_address(sglist))); - int i, npages, count; struct scatterlist *sg; dma_addr_t pci_dma_addr; + unsigned int i; if (!nents) return; @@ -342,31 +345,15 @@ static void ipu6_dma_unmap_sg(struct device *dev, if (WARN_ON(!iova)) return; - if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0) - ipu6_dma_sync_sg_for_cpu(dev, sglist, nents, DMA_BIDIRECTIONAL); - - /* get the nents as orig_nents given by caller */ - count = 0; - npages = iova_size(iova); - for_each_sg(sglist, sg, nents, i) { - if (sg_dma_len(sg) == 0 || - sg_dma_address(sg) == DMA_MAPPING_ERROR) - break; - - npages -= PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg))); - count++; - if (npages <= 0) - break; - } - /* * Before IPU6 mmu unmap, return the pci dma address back to sg * assume the nents is less than orig_nents as the least granule * is 1 SZ_4K page */ - dev_dbg(dev, "trying to unmap concatenated %u ents\n", count); - for_each_sg(sglist, sg, count, i) { - dev_dbg(dev, "ipu unmap sg[%d] %pad\n", i, &sg_dma_address(sg)); + dev_dbg(dev, "trying to unmap concatenated %u ents\n", nents); + for_each_sg(sglist, sg, nents, i) { + dev_dbg(dev, "unmap sg[%d] %pad size %u\n", i, + &sg_dma_address(sg), sg_dma_len(sg)); pci_dma_addr = ipu6_mmu_iova_to_phys(mmu->dmap->mmu_info, sg_dma_address(sg)); dev_dbg(dev, "return pci_dma_addr %pad back to sg[%d]\n", @@ -380,23 +367,21 @@ static void ipu6_dma_unmap_sg(struct device *dev, PFN_PHYS(iova_size(iova))); mmu->tlb_invalidate(mmu); - - dma_unmap_sg_attrs(&pdev->dev, sglist, nents, dir, attrs); - __free_iova(&mmu->dmap->iovad, iova); } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sg, INTEL_IPU6); -static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist, - int nents, enum dma_data_direction dir, - unsigned long attrs) +int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs) { - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; - struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev; + struct device *dev = &sys->auxdev.dev; + struct ipu6_mmu *mmu = sys->mmu; struct scatterlist *sg; struct iova *iova; size_t npages = 0; unsigned long iova_addr; - int i, count; + int i; for_each_sg(sglist, sg, nents, i) { if (sg->offset) { @@ -406,17 +391,11 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist, } } - dev_dbg(dev, "pci_dma_map_sg trying to map %d ents\n", nents); - count = dma_map_sg_attrs(&pdev->dev, sglist, nents, dir, attrs); - if (count <= 0) { - dev_err(dev, "pci_dma_map_sg %d ents failed\n", nents); - return 0; - } - - dev_dbg(dev, "pci_dma_map_sg %d ents mapped\n", count); + for_each_sg(sglist, sg, nents, i) + npages += PFN_UP(sg_dma_len(sg)); - for_each_sg(sglist, sg, count, i) - npages += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg))); + dev_dbg(dev, "dmamap trying to map %d ents %zu pages\n", + nents, npages); iova = alloc_iova(&mmu->dmap->iovad, npages, PHYS_PFN(dma_get_mask(dev)), 0); @@ -427,12 +406,13 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist, iova->pfn_hi); iova_addr = iova->pfn_lo; - for_each_sg(sglist, sg, count, i) { + for_each_sg(sglist, sg, nents, i) { + phys_addr_t iova_pa; int ret; - dev_dbg(dev, "mapping entry %d: iova 0x%llx phy %pad size %d\n", - i, PFN_PHYS(iova_addr), &sg_dma_address(sg), - sg_dma_len(sg)); + iova_pa = PFN_PHYS(iova_addr); + dev_dbg(dev, "mapping entry %d: iova %pap phy %pap size %d\n", + i, &iova_pa, &sg_dma_address(sg), sg_dma_len(sg)); ret = ipu6_mmu_map(mmu->dmap->mmu_info, PFN_PHYS(iova_addr), sg_dma_address(sg), @@ -442,28 +422,51 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist, sg_dma_address(sg) = PFN_PHYS(iova_addr); - iova_addr += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg))); + iova_addr += PFN_UP(sg_dma_len(sg)); } - if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0) - ipu6_dma_sync_sg_for_cpu(dev, sglist, nents, DMA_BIDIRECTIONAL); + dev_dbg(dev, "dmamap %d ents %zu pages mapped\n", nents, npages); - return count; + return nents; out_fail: - ipu6_dma_unmap_sg(dev, sglist, i, dir, attrs); + ipu6_dma_unmap_sg(sys, sglist, i, dir, attrs); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ipu6_dma_map_sg, INTEL_IPU6); + +int ipu6_dma_map_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs) +{ + int nents; + + nents = ipu6_dma_map_sg(sys, sgt->sgl, sgt->nents, dir, attrs); + if (nents < 0) + return nents; + + sgt->nents = nents; return 0; } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_map_sgtable, INTEL_IPU6); + +void ipu6_dma_unmap_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs) +{ + ipu6_dma_unmap_sg(sys, sgt->sgl, sgt->nents, dir, attrs); +} +EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sgtable, INTEL_IPU6); /* * Create scatter-list for the already allocated DMA buffer */ -static int ipu6_dma_get_sgtable(struct device *dev, struct sg_table *sgt, - void *cpu_addr, dma_addr_t handle, size_t size, - unsigned long attrs) +int ipu6_dma_get_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + void *cpu_addr, dma_addr_t handle, size_t size, + unsigned long attrs) { - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; + struct device *dev = &sys->auxdev.dev; + struct ipu6_mmu *mmu = sys->mmu; struct vm_info *info; int n_pages; int ret = 0; @@ -478,25 +481,12 @@ static int ipu6_dma_get_sgtable(struct device *dev, struct sg_table *sgt, if (WARN_ON(!info->pages)) return -ENOMEM; - n_pages = PHYS_PFN(PAGE_ALIGN(size)); + n_pages = PFN_UP(size); ret = sg_alloc_table_from_pages(sgt, info->pages, n_pages, 0, size, GFP_KERNEL); if (ret) - dev_warn(dev, "IPU6 get sgt table failed\n"); + dev_warn(dev, "get sgt table failed\n"); return ret; } - -const struct dma_map_ops ipu6_dma_ops = { - .alloc = ipu6_dma_alloc, - .free = ipu6_dma_free, - .mmap = ipu6_dma_mmap, - .map_sg = ipu6_dma_map_sg, - .unmap_sg = ipu6_dma_unmap_sg, - .sync_single_for_cpu = ipu6_dma_sync_single_for_cpu, - .sync_single_for_device = ipu6_dma_sync_single_for_cpu, - .sync_sg_for_cpu = ipu6_dma_sync_sg_for_cpu, - .sync_sg_for_device = ipu6_dma_sync_sg_for_cpu, - .get_sgtable = ipu6_dma_get_sgtable, -}; diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.h b/drivers/media/pci/intel/ipu6/ipu6-dma.h index 847ea5b7c925..b51244add9e6 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-dma.h +++ b/drivers/media/pci/intel/ipu6/ipu6-dma.h @@ -5,7 +5,13 @@ #define IPU6_DMA_H #include <linux/dma-map-ops.h> +#include <linux/dma-mapping.h> #include <linux/iova.h> +#include <linux/iova.h> +#include <linux/scatterlist.h> +#include <linux/types.h> + +#include "ipu6-bus.h" struct ipu6_mmu_info; @@ -14,6 +20,30 @@ struct ipu6_dma_mapping { struct iova_domain iovad; }; -extern const struct dma_map_ops ipu6_dma_ops; - +void ipu6_dma_sync_single(struct ipu6_bus_device *sys, dma_addr_t dma_handle, + size_t size); +void ipu6_dma_sync_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents); +void ipu6_dma_sync_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt); +void *ipu6_dma_alloc(struct ipu6_bus_device *sys, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, + unsigned long attrs); +void ipu6_dma_free(struct ipu6_bus_device *sys, size_t size, void *vaddr, + dma_addr_t dma_handle, unsigned long attrs); +int ipu6_dma_mmap(struct ipu6_bus_device *sys, struct vm_area_struct *vma, + void *addr, dma_addr_t iova, size_t size, + unsigned long attrs); +int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs); +void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs); +int ipu6_dma_map_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs); +void ipu6_dma_unmap_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs); +int ipu6_dma_get_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + void *cpu_addr, dma_addr_t handle, size_t size, + unsigned long attrs); #endif /* IPU6_DMA_H */ diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-com.c b/drivers/media/pci/intel/ipu6/ipu6-fw-com.c index 0b33fe9e703d..53edb445d939 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-fw-com.c +++ b/drivers/media/pci/intel/ipu6/ipu6-fw-com.c @@ -12,6 +12,7 @@ #include <linux/types.h> #include "ipu6-bus.h" +#include "ipu6-dma.h" #include "ipu6-fw-com.h" /* @@ -88,7 +89,6 @@ struct ipu6_fw_com_context { void *dma_buffer; dma_addr_t dma_addr; unsigned int dma_size; - unsigned long attrs; struct ipu6_fw_sys_queue *input_queue; /* array of host to SP queues */ struct ipu6_fw_sys_queue *output_queue; /* array of SP to host */ @@ -164,7 +164,6 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg, struct ipu6_fw_com_context *ctx; struct device *dev = &adev->auxdev.dev; size_t sizeall, offset; - unsigned long attrs = 0; void *specific_host_addr; unsigned int i; @@ -206,9 +205,8 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg, sizeall += sizeinput + sizeoutput; - ctx->dma_buffer = dma_alloc_attrs(dev, sizeall, &ctx->dma_addr, - GFP_KERNEL, attrs); - ctx->attrs = attrs; + ctx->dma_buffer = ipu6_dma_alloc(adev, sizeall, &ctx->dma_addr, + GFP_KERNEL, 0); if (!ctx->dma_buffer) { dev_err(dev, "failed to allocate dma memory\n"); kfree(ctx); @@ -239,10 +237,12 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg, memcpy(specific_host_addr, cfg->specific_addr, cfg->specific_size); + ipu6_dma_sync_single(adev, ctx->config_vied_addr, sizeall); + /* initialize input queues */ offset += specific_size; res.reg = SYSCOM_QPR_BASE_REG; - res.host_address = (u64)(ctx->dma_buffer + offset); + res.host_address = (uintptr_t)(ctx->dma_buffer + offset); res.vied_address = ctx->dma_addr + offset; for (i = 0; i < cfg->num_input_queues; i++) ipu6_sys_queue_init(ctx->input_queue + i, @@ -251,7 +251,7 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg, /* initialize output queues */ offset += sizeinput; - res.host_address = (u64)(ctx->dma_buffer + offset); + res.host_address = (uintptr_t)(ctx->dma_buffer + offset); res.vied_address = ctx->dma_addr + offset; for (i = 0; i < cfg->num_output_queues; i++) { ipu6_sys_queue_init(ctx->output_queue + i, @@ -315,8 +315,8 @@ int ipu6_fw_com_release(struct ipu6_fw_com_context *ctx, unsigned int force) if (!force && !ctx->cell_ready(ctx->adev)) return -EBUSY; - dma_free_attrs(&ctx->adev->auxdev.dev, ctx->dma_size, - ctx->dma_buffer, ctx->dma_addr, ctx->attrs); + ipu6_dma_free(ctx->adev, ctx->dma_size, + ctx->dma_buffer, ctx->dma_addr, 0); kfree(ctx); return 0; } @@ -358,7 +358,7 @@ void *ipu6_send_get_token(struct ipu6_fw_com_context *ctx, int q_nbr) index = readl(q_dmem + FW_COM_WR_REG); - return (void *)(q->host_address + index * q->token_size); + return (void *)((uintptr_t)q->host_address + index * q->token_size); } EXPORT_SYMBOL_NS_GPL(ipu6_send_get_token, INTEL_IPU6); @@ -395,7 +395,7 @@ void *ipu6_recv_get_token(struct ipu6_fw_com_context *ctx, int q_nbr) if (!packets) return NULL; - return (void *)(q->host_address + rd * q->token_size); + return (void *)((uintptr_t)q->host_address + rd * q->token_size); } EXPORT_SYMBOL_NS_GPL(ipu6_recv_get_token, INTEL_IPU6); diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c b/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c index 1715275e6776..db2874843453 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c @@ -67,7 +67,7 @@ static void dwc_dphy_write(struct ipu6_isys *isys, u32 phy_id, u32 addr, void __iomem *isys_base = isys->pdata->base; void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id); - dev_dbg(dev, "write: reg 0x%lx = data 0x%x", base + addr - isys_base, + dev_dbg(dev, "write: reg 0x%zx = data 0x%x", base + addr - isys_base, data); writel(data, base + addr); } @@ -80,7 +80,7 @@ static u32 dwc_dphy_read(struct ipu6_isys *isys, u32 phy_id, u32 addr) u32 data; data = readl(base + addr); - dev_dbg(dev, "read: reg 0x%lx = data 0x%x", base + addr - isys_base, + dev_dbg(dev, "read: reg 0x%zx = data 0x%x", base + addr - isys_base, data); return data; diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c index 03dbb0e0ea79..bbb66b56ee88 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c @@ -13,17 +13,48 @@ #include <media/media-entity.h> #include <media/v4l2-subdev.h> -#include <media/videobuf2-dma-contig.h> +#include <media/videobuf2-dma-sg.h> #include <media/videobuf2-v4l2.h> #include "ipu6-bus.h" +#include "ipu6-dma.h" #include "ipu6-fw-isys.h" #include "ipu6-isys.h" #include "ipu6-isys-video.h" -static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, - unsigned int *num_planes, unsigned int sizes[], - struct device *alloc_devs[]) +static int ipu6_isys_buf_init(struct vb2_buffer *vb) +{ + struct ipu6_isys *isys = vb2_get_drv_priv(vb->vb2_queue); + struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0); + struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb); + struct ipu6_isys_video_buffer *ivb = + vb2_buffer_to_ipu6_isys_video_buffer(vvb); + int ret; + + ret = ipu6_dma_map_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0); + if (ret) + return ret; + + ivb->dma_addr = sg_dma_address(sg->sgl); + + return 0; +} + +static void ipu6_isys_buf_cleanup(struct vb2_buffer *vb) +{ + struct ipu6_isys *isys = vb2_get_drv_priv(vb->vb2_queue); + struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0); + struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb); + struct ipu6_isys_video_buffer *ivb = + vb2_buffer_to_ipu6_isys_video_buffer(vvb); + + ivb->dma_addr = 0; + ipu6_dma_unmap_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0); +} + +static int ipu6_isys_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) { struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q); struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq); @@ -207,9 +238,11 @@ ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb, struct ipu6_fw_isys_frame_buff_set_abi *set) { struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue); + struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb); + struct ipu6_isys_video_buffer *ivb = + vb2_buffer_to_ipu6_isys_video_buffer(vvb); - set->output_pins[aq->fw_output].addr = - vb2_dma_contig_plane_dma_addr(vb, 0); + set->output_pins[aq->fw_output].addr = ivb->dma_addr; set->output_pins[aq->fw_output].out_buf_id = vb->index + 1; } @@ -332,7 +365,7 @@ static void buf_queue(struct vb2_buffer *vb) dev_dbg(dev, "queue buffer %u for %s\n", vb->index, av->vdev.name); - dma = vb2_dma_contig_plane_dma_addr(vb, 0); + dma = ivb->dma_addr; dev_dbg(dev, "iova: iova %pad\n", &dma); spin_lock_irqsave(&aq->lock, flags); @@ -724,10 +757,14 @@ void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream, } list_for_each_entry_reverse(ib, &aq->active, head) { + struct ipu6_isys_video_buffer *ivb; + struct vb2_v4l2_buffer *vvb; dma_addr_t addr; vb = ipu6_isys_buffer_to_vb2_buffer(ib); - addr = vb2_dma_contig_plane_dma_addr(vb, 0); + vvb = to_vb2_v4l2_buffer(vb); + ivb = vb2_buffer_to_ipu6_isys_video_buffer(vvb); + addr = ivb->dma_addr; if (info->pin.addr != addr) { if (first) @@ -766,10 +803,12 @@ void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream, } static const struct vb2_ops ipu6_isys_queue_ops = { - .queue_setup = queue_setup, + .queue_setup = ipu6_isys_queue_setup, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, + .buf_init = ipu6_isys_buf_init, .buf_prepare = ipu6_isys_buf_prepare, + .buf_cleanup = ipu6_isys_buf_cleanup, .start_streaming = start_streaming, .stop_streaming = stop_streaming, .buf_queue = buf_queue, @@ -779,16 +818,17 @@ int ipu6_isys_queue_init(struct ipu6_isys_queue *aq) { struct ipu6_isys *isys = ipu6_isys_queue_to_video(aq)->isys; struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq); + struct ipu6_bus_device *adev = isys->adev; int ret; /* no support for userptr */ if (!aq->vbq.io_modes) aq->vbq.io_modes = VB2_MMAP | VB2_DMABUF; - aq->vbq.drv_priv = aq; + aq->vbq.drv_priv = isys; aq->vbq.ops = &ipu6_isys_queue_ops; aq->vbq.lock = &av->mutex; - aq->vbq.mem_ops = &vb2_dma_contig_memops; + aq->vbq.mem_ops = &vb2_dma_sg_memops; aq->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; aq->vbq.min_queued_buffers = 1; aq->vbq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; @@ -797,8 +837,8 @@ int ipu6_isys_queue_init(struct ipu6_isys_queue *aq) if (ret) return ret; - aq->dev = &isys->adev->auxdev.dev; - aq->vbq.dev = &isys->adev->auxdev.dev; + aq->dev = &adev->auxdev.dev; + aq->vbq.dev = &adev->isp->pdev->dev; spin_lock_init(&aq->lock); INIT_LIST_HEAD(&aq->active); INIT_LIST_HEAD(&aq->incoming); diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h index 95cfd4869d93..fe8fc796a58f 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h @@ -38,6 +38,7 @@ struct ipu6_isys_buffer { struct ipu6_isys_video_buffer { struct vb2_v4l2_buffer vb_v4l2; struct ipu6_isys_buffer ib; + dma_addr_t dma_addr; }; #define IPU6_ISYS_BUFFER_LIST_FL_INCOMING BIT(0) diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c index b37561352ead..387963529adb 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c @@ -543,7 +543,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av, ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg); if (ret < 0) { - ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg); + ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); return ret; } } @@ -560,7 +560,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av, IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN); if (ret < 0) { dev_err(dev, "can't open stream (%d)\n", ret); - ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg); + ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); return ret; } @@ -569,7 +569,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av, tout = wait_for_completion_timeout(&stream->stream_open_completion, IPU6_FW_CALL_TIMEOUT_JIFFIES); - ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg); + ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); if (!tout) { dev_err(dev, "stream open time out\n"); diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c index c4aff2e2009b..7148f8fe23f5 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c @@ -34,6 +34,7 @@ #include "ipu6-bus.h" #include "ipu6-cpd.h" +#include "ipu6-dma.h" #include "ipu6-isys.h" #include "ipu6-isys-csi2.h" #include "ipu6-mmu.h" @@ -576,7 +577,7 @@ void update_watermark_setting(struct ipu6_isys *isys) } enable_iwake(isys, true); - calc_fill_time_us = max_sram_size / isys_pb_datarate_mbs; + calc_fill_time_us = div64_u64(max_sram_size, isys_pb_datarate_mbs); if (isys->pdata->ipdata->enhanced_iwake) { ltr = isys->pdata->ipdata->ltr; @@ -933,29 +934,27 @@ static const struct dev_pm_ops isys_pm_ops = { static void free_fw_msg_bufs(struct ipu6_isys *isys) { - struct device *dev = &isys->adev->auxdev.dev; struct isys_fw_msgs *fwmsg, *safe; list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist, head) - dma_free_attrs(dev, sizeof(struct isys_fw_msgs), fwmsg, - fwmsg->dma_addr, 0); + ipu6_dma_free(isys->adev, sizeof(struct isys_fw_msgs), fwmsg, + fwmsg->dma_addr, 0); list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist_fw, head) - dma_free_attrs(dev, sizeof(struct isys_fw_msgs), fwmsg, - fwmsg->dma_addr, 0); + ipu6_dma_free(isys->adev, sizeof(struct isys_fw_msgs), fwmsg, + fwmsg->dma_addr, 0); } static int alloc_fw_msg_bufs(struct ipu6_isys *isys, int amount) { - struct device *dev = &isys->adev->auxdev.dev; struct isys_fw_msgs *addr; dma_addr_t dma_addr; unsigned long flags; unsigned int i; for (i = 0; i < amount; i++) { - addr = dma_alloc_attrs(dev, sizeof(struct isys_fw_msgs), - &dma_addr, GFP_KERNEL, 0); + addr = ipu6_dma_alloc(isys->adev, sizeof(*addr), + &dma_addr, GFP_KERNEL, 0); if (!addr) break; addr->dma_addr = dma_addr; @@ -974,8 +973,8 @@ static int alloc_fw_msg_bufs(struct ipu6_isys *isys, int amount) struct isys_fw_msgs, head); list_del(&addr->head); spin_unlock_irqrestore(&isys->listlock, flags); - dma_free_attrs(dev, sizeof(struct isys_fw_msgs), addr, - addr->dma_addr, 0); + ipu6_dma_free(isys->adev, sizeof(struct isys_fw_msgs), addr, + addr->dma_addr, 0); spin_lock_irqsave(&isys->listlock, flags); } spin_unlock_irqrestore(&isys->listlock, flags); @@ -1026,11 +1025,11 @@ void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys) spin_unlock_irqrestore(&isys->listlock, flags); } -void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, u64 data) +void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data) { struct isys_fw_msgs *msg; unsigned long flags; - u64 *ptr = (u64 *)data; + void *ptr = (void *)data; if (!ptr) return; diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h index 86dfc2eff5d0..610b60e69152 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys.h +++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h @@ -180,7 +180,7 @@ struct isys_fw_msgs { }; struct isys_fw_msgs *ipu6_get_fw_msg_buf(struct ipu6_isys_stream *stream); -void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, u64 data); +void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data); void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys); extern const struct v4l2_ioctl_ops ipu6_isys_ioctl_ops; diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c index c3a20507d6db..a81e9b09a3c5 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c +++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c @@ -97,13 +97,15 @@ static void page_table_dump(struct ipu6_mmu_info *mmu_info) for (l1_idx = 0; l1_idx < ISP_L1PT_PTES; l1_idx++) { u32 l2_idx; u32 iova = (phys_addr_t)l1_idx << ISP_L1PT_SHIFT; + phys_addr_t l2_phys; if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) continue; + + l2_phys = TBL_PHYS_ADDR(mmu_info->l1_pt[l1_idx];) dev_dbg(mmu_info->dev, - "l1 entry %u; iovas 0x%8.8x-0x%8.8x, at %pa\n", - l1_idx, iova, iova + ISP_PAGE_SIZE, - TBL_PHYS_ADDR(mmu_info->l1_pt[l1_idx])); + "l1 entry %u; iovas 0x%8.8x-0x%8.8x, at %pap\n", + l1_idx, iova, iova + ISP_PAGE_SIZE, &l2_phys); for (l2_idx = 0; l2_idx < ISP_L2PT_PTES; l2_idx++) { u32 *l2_pt = mmu_info->l2_pts[l1_idx]; @@ -227,7 +229,7 @@ static u32 *alloc_l1_pt(struct ipu6_mmu_info *mmu_info) } mmu_info->l1_pt_dma = dma >> ISP_PADDR_SHIFT; - dev_dbg(mmu_info->dev, "l1 pt %p mapped at %llx\n", pt, dma); + dev_dbg(mmu_info->dev, "l1 pt %p mapped at %pad\n", pt, &dma); return pt; @@ -252,75 +254,142 @@ static u32 *alloc_l2_pt(struct ipu6_mmu_info *mmu_info) return pt; } +static void l2_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, + phys_addr_t dummy, size_t size) +{ + unsigned int l2_entries; + unsigned int l2_idx; + unsigned long flags; + u32 l1_idx; + u32 *l2_pt; + + spin_lock_irqsave(&mmu_info->lock, flags); + for (l1_idx = iova >> ISP_L1PT_SHIFT; + size > 0 && l1_idx < ISP_L1PT_PTES; l1_idx++) { + dev_dbg(mmu_info->dev, + "unmapping l2 pgtable (l1 index %u (iova 0x%8.8lx))\n", + l1_idx, iova); + + if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) { + dev_err(mmu_info->dev, + "unmap not mapped iova 0x%8.8lx l1 index %u\n", + iova, l1_idx); + continue; + } + l2_pt = mmu_info->l2_pts[l1_idx]; + + l2_entries = 0; + for (l2_idx = (iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT; + size > 0 && l2_idx < ISP_L2PT_PTES; l2_idx++) { + phys_addr_t pteval = TBL_PHYS_ADDR(l2_pt[l2_idx]); + + dev_dbg(mmu_info->dev, + "unmap l2 index %u with pteval 0x%p\n", + l2_idx, &pteval); + l2_pt[l2_idx] = mmu_info->dummy_page_pteval; + + iova += ISP_PAGE_SIZE; + size -= ISP_PAGE_SIZE; + + l2_entries++; + } + + WARN_ON_ONCE(!l2_entries); + clflush_cache_range(&l2_pt[l2_idx - l2_entries], + sizeof(l2_pt[0]) * l2_entries); + } + + WARN_ON_ONCE(size); + spin_unlock_irqrestore(&mmu_info->lock, flags); +} + static int l2_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, phys_addr_t paddr, size_t size) { - u32 l1_idx = iova >> ISP_L1PT_SHIFT; - u32 iova_start = iova; + struct device *dev = mmu_info->dev; + unsigned int l2_entries; u32 *l2_pt, *l2_virt; unsigned int l2_idx; unsigned long flags; + size_t mapped = 0; dma_addr_t dma; u32 l1_entry; - - dev_dbg(mmu_info->dev, - "mapping l2 page table for l1 index %u (iova %8.8x)\n", - l1_idx, (u32)iova); + u32 l1_idx; + int err = 0; spin_lock_irqsave(&mmu_info->lock, flags); - l1_entry = mmu_info->l1_pt[l1_idx]; - if (l1_entry == mmu_info->dummy_l2_pteval) { - l2_virt = mmu_info->l2_pts[l1_idx]; - if (likely(!l2_virt)) { - l2_virt = alloc_l2_pt(mmu_info); - if (!l2_virt) { - spin_unlock_irqrestore(&mmu_info->lock, flags); - return -ENOMEM; + + paddr = ALIGN(paddr, ISP_PAGE_SIZE); + for (l1_idx = iova >> ISP_L1PT_SHIFT; + size > 0 && l1_idx < ISP_L1PT_PTES; l1_idx++) { + dev_dbg(dev, + "mapping l2 page table for l1 index %u (iova %8.8x)\n", + l1_idx, (u32)iova); + + l1_entry = mmu_info->l1_pt[l1_idx]; + if (l1_entry == mmu_info->dummy_l2_pteval) { + l2_virt = mmu_info->l2_pts[l1_idx]; + if (likely(!l2_virt)) { + l2_virt = alloc_l2_pt(mmu_info); + if (!l2_virt) { + err = -ENOMEM; + goto error; + } } - } - dma = map_single(mmu_info, l2_virt); - if (!dma) { - dev_err(mmu_info->dev, "Failed to map l2pt page\n"); - free_page((unsigned long)l2_virt); - spin_unlock_irqrestore(&mmu_info->lock, flags); - return -EINVAL; - } + dma = map_single(mmu_info, l2_virt); + if (!dma) { + dev_err(dev, "Failed to map l2pt page\n"); + free_page((unsigned long)l2_virt); + err = -EINVAL; + goto error; + } - l1_entry = dma >> ISP_PADDR_SHIFT; + l1_entry = dma >> ISP_PADDR_SHIFT; - dev_dbg(mmu_info->dev, "page for l1_idx %u %p allocated\n", - l1_idx, l2_virt); - mmu_info->l1_pt[l1_idx] = l1_entry; - mmu_info->l2_pts[l1_idx] = l2_virt; - clflush_cache_range((void *)&mmu_info->l1_pt[l1_idx], - sizeof(mmu_info->l1_pt[l1_idx])); - } + dev_dbg(dev, "page for l1_idx %u %p allocated\n", + l1_idx, l2_virt); + mmu_info->l1_pt[l1_idx] = l1_entry; + mmu_info->l2_pts[l1_idx] = l2_virt; - l2_pt = mmu_info->l2_pts[l1_idx]; + clflush_cache_range(&mmu_info->l1_pt[l1_idx], + sizeof(mmu_info->l1_pt[l1_idx])); + } - dev_dbg(mmu_info->dev, "l2_pt at %p with dma 0x%x\n", l2_pt, l1_entry); + l2_pt = mmu_info->l2_pts[l1_idx]; + l2_entries = 0; - paddr = ALIGN(paddr, ISP_PAGE_SIZE); + for (l2_idx = (iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT; + size > 0 && l2_idx < ISP_L2PT_PTES; l2_idx++) { + l2_pt[l2_idx] = paddr >> ISP_PADDR_SHIFT; - l2_idx = (iova_start & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT; + dev_dbg(dev, "l2 index %u mapped as 0x%8.8x\n", l2_idx, + l2_pt[l2_idx]); - dev_dbg(mmu_info->dev, "l2_idx %u, phys 0x%8.8x\n", l2_idx, - l2_pt[l2_idx]); - if (l2_pt[l2_idx] != mmu_info->dummy_page_pteval) { - spin_unlock_irqrestore(&mmu_info->lock, flags); - return -EINVAL; - } + iova += ISP_PAGE_SIZE; + paddr += ISP_PAGE_SIZE; + mapped += ISP_PAGE_SIZE; + size -= ISP_PAGE_SIZE; + + l2_entries++; + } - l2_pt[l2_idx] = paddr >> ISP_PADDR_SHIFT; + WARN_ON_ONCE(!l2_entries); + clflush_cache_range(&l2_pt[l2_idx - l2_entries], + sizeof(l2_pt[0]) * l2_entries); + } - clflush_cache_range((void *)&l2_pt[l2_idx], sizeof(l2_pt[l2_idx])); spin_unlock_irqrestore(&mmu_info->lock, flags); - dev_dbg(mmu_info->dev, "l2 index %u mapped as 0x%8.8x\n", l2_idx, - l2_pt[l2_idx]); - return 0; + +error: + spin_unlock_irqrestore(&mmu_info->lock, flags); + /* unroll mapping in case something went wrong */ + if (mapped) + l2_unmap(mmu_info, iova - mapped, paddr - mapped, mapped); + + return err; } static int __ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, @@ -330,61 +399,21 @@ static int __ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, u32 iova_end = ALIGN(iova + size, ISP_PAGE_SIZE); dev_dbg(mmu_info->dev, - "mapping iova 0x%8.8x--0x%8.8x, size %zu at paddr 0x%10.10llx\n", - iova_start, iova_end, size, paddr); + "mapping iova 0x%8.8x--0x%8.8x, size %zu at paddr %pap\n", + iova_start, iova_end, size, &paddr); return l2_map(mmu_info, iova_start, paddr, size); } -static size_t l2_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, - phys_addr_t dummy, size_t size) +static void __ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, + unsigned long iova, size_t size) { - u32 l1_idx = iova >> ISP_L1PT_SHIFT; - u32 iova_start = iova; - unsigned int l2_idx; - size_t unmapped = 0; - unsigned long flags; - u32 *l2_pt; - - dev_dbg(mmu_info->dev, "unmapping l2 page table for l1 index %u (iova 0x%8.8lx)\n", - l1_idx, iova); - - spin_lock_irqsave(&mmu_info->lock, flags); - if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) { - spin_unlock_irqrestore(&mmu_info->lock, flags); - dev_err(mmu_info->dev, - "unmap iova 0x%8.8lx l1 idx %u which was not mapped\n", - iova, l1_idx); - return 0; - } - - for (l2_idx = (iova_start & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT; - (iova_start & ISP_L1PT_MASK) + (l2_idx << ISP_PAGE_SHIFT) - < iova_start + size && l2_idx < ISP_L2PT_PTES; l2_idx++) { - l2_pt = mmu_info->l2_pts[l1_idx]; - dev_dbg(mmu_info->dev, - "unmap l2 index %u with pteval 0x%10.10llx\n", - l2_idx, TBL_PHYS_ADDR(l2_pt[l2_idx])); - l2_pt[l2_idx] = mmu_info->dummy_page_pteval; - - clflush_cache_range((void *)&l2_pt[l2_idx], - sizeof(l2_pt[l2_idx])); - unmapped++; - } - spin_unlock_irqrestore(&mmu_info->lock, flags); - - return unmapped << ISP_PAGE_SHIFT; -} - -static size_t __ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, - unsigned long iova, size_t size) -{ - return l2_unmap(mmu_info, iova, 0, size); + l2_unmap(mmu_info, iova, 0, size); } static int allocate_trash_buffer(struct ipu6_mmu *mmu) { - unsigned int n_pages = PHYS_PFN(PAGE_ALIGN(IPU6_MMUV2_TRASH_RANGE)); + unsigned int n_pages = PFN_UP(IPU6_MMUV2_TRASH_RANGE); struct iova *iova; unsigned int i; dma_addr_t dma; @@ -525,9 +554,10 @@ static struct ipu6_mmu_info *ipu6_mmu_alloc(struct ipu6_device *isp) return NULL; mmu_info->aperture_start = 0; - mmu_info->aperture_end = DMA_BIT_MASK(isp->secure_mode ? - IPU6_MMU_ADDR_BITS : - IPU6_MMU_ADDR_BITS_NON_SECURE); + mmu_info->aperture_end = + (dma_addr_t)DMA_BIT_MASK(isp->secure_mode ? + IPU6_MMU_ADDR_BITS : + IPU6_MMU_ADDR_BITS_NON_SECURE); mmu_info->pgsize_bitmap = SZ_4K; mmu_info->dev = &isp->pdev->dev; @@ -619,40 +649,13 @@ phys_addr_t ipu6_mmu_iova_to_phys(struct ipu6_mmu_info *mmu_info, return phy_addr; } -static size_t ipu6_mmu_pgsize(unsigned long pgsize_bitmap, - unsigned long addr_merge, size_t size) -{ - unsigned int pgsize_idx; - size_t pgsize; - - /* Max page size that still fits into 'size' */ - pgsize_idx = __fls(size); - - if (likely(addr_merge)) { - /* Max page size allowed by address */ - unsigned int align_pgsize_idx = __ffs(addr_merge); - - pgsize_idx = min(pgsize_idx, align_pgsize_idx); - } - - pgsize = (1UL << (pgsize_idx + 1)) - 1; - pgsize &= pgsize_bitmap; - - WARN_ON(!pgsize); - - /* pick the biggest page */ - pgsize_idx = __fls(pgsize); - pgsize = 1UL << pgsize_idx; - - return pgsize; -} - -size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, - size_t size) +void ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, + size_t size) { - size_t unmapped_page, unmapped = 0; unsigned int min_pagesz; + dev_dbg(mmu_info->dev, "unmapping iova 0x%lx size 0x%zx\n", iova, size); + /* find out the minimum page size supported */ min_pagesz = 1 << __ffs(mmu_info->pgsize_bitmap); @@ -664,38 +667,16 @@ size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, if (!IS_ALIGNED(iova | size, min_pagesz)) { dev_err(NULL, "unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n", iova, size, min_pagesz); - return -EINVAL; - } - - /* - * Keep iterating until we either unmap 'size' bytes (or more) - * or we hit an area that isn't mapped. - */ - while (unmapped < size) { - size_t pgsize = ipu6_mmu_pgsize(mmu_info->pgsize_bitmap, - iova, size - unmapped); - - unmapped_page = __ipu6_mmu_unmap(mmu_info, iova, pgsize); - if (!unmapped_page) - break; - - dev_dbg(mmu_info->dev, "unmapped: iova 0x%lx size 0x%zx\n", - iova, unmapped_page); - - iova += unmapped_page; - unmapped += unmapped_page; + return; } - return unmapped; + __ipu6_mmu_unmap(mmu_info, iova, size); } int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, phys_addr_t paddr, size_t size) { - unsigned long orig_iova = iova; unsigned int min_pagesz; - size_t orig_size = size; - int ret = 0; if (mmu_info->pgsize_bitmap == 0UL) return -ENODEV; @@ -718,28 +699,7 @@ int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, dev_dbg(mmu_info->dev, "map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size); - while (size) { - size_t pgsize = ipu6_mmu_pgsize(mmu_info->pgsize_bitmap, - iova | paddr, size); - - dev_dbg(mmu_info->dev, - "mapping: iova 0x%lx pa %pa pgsize 0x%zx\n", - iova, &paddr, pgsize); - - ret = __ipu6_mmu_map(mmu_info, iova, paddr, pgsize); - if (ret) - break; - - iova += pgsize; - paddr += pgsize; - size -= pgsize; - } - - /* unroll mapping in case something went wrong */ - if (ret) - ipu6_mmu_unmap(mmu_info, orig_iova, orig_size - size); - - return ret; + return __ipu6_mmu_map(mmu_info, iova, paddr, size); } static void ipu6_mmu_destroy(struct ipu6_mmu *mmu) diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.h b/drivers/media/pci/intel/ipu6/ipu6-mmu.h index 21cdb0f146eb..8e40b4a66d7d 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-mmu.h +++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.h @@ -66,8 +66,8 @@ int ipu6_mmu_hw_init(struct ipu6_mmu *mmu); void ipu6_mmu_hw_cleanup(struct ipu6_mmu *mmu); int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, phys_addr_t paddr, size_t size); -size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, - size_t size); +void ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, + size_t size); phys_addr_t ipu6_mmu_iova_to_phys(struct ipu6_mmu_info *mmu_info, dma_addr_t iova); #endif diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h index 20f27011df43..efd65e494c16 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h +++ b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h @@ -219,8 +219,6 @@ enum { BUTTRESS_ISR_IS_IRQ | BUTTRESS_ISR_PS_IRQ) #define BUTTRESS_EVENT (BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \ - BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING | \ BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE | \ - BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH | \ BUTTRESS_ISR_SAI_VIOLATION) #endif /* IPU6_PLATFORM_BUTTRESS_REGS_H */ diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c index 7fb707d35309..a38292e8eaac 100644 --- a/drivers/media/pci/intel/ipu6/ipu6.c +++ b/drivers/media/pci/intel/ipu6/ipu6.c @@ -247,7 +247,8 @@ ipu6_pkg_dir_configure_spc(struct ipu6_device *isp, dma_addr = sg_dma_address(isp->psys->fw_sgt.sgl); pg_offset = server_fw_addr - dma_addr; - prog = (struct ipu6_cell_program *)((u64)isp->cpd_fw->data + pg_offset); + prog = (struct ipu6_cell_program *)((uintptr_t)isp->cpd_fw->data + + pg_offset); spc_base = base + prog->regs_addr; if (spc_base != (base + hw_variant->spc_offset)) dev_warn(&isp->pdev->dev, @@ -752,6 +753,9 @@ static void ipu6_pci_reset_done(struct pci_dev *pdev) */ static int ipu6_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); + + synchronize_irq(pdev->irq); return 0; } diff --git a/drivers/media/pci/mantis/mantis_core.h b/drivers/media/pci/mantis/mantis_core.h deleted file mode 100644 index 93c89a10a2c7..000000000000 --- a/drivers/media/pci/mantis/mantis_core.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - -*/ - -#ifndef __MANTIS_CORE_H -#define __MANTIS_CORE_H - -#include "mantis_common.h" - - -#define FE_TYPE_SAT 0 -#define FE_TYPE_CAB 1 -#define FE_TYPE_TER 2 - -#define FE_TYPE_TS204 0 -#define FE_TYPE_TS188 1 - - -struct vendorname { - u8 *sub_vendor_name; - u32 sub_vendor_id; -}; - -struct devicetype { - u8 *sub_device_name; - u32 sub_device_id; - u8 device_type; - u32 type_flags; -}; - - -extern int mantis_dma_init(struct mantis_pci *mantis); -extern int mantis_dma_exit(struct mantis_pci *mantis); -extern void mantis_dma_start(struct mantis_pci *mantis); -extern void mantis_dma_stop(struct mantis_pci *mantis); -extern int mantis_i2c_init(struct mantis_pci *mantis); -extern int mantis_i2c_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_CORE_H */ diff --git a/drivers/media/pci/mgb4/mgb4_cmt.c b/drivers/media/pci/mgb4/mgb4_cmt.c index 70dc78ef193c..a25b68403bc6 100644 --- a/drivers/media/pci/mgb4/mgb4_cmt.c +++ b/drivers/media/pci/mgb4/mgb4_cmt.c @@ -227,6 +227,8 @@ void mgb4_cmt_set_vin_freq_range(struct mgb4_vin_dev *vindev, u32 config; size_t i; + freq_range = array_index_nospec(freq_range, ARRAY_SIZE(cmt_vals_in)); + addr = cmt_addrs_in[vindev->config->id]; reg_set = cmt_vals_in[freq_range]; diff --git a/drivers/media/pci/mgb4/mgb4_core.c b/drivers/media/pci/mgb4/mgb4_core.c index 2819bbdab484..bc63dc81bcae 100644 --- a/drivers/media/pci/mgb4/mgb4_core.c +++ b/drivers/media/pci/mgb4/mgb4_core.c @@ -582,9 +582,7 @@ static int mgb4_probe(struct pci_dev *pdev, const struct pci_device_id *id) NULL); #endif -#ifdef CONFIG_DEBUG_FS mgbdev->debugfs = debugfs_create_dir(dev_name(&pdev->dev), NULL); -#endif /* Get card serial number. On systems without MTD flash support we may * get an error thus ignore the return value. An invalid serial number @@ -646,6 +644,8 @@ static void mgb4_remove(struct pci_dev *pdev) hwmon_device_unregister(mgbdev->hwmon_dev); #endif + debugfs_remove_recursive(mgbdev->debugfs); + if (mgbdev->indio_dev) mgb4_trigger_free(mgbdev->indio_dev); @@ -656,10 +656,6 @@ static void mgb4_remove(struct pci_dev *pdev) if (mgbdev->vin[i]) mgb4_vin_free(mgbdev->vin[i]); -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(mgbdev->debugfs); -#endif - device_remove_groups(&mgbdev->pdev->dev, mgb4_pci_groups); free_spi(mgbdev); free_i2c(mgbdev); diff --git a/drivers/media/pci/mgb4/mgb4_core.h b/drivers/media/pci/mgb4/mgb4_core.h index b52cd67270b5..9aec62514c0b 100644 --- a/drivers/media/pci/mgb4/mgb4_core.h +++ b/drivers/media/pci/mgb4/mgb4_core.h @@ -68,9 +68,7 @@ struct mgb4_dev { u8 module_version; u32 serial_number; -#ifdef CONFIG_DEBUG_FS struct dentry *debugfs; -#endif }; #endif diff --git a/drivers/media/pci/mgb4/mgb4_vin.c b/drivers/media/pci/mgb4/mgb4_vin.c index e9332abb3172..3f171c624b40 100644 --- a/drivers/media/pci/mgb4/mgb4_vin.c +++ b/drivers/media/pci/mgb4/mgb4_vin.c @@ -260,6 +260,7 @@ static void buffer_queue(struct vb2_buffer *vb) static void stop_streaming(struct vb2_queue *vq) { struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vq); + struct mgb4_regs *video = &vindev->mgbdev->video; const struct mgb4_vin_config *config = vindev->config; int irq = xdma_get_user_irq(vindev->mgbdev->xdev, config->vin_irq); @@ -273,6 +274,9 @@ static void stop_streaming(struct vb2_queue *vq) mgb4_mask_reg(&vindev->mgbdev->video, config->regs.config, 0x2, 0x0); + mgb4_write_reg(video, vindev->config->regs.padding, 0); + set_loopback_padding(vindev, 0); + cancel_work_sync(&vindev->dma_work); return_all_buffers(vindev, VB2_BUF_STATE_ERROR); } @@ -280,6 +284,7 @@ static void stop_streaming(struct vb2_queue *vq) static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vq); + struct mgb4_regs *video = &vindev->mgbdev->video; const struct mgb4_vin_config *config = vindev->config; int irq = xdma_get_user_irq(vindev->mgbdev->xdev, config->vin_irq); @@ -292,6 +297,9 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) mgb4_mask_reg(&vindev->mgbdev->video, config->regs.config, 0x2, 0x2); + mgb4_write_reg(video, vindev->config->regs.padding, vindev->padding); + set_loopback_padding(vindev, vindev->padding); + xdma_enable_user_irq(vindev->mgbdev->xdev, irq); return 0; @@ -304,8 +312,6 @@ static const struct vb2_ops queue_ops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish }; static int fh_open(struct file *file) @@ -324,34 +330,16 @@ static int fh_open(struct file *file) if (get_timings(vindev, &vindev->timings) < 0) vindev->timings = cea1080p60; - set_loopback_padding(vindev, vindev->padding); out: mutex_unlock(&vindev->lock); return rv; } -static int fh_release(struct file *file) -{ - struct mgb4_vin_dev *vindev = video_drvdata(file); - int rv; - - mutex_lock(&vindev->lock); - - if (v4l2_fh_is_singular_file(file)) - set_loopback_padding(vindev, 0); - - rv = _vb2_fop_release(file, NULL); - - mutex_unlock(&vindev->lock); - - return rv; -} - static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, .open = fh_open, - .release = fh_release, + .release = vb2_fop_release, .unlocked_ioctl = video_ioctl2, .read = vb2_fop_read, .mmap = vb2_fop_mmap, @@ -507,8 +495,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) vindev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width * pixelsize)) / pixelsize; - mgb4_write_reg(video, vindev->config->regs.padding, vindev->padding); - set_loopback_padding(vindev, vindev->padding); return 0; } @@ -853,14 +839,16 @@ static void fpga_init(struct mgb4_vin_dev *vindev) mgb4_write_reg(video, regs->config, 1U << 9); } -#ifdef CONFIG_DEBUG_FS -static void debugfs_init(struct mgb4_vin_dev *vindev) +static void create_debugfs(struct mgb4_vin_dev *vindev) { +#ifdef CONFIG_DEBUG_FS struct mgb4_regs *video = &vindev->mgbdev->video; + struct dentry *entry; - vindev->debugfs = debugfs_create_dir(vindev->vdev.name, - vindev->mgbdev->debugfs); - if (!vindev->debugfs) + if (IS_ERR_OR_NULL(vindev->mgbdev->debugfs)) + return; + entry = debugfs_create_dir(vindev->vdev.name, vindev->mgbdev->debugfs); + if (IS_ERR(entry)) return; vindev->regs[0].name = "CONFIG"; @@ -892,10 +880,9 @@ static void debugfs_init(struct mgb4_vin_dev *vindev) vindev->regset.base = video->membase; vindev->regset.regs = vindev->regs; - debugfs_create_regset32("registers", 0444, vindev->debugfs, - &vindev->regset); -} + debugfs_create_regset32("registers", 0444, entry, &vindev->regset); #endif +} struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id) { @@ -1001,9 +988,7 @@ struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id) goto err_video_dev; } -#ifdef CONFIG_DEBUG_FS - debugfs_init(vindev); -#endif + create_debugfs(vindev); return vindev; @@ -1034,10 +1019,6 @@ void mgb4_vin_free(struct mgb4_vin_dev *vindev) free_irq(vin_irq, vindev); free_irq(err_irq, vindev); -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(vindev->debugfs); -#endif - groups = MGB4_IS_GMSL(vindev->mgbdev) ? mgb4_gmsl_in_groups : mgb4_fpdl3_in_groups; device_remove_groups(&vindev->vdev.dev, groups); diff --git a/drivers/media/pci/mgb4/mgb4_vin.h b/drivers/media/pci/mgb4/mgb4_vin.h index 9693bd0ce180..8fd10c0a5554 100644 --- a/drivers/media/pci/mgb4/mgb4_vin.h +++ b/drivers/media/pci/mgb4/mgb4_vin.h @@ -58,7 +58,6 @@ struct mgb4_vin_dev { const struct mgb4_vin_config *config; #ifdef CONFIG_DEBUG_FS - struct dentry *debugfs; struct debugfs_regset32 regset; struct debugfs_reg32 regs[sizeof(struct mgb4_vin_regs) / 4]; #endif diff --git a/drivers/media/pci/mgb4/mgb4_vout.c b/drivers/media/pci/mgb4/mgb4_vout.c index 998edcbd9723..6b2791e29de1 100644 --- a/drivers/media/pci/mgb4/mgb4_vout.c +++ b/drivers/media/pci/mgb4/mgb4_vout.c @@ -230,8 +230,6 @@ static const struct vb2_ops queue_ops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish }; static int vidioc_querycap(struct file *file, void *priv, @@ -676,14 +674,16 @@ static void fpga_init(struct mgb4_vout_dev *voutdev) (voutdev->config->id + MGB4_VIN_DEVICES) << 2 | 1 << 4); } -#ifdef CONFIG_DEBUG_FS -static void debugfs_init(struct mgb4_vout_dev *voutdev) +static void create_debugfs(struct mgb4_vout_dev *voutdev) { +#ifdef CONFIG_DEBUG_FS struct mgb4_regs *video = &voutdev->mgbdev->video; + struct dentry *entry; - voutdev->debugfs = debugfs_create_dir(voutdev->vdev.name, - voutdev->mgbdev->debugfs); - if (!voutdev->debugfs) + if (IS_ERR_OR_NULL(voutdev->mgbdev->debugfs)) + return; + entry = debugfs_create_dir(voutdev->vdev.name, voutdev->mgbdev->debugfs); + if (IS_ERR(entry)) return; voutdev->regs[0].name = "CONFIG"; @@ -711,10 +711,9 @@ static void debugfs_init(struct mgb4_vout_dev *voutdev) voutdev->regset.base = video->membase; voutdev->regset.regs = voutdev->regs; - debugfs_create_regset32("registers", 0444, voutdev->debugfs, - &voutdev->regset); -} + debugfs_create_regset32("registers", 0444, entry, &voutdev->regset); #endif +} struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id) { @@ -808,9 +807,7 @@ struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id) goto err_video_dev; } -#ifdef CONFIG_DEBUG_FS - debugfs_init(voutdev); -#endif + create_debugfs(voutdev); return voutdev; @@ -833,10 +830,6 @@ void mgb4_vout_free(struct mgb4_vout_dev *voutdev) free_irq(irq, voutdev); -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(voutdev->debugfs); -#endif - groups = MGB4_IS_GMSL(voutdev->mgbdev) ? mgb4_gmsl_out_groups : mgb4_fpdl3_out_groups; device_remove_groups(&voutdev->vdev.dev, groups); diff --git a/drivers/media/pci/mgb4/mgb4_vout.h b/drivers/media/pci/mgb4/mgb4_vout.h index adc8fe1e7ae6..a07eeabdcf34 100644 --- a/drivers/media/pci/mgb4/mgb4_vout.h +++ b/drivers/media/pci/mgb4/mgb4_vout.h @@ -54,7 +54,6 @@ struct mgb4_vout_dev { const struct mgb4_vout_config *config; #ifdef CONFIG_DEBUG_FS - struct dentry *debugfs; struct debugfs_regset32 regset; struct debugfs_reg32 regs[sizeof(struct mgb4_vout_regs) / 4]; #endif diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c b/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c index e90aa1c1584c..34d6d52f1e4e 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c @@ -175,11 +175,11 @@ int netup_spi_init(struct netup_unidvb_dev *ndev) struct spi_controller *ctlr; struct netup_spi *nspi; - ctlr = devm_spi_alloc_master(&ndev->pci_dev->dev, - sizeof(struct netup_spi)); + ctlr = devm_spi_alloc_host(&ndev->pci_dev->dev, + sizeof(struct netup_spi)); if (!ctlr) { dev_err(&ndev->pci_dev->dev, - "%s(): unable to alloc SPI master\n", __func__); + "%s(): unable to alloc SPI host\n", __func__); return -EINVAL; } nspi = spi_controller_get_devdata(ctlr); diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index bbf480ab31ca..8c4f70e4177d 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -78,8 +78,6 @@ static const struct vb2_ops saa7134_empress_qops = { .buf_init = saa7134_ts_buffer_init, .buf_prepare = saa7134_ts_buffer_prepare, .buf_queue = saa7134_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c index 437dbe5e75e2..ec699ea14799 100644 --- a/drivers/media/pci/saa7134/saa7134-ts.c +++ b/drivers/media/pci/saa7134/saa7134-ts.c @@ -166,8 +166,6 @@ struct vb2_ops saa7134_ts_qops = { .buf_init = saa7134_ts_buffer_init, .buf_prepare = saa7134_ts_buffer_prepare, .buf_queue = saa7134_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = saa7134_ts_stop_streaming, }; EXPORT_SYMBOL_GPL(saa7134_ts_qops); diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index 3e773690468b..efa6e4fa423a 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c @@ -161,8 +161,6 @@ const struct vb2_ops saa7134_vbi_qops = { .buf_init = buffer_init, .buf_prepare = buffer_prepare, .buf_queue = saa7134_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = saa7134_vb2_start_streaming, .stop_streaming = saa7134_vb2_stop_streaming, }; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 56b4481a40e6..43e7b006eb59 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -844,8 +844,6 @@ static const struct vb2_ops vb2_qops = { .buf_init = buffer_init, .buf_prepare = buffer_prepare, .buf_queue = saa7134_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = saa7134_vb2_start_streaming, .stop_streaming = saa7134_vb2_stop_streaming, }; diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 0adf3d80f248..5ee59b3844cc 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -756,8 +756,6 @@ static const struct vb2_ops solo_enc_video_qops = { .buf_finish = solo_enc_buf_finish, .start_streaming = solo_enc_start_streaming, .stop_streaming = solo_enc_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int solo_enc_querycap(struct file *file, void *priv, diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index e18cc41fca83..35715b21dbdf 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -365,8 +365,6 @@ static const struct vb2_ops solo_video_qops = { .buf_queue = solo_buf_queue, .start_streaming = solo_start_streaming, .stop_streaming = solo_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int solo_querycap(struct file *file, void *priv, diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 364ce9e57018..3049bad20f14 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -372,8 +372,6 @@ static const struct vb2_ops vip_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c index 4f35c159efe5..0a08708e52b0 100644 --- a/drivers/media/pci/tw5864/tw5864-video.c +++ b/drivers/media/pci/tw5864/tw5864-video.c @@ -471,8 +471,6 @@ static const struct vb2_ops tw5864_video_qops = { .buf_queue = tw5864_buf_queue, .start_streaming = tw5864_start_streaming, .stop_streaming = tw5864_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int tw5864_s_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index cdf5d733b863..77773dec48b8 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -524,8 +524,6 @@ static const struct vb2_ops tw68_video_qops = { .buf_finish = tw68_buf_finish, .start_streaming = tw68_start_streaming, .stop_streaming = tw68_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index 63be95fce83d..785dd797d921 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -579,8 +579,6 @@ static const struct vb2_ops tw686x_video_qops = { .buf_prepare = tw686x_buf_prepare, .start_streaming = tw686x_start_streaming, .stop_streaming = tw686x_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int tw686x_s_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index 5c05e64c71a9..f42f596d3e62 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -950,8 +950,6 @@ static const struct vb2_ops zr_video_qops = { .buf_prepare = zr_vb2_prepare, .start_streaming = zr_vb2_start_streaming, .stop_streaming = zr_vb2_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 73606cee586e..e491399afcc9 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -1509,8 +1509,10 @@ static int allocate_buffers_internal(struct allegro_channel *channel, INIT_LIST_HEAD(&buffer->head); err = allegro_alloc_buffer(dev, buffer, size); - if (err) + if (err) { + kfree(buffer); goto err; + } list_add(&buffer->head, list); } @@ -2895,8 +2897,6 @@ static const struct vb2_ops allegro_queue_ops = { .buf_queue = allegro_buf_queue, .start_streaming = allegro_start_streaming, .stop_streaming = allegro_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int allegro_queue_init(void *priv, @@ -4003,7 +4003,7 @@ static const struct dev_pm_ops allegro_pm_ops = { static struct platform_driver allegro_driver = { .probe = allegro_probe, - .remove_new = allegro_remove, + .remove = allegro_remove, .driver = { .name = "allegro", .of_match_table = allegro_dt_ids, diff --git a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c index 09409908ba5d..0c004bb8ba05 100644 --- a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c +++ b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c @@ -391,8 +391,6 @@ static const struct vb2_ops ge2d_qops = { .buf_queue = ge2d_buf_queue, .start_streaming = ge2d_start_streaming, .stop_streaming = ge2d_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int @@ -1045,7 +1043,7 @@ MODULE_DEVICE_TABLE(of, meson_ge2d_match); static struct platform_driver ge2d_drv = { .probe = ge2d_probe, - .remove_new = ge2d_remove, + .remove = ge2d_remove, .driver = { .name = "meson-ge2d", .of_match_table = meson_ge2d_match, diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index 351b4edc8742..c5c1f1fbaa80 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -52,6 +52,7 @@ struct venc_t { u32 ready_count; u32 enable; u32 stopped; + u32 memory_resource_configured; u32 skipped_count; u32 skipped_bytes; @@ -943,10 +944,19 @@ static int venc_start_session(struct vpu_inst *inst, u32 type) ret = vpu_iface_set_encode_params(inst, &venc->params, 0); if (ret) goto error; + + venc->memory_resource_configured = false; ret = vpu_session_configure_codec(inst); if (ret) goto error; + if (!venc->memory_resource_configured) { + vb2_queue_error(v4l2_m2m_get_src_vq(inst->fh.m2m_ctx)); + vb2_queue_error(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx)); + ret = -ENOMEM; + goto error; + } + inst->state = VPU_CODEC_STATE_CONFIGURED; /*vpu_iface_config_memory_resource*/ @@ -985,6 +995,7 @@ static void venc_cleanup_mem_resource(struct vpu_inst *inst) u32 i; venc = inst->priv; + venc->memory_resource_configured = false; for (i = 0; i < ARRAY_SIZE(venc->enc); i++) vpu_free_dma(&venc->enc[i]); @@ -1048,6 +1059,7 @@ static void venc_request_mem_resource(struct vpu_inst *inst, vpu_iface_config_memory_resource(inst, MEM_RES_REF, i, &venc->ref[i]); for (i = 0; i < act_frame_num; i++) vpu_iface_config_memory_resource(inst, MEM_RES_ACT, i, &venc->act[i]); + venc->memory_resource_configured = true; } static void venc_cleanup_frames(struct venc_t *venc) diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c index 3a2030d02e45..8df85c14ab3f 100644 --- a/drivers/media/platform/amphion/vpu_core.c +++ b/drivers/media/platform/amphion/vpu_core.c @@ -864,7 +864,7 @@ MODULE_DEVICE_TABLE(of, vpu_core_dt_match); static struct platform_driver amphion_vpu_core_driver = { .probe = vpu_core_probe, - .remove_new = vpu_core_remove, + .remove = vpu_core_remove, .driver = { .name = "amphion-vpu-core", .of_match_table = vpu_core_dt_match, diff --git a/drivers/media/platform/amphion/vpu_drv.c b/drivers/media/platform/amphion/vpu_drv.c index 2bf70aafd2ba..efbfd2652721 100644 --- a/drivers/media/platform/amphion/vpu_drv.c +++ b/drivers/media/platform/amphion/vpu_drv.c @@ -151,8 +151,8 @@ err_add_decoder: media_device_cleanup(&vpu->mdev); v4l2_device_unregister(&vpu->v4l2_dev); err_vpu_deinit: - pm_runtime_set_suspended(dev); pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); return ret; } @@ -227,7 +227,7 @@ MODULE_DEVICE_TABLE(of, vpu_dt_match); static struct platform_driver amphion_vpu_driver = { .probe = vpu_probe, - .remove_new = vpu_remove, + .remove = vpu_remove, .driver = { .name = "amphion-vpu", .of_match_table = vpu_dt_match, diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 83db57bc80b7..45707931bc4f 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -646,8 +646,6 @@ static const struct vb2_ops vpu_vb2_ops = { .start_streaming = vpu_vb2_start_streaming, .stop_streaming = vpu_vb2_stop_streaming, .buf_queue = vpu_vb2_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) @@ -841,6 +839,7 @@ int vpu_add_func(struct vpu_dev *vpu, struct vpu_func *func) vfd->fops = vdec_get_fops(); vfd->ioctl_ops = vdec_get_ioctl_ops(); } + video_set_drvdata(vfd, vpu); ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); if (ret) { @@ -848,7 +847,6 @@ int vpu_add_func(struct vpu_dev *vpu, struct vpu_func *func) v4l2_m2m_release(func->m2m_dev); return ret; } - video_set_drvdata(vfd, vpu); func->vfd = vfd; ret = v4l2_m2m_register_media_controller(func->m2m_dev, func->vfd, func->function); diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c index fc6050e3be0d..54cae0da9aca 100644 --- a/drivers/media/platform/aspeed/aspeed-video.c +++ b/drivers/media/platform/aspeed/aspeed-video.c @@ -1891,8 +1891,6 @@ static void aspeed_video_buf_queue(struct vb2_buffer *vb) static const struct vb2_ops aspeed_video_vb2_ops = { .queue_setup = aspeed_video_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = aspeed_video_buf_prepare, .start_streaming = aspeed_video_start_streaming, .stop_streaming = aspeed_video_stop_streaming, @@ -2226,7 +2224,7 @@ static struct platform_driver aspeed_video_driver = { .of_match_table = aspeed_video_of_match, }, .probe = aspeed_video_probe, - .remove_new = aspeed_video_remove, + .remove = aspeed_video_remove, }; module_platform_driver(aspeed_video_driver); diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 5c823d3f9cc0..0d1c39347529 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -526,8 +526,6 @@ static const struct vb2_ops isi_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int isi_g_fmt_vid_cap(struct file *file, void *priv, @@ -1367,7 +1365,7 @@ static struct platform_driver atmel_isi_driver = { .pm = &atmel_isi_dev_pm_ops, }, .probe = atmel_isi_probe, - .remove_new = atmel_isi_remove, + .remove = atmel_isi_remove, }; module_platform_driver(atmel_isi_driver); diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c index a1d93c14553d..3aed0e493c81 100644 --- a/drivers/media/platform/broadcom/bcm2835-unicam.c +++ b/drivers/media/platform/broadcom/bcm2835-unicam.c @@ -1801,8 +1801,6 @@ static void unicam_buffer_queue(struct vb2_buffer *vb) static const struct vb2_ops unicam_video_qops = { .queue_setup = unicam_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = unicam_buffer_prepare, .start_streaming = unicam_start_streaming, .stop_streaming = unicam_stop_streaming, @@ -2724,7 +2722,7 @@ MODULE_DEVICE_TABLE(of, unicam_of_match); static struct platform_driver unicam_driver = { .probe = unicam_probe, - .remove_new = unicam_remove, + .remove = unicam_remove, .driver = { .name = UNICAM_MODULE_NAME, .pm = pm_ptr(&unicam_pm_ops), diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 6f7d27a48eff..4d64df829e75 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -751,7 +751,7 @@ MODULE_DEVICE_TABLE(of, csi2rx_of_table); static struct platform_driver csi2rx_driver = { .probe = csi2rx_probe, - .remove_new = csi2rx_remove, + .remove = csi2rx_remove, .driver = { .name = "cdns-csi2rx", diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c index 3d98f91f1bee..e22b133f346d 100644 --- a/drivers/media/platform/cadence/cdns-csi2tx.c +++ b/drivers/media/platform/cadence/cdns-csi2tx.c @@ -644,7 +644,7 @@ static void csi2tx_remove(struct platform_device *pdev) static struct platform_driver csi2tx_driver = { .probe = csi2tx_probe, - .remove_new = csi2tx_remove, + .remove = csi2tx_remove, .driver = { .name = "cdns-csi2tx", diff --git a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c index 7da0194ec850..289a076c3bcc 100644 --- a/drivers/media/platform/chips-media/coda/coda-common.c +++ b/drivers/media/platform/chips-media/coda/coda-common.c @@ -2171,8 +2171,6 @@ static const struct vb2_ops coda_qops = { .buf_queue = coda_buf_queue, .start_streaming = coda_start_streaming, .stop_streaming = coda_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int coda_s_ctrl(struct v4l2_ctrl *ctrl) @@ -3346,7 +3344,7 @@ static const struct dev_pm_ops coda_pm_ops = { static struct platform_driver coda_driver = { .probe = coda_probe, - .remove_new = coda_remove, + .remove = coda_remove, .driver = { .name = CODA_NAME, .of_match_table = coda_dt_ids, diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c index d60841c54a80..2c9d8cbca6e4 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.c +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c @@ -7,6 +7,8 @@ #include "wave5-helper.h" +#define DEFAULT_BS_SIZE(width, height) ((width) * (height) / 8 * 3) + const char *state_to_str(enum vpu_instance_state state) { switch (state) { @@ -58,7 +60,6 @@ int wave5_vpu_release_device(struct file *filp, char *name) { struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data); - struct vpu_device *dev = inst->dev; int ret = 0; v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); @@ -78,18 +79,6 @@ int wave5_vpu_release_device(struct file *filp, } wave5_cleanup_instance(inst); - if (dev->irq < 0) { - ret = mutex_lock_interruptible(&dev->dev_lock); - if (ret) - return ret; - - if (list_empty(&dev->instances)) { - dev_dbg(dev->dev, "Disabling the hrtimer\n"); - hrtimer_cancel(&dev->hrtimer); - } - - mutex_unlock(&dev->dev_lock); - } return ret; } @@ -230,3 +219,25 @@ void wave5_return_bufs(struct vb2_queue *q, u32 state) v4l2_m2m_buf_done(vbuf, state); } } + +void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, + int pix_fmt_type, + unsigned int width, + unsigned int height, + const struct v4l2_frmsize_stepwise *frmsize) +{ + v4l2_apply_frmsize_constraints(&width, &height, frmsize); + + if (pix_fmt_type == VPU_FMT_TYPE_CODEC) { + pix_mp->width = width; + pix_mp->height = height; + pix_mp->num_planes = 1; + pix_mp->plane_fmt[0].bytesperline = 0; + pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_BS_SIZE(width, height), + pix_mp->plane_fmt[0].sizeimage); + } else { + v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, width, height); + } + pix_mp->flags = 0; + pix_mp->field = V4L2_FIELD_NONE; +} diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.h b/drivers/media/platform/chips-media/wave5/wave5-helper.h index 6cee1c14d3ce..9937fce553fc 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.h +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.h @@ -28,4 +28,9 @@ const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx, const struct vpu_format fmt_list[MAX_FMTS]); enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type); void wave5_return_bufs(struct vb2_queue *q, u32 state); +void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, + int pix_fmt_type, + unsigned int width, + unsigned int height, + const struct v4l2_frmsize_stepwise *frmsize); #endif diff --git a/drivers/media/platform/chips-media/wave5/wave5-hw.c b/drivers/media/platform/chips-media/wave5/wave5-hw.c index c89aafabc742..c8a905994109 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-hw.c +++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c @@ -23,6 +23,15 @@ #define W521_FEATURE_AVC_ENCODER BIT(1) #define W521_FEATURE_HEVC_ENCODER BIT(0) +#define ENC_AVC_INTRA_IDR_PARAM_MASK 0x7ff +#define ENC_AVC_INTRA_PERIOD_SHIFT 6 +#define ENC_AVC_IDR_PERIOD_SHIFT 17 +#define ENC_AVC_FORCED_IDR_HEADER_SHIFT 28 + +#define ENC_HEVC_INTRA_QP_SHIFT 3 +#define ENC_HEVC_FORCED_IDR_HEADER_SHIFT 9 +#define ENC_HEVC_INTRA_PERIOD_SHIFT 16 + /* Decoder support fields */ #define W521_FEATURE_AVC_DECODER BIT(3) #define W521_FEATURE_HEVC_DECODER BIT(2) @@ -35,7 +44,7 @@ #define REMAP_CTRL_MAX_SIZE_BITS ((W5_REMAP_MAX_SIZE >> 12) & 0x1ff) #define REMAP_CTRL_REGISTER_VALUE(index) ( \ - (BIT(31) | (index << 12) | BIT(11) | REMAP_CTRL_MAX_SIZE_BITS) \ + (BIT(31) | ((index) << 12) | BIT(11) | REMAP_CTRL_MAX_SIZE_BITS)\ ) #define FASTIO_ADDRESS_MASK GENMASK(15, 0) @@ -1219,8 +1228,8 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size) return setup_wave5_properties(dev); } -static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code, - size_t size) +int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code, + size_t size) { u32 reg_val; struct vpu_buf *common_vb; @@ -1772,12 +1781,19 @@ int wave5_vpu_enc_init_seq(struct vpu_instance *inst) if (inst->std == W_AVC_ENC) vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM, p_param->intra_qp | - ((p_param->intra_period & 0x7ff) << 6) | - ((p_param->avc_idr_period & 0x7ff) << 17)); + ((p_param->intra_period & ENC_AVC_INTRA_IDR_PARAM_MASK) + << ENC_AVC_INTRA_PERIOD_SHIFT) | + ((p_param->avc_idr_period & ENC_AVC_INTRA_IDR_PARAM_MASK) + << ENC_AVC_IDR_PERIOD_SHIFT) | + (p_param->forced_idr_header_enable + << ENC_AVC_FORCED_IDR_HEADER_SHIFT)); else if (inst->std == W_HEVC_ENC) vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM, - p_param->decoding_refresh_type | (p_param->intra_qp << 3) | - (p_param->intra_period << 16)); + p_param->decoding_refresh_type | + (p_param->intra_qp << ENC_HEVC_INTRA_QP_SHIFT) | + (p_param->forced_idr_header_enable + << ENC_HEVC_FORCED_IDR_HEADER_SHIFT) | + (p_param->intra_period << ENC_HEVC_INTRA_PERIOD_SHIFT)); reg_val = (p_param->rdo_skip << 2) | (p_param->lambda_scaling_enable << 3) | diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c index 0c5c9a8de91f..d3ff420c52ce 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -5,116 +5,98 @@ * Copyright (C) 2021-2023 CHIPS&MEDIA INC */ +#include <linux/pm_runtime.h> #include "wave5-helper.h" #define VPU_DEC_DEV_NAME "C&M Wave5 VPU decoder" #define VPU_DEC_DRV_NAME "wave5-dec" -#define DEFAULT_SRC_SIZE(width, height) ({ \ - (width) * (height) / 8 * 3; \ -}) +static const struct v4l2_frmsize_stepwise dec_hevc_frmsize = { + .min_width = W5_MIN_DEC_PIC_8_WIDTH, + .max_width = W5_MAX_DEC_PIC_WIDTH, + .step_width = W5_DEC_CODEC_STEP_WIDTH, + .min_height = W5_MIN_DEC_PIC_8_HEIGHT, + .max_height = W5_MAX_DEC_PIC_HEIGHT, + .step_height = W5_DEC_CODEC_STEP_HEIGHT, +}; + +static const struct v4l2_frmsize_stepwise dec_h264_frmsize = { + .min_width = W5_MIN_DEC_PIC_32_WIDTH, + .max_width = W5_MAX_DEC_PIC_WIDTH, + .step_width = W5_DEC_CODEC_STEP_WIDTH, + .min_height = W5_MIN_DEC_PIC_32_HEIGHT, + .max_height = W5_MAX_DEC_PIC_HEIGHT, + .step_height = W5_DEC_CODEC_STEP_HEIGHT, +}; + +static const struct v4l2_frmsize_stepwise dec_raw_frmsize = { + .min_width = W5_MIN_DEC_PIC_8_WIDTH, + .max_width = W5_MAX_DEC_PIC_WIDTH, + .step_width = W5_DEC_RAW_STEP_WIDTH, + .min_height = W5_MIN_DEC_PIC_8_HEIGHT, + .max_height = W5_MAX_DEC_PIC_HEIGHT, + .step_height = W5_DEC_RAW_STEP_HEIGHT, +}; static const struct vpu_format dec_fmt_list[FMT_TYPES][MAX_FMTS] = { [VPU_FMT_TYPE_CODEC] = { { .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_hevc_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_H264, - .max_width = 8192, - .min_width = 32, - .max_height = 4320, - .min_height = 32, + .v4l2_frmsize = &dec_h264_frmsize, }, }, [VPU_FMT_TYPE_RAW] = { { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV12, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV21, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV16, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV61, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, } }; @@ -233,74 +215,6 @@ static void wave5_handle_src_buffer(struct vpu_instance *inst, dma_addr_t rd_ptr inst->remaining_consumed_bytes = consumed_bytes; } -static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width, - unsigned int height) -{ - switch (pix_mp->pixelformat) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height * 3 / 2; - break; - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height * 2; - break; - case V4L2_PIX_FMT_YUV420M: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[1].sizeimage = width * height / 4; - pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[2].sizeimage = width * height / 4; - break; - case V4L2_PIX_FMT_NV12M: - case V4L2_PIX_FMT_NV21M: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[1].sizeimage = width * height / 2; - break; - case V4L2_PIX_FMT_YUV422M: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[1].sizeimage = width * height / 2; - pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[2].sizeimage = width * height / 2; - break; - case V4L2_PIX_FMT_NV16M: - case V4L2_PIX_FMT_NV61M: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[1].sizeimage = width * height; - break; - default: - pix_mp->width = width; - pix_mp->height = height; - pix_mp->plane_fmt[0].bytesperline = 0; - pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_SRC_SIZE(width, height), - pix_mp->plane_fmt[0].sizeimage); - break; - } -} - static int start_decode(struct vpu_instance *inst, u32 *fail_res) { struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; @@ -388,6 +302,8 @@ static int handle_dynamic_resolution_change(struct vpu_instance *inst) } if (p_dec_info->initial_info_obtained) { + const struct vpu_format *vpu_fmt; + inst->conf_win.left = initial_info->pic_crop_rect.left; inst->conf_win.top = initial_info->pic_crop_rect.top; inst->conf_win.width = initial_info->pic_width - @@ -395,10 +311,27 @@ static int handle_dynamic_resolution_change(struct vpu_instance *inst) inst->conf_win.height = initial_info->pic_height - initial_info->pic_crop_rect.top - initial_info->pic_crop_rect.bottom; - wave5_update_pix_fmt(&inst->src_fmt, initial_info->pic_width, - initial_info->pic_height); - wave5_update_pix_fmt(&inst->dst_fmt, initial_info->pic_width, - initial_info->pic_height); + vpu_fmt = wave5_find_vpu_fmt(inst->src_fmt.pixelformat, + dec_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->src_fmt, + VPU_FMT_TYPE_CODEC, + initial_info->pic_width, + initial_info->pic_height, + vpu_fmt->v4l2_frmsize); + + vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, + dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->dst_fmt, + VPU_FMT_TYPE_RAW, + initial_info->pic_width, + initial_info->pic_height, + vpu_fmt->v4l2_frmsize); } v4l2_event_queue_fh(fh, &vpu_event_src_ch); @@ -518,6 +451,8 @@ static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst) if (q_status.report_queue_count == 0 && (q_status.instance_queue_count == 0 || dec_info.sequence_changed)) { dev_dbg(inst->dev->dev, "%s: finishing job.\n", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } } @@ -545,12 +480,12 @@ static int wave5_vpu_dec_enum_framesizes(struct file *f, void *fh, struct v4l2_f } fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; - fsize->stepwise.min_width = vpu_fmt->min_width; - fsize->stepwise.max_width = vpu_fmt->max_width; - fsize->stepwise.step_width = 1; - fsize->stepwise.min_height = vpu_fmt->min_height; - fsize->stepwise.max_height = vpu_fmt->max_height; - fsize->stepwise.step_height = 1; + fsize->stepwise.min_width = vpu_fmt->v4l2_frmsize->min_width; + fsize->stepwise.max_width = vpu_fmt->v4l2_frmsize->max_width; + fsize->stepwise.step_width = W5_DEC_CODEC_STEP_WIDTH; + fsize->stepwise.min_height = vpu_fmt->v4l2_frmsize->min_height; + fsize->stepwise.max_height = vpu_fmt->v4l2_frmsize->max_height; + fsize->stepwise.step_height = W5_DEC_CODEC_STEP_HEIGHT; return 0; } @@ -573,6 +508,7 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo { struct vpu_instance *inst = wave5_to_vpu_inst(fh); struct dec_info *p_dec_info = &inst->codec_info->dec_info; + const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; int width, height; @@ -586,14 +522,12 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo width = inst->dst_fmt.width; height = inst->dst_fmt.height; f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; - f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes; + frmsize = &dec_raw_frmsize; } else { - const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt); - - width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); - height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; - f->fmt.pix_mp.num_planes = info->mem_planes; + frmsize = vpu_fmt->v4l2_frmsize; } if (p_dec_info->initial_info_obtained) { @@ -601,9 +535,8 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo height = inst->dst_fmt.height; } - wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); - f->fmt.pix_mp.flags = 0; - f->fmt.pix_mp.field = V4L2_FIELD_NONE; + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_RAW, + width, height, frmsize); f->fmt.pix_mp.colorspace = inst->colorspace; f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; f->fmt.pix_mp.quantization = inst->quantization; @@ -715,7 +648,9 @@ static int wave5_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_f static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; + int width, height; dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u colorspace: %u field: %u\n", @@ -724,20 +659,19 @@ static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_fo vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, dec_fmt_list[VPU_FMT_TYPE_CODEC]); if (!vpu_fmt) { + width = inst->src_fmt.width; + height = inst->src_fmt.height; f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; - f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes; - wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height); + frmsize = &dec_hevc_frmsize; } else { - int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); - int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); - + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; - f->fmt.pix_mp.num_planes = 1; - wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); + frmsize = vpu_fmt->v4l2_frmsize; } - f->fmt.pix_mp.flags = 0; - f->fmt.pix_mp.field = V4L2_FIELD_NONE; + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_CODEC, + width, height, frmsize); return 0; } @@ -745,6 +679,7 @@ static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_fo static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; int i, ret; dev_dbg(inst->dev->dev, @@ -779,7 +714,13 @@ static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_form inst->quantization = f->fmt.pix_mp.quantization; inst->xfer_func = f->fmt.pix_mp.xfer_func; - wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height); + vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->dst_fmt, VPU_FMT_TYPE_RAW, + f->fmt.pix_mp.width, f->fmt.pix_mp.height, + vpu_fmt->v4l2_frmsize); return 0; } @@ -1002,6 +943,7 @@ static int wave5_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buff struct vpu_instance *inst = vb2_get_drv_priv(q); struct v4l2_pix_format_mplane inst_format = (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt; + unsigned int i; dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__, *num_buffers, *num_planes, q->type); @@ -1015,31 +957,9 @@ static int wave5_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buff if (*num_buffers < inst->fbc_buf_count) *num_buffers = inst->fbc_buf_count; - if (*num_planes == 1) { - if (inst->output_format == FORMAT_422) - sizes[0] = inst_format.width * inst_format.height * 2; - else - sizes[0] = inst_format.width * inst_format.height * 3 / 2; - dev_dbg(inst->dev->dev, "%s: size[0]: %u\n", __func__, sizes[0]); - } else if (*num_planes == 2) { - sizes[0] = inst_format.width * inst_format.height; - if (inst->output_format == FORMAT_422) - sizes[1] = inst_format.width * inst_format.height; - else - sizes[1] = inst_format.width * inst_format.height / 2; - dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u\n", - __func__, sizes[0], sizes[1]); - } else if (*num_planes == 3) { - sizes[0] = inst_format.width * inst_format.height; - if (inst->output_format == FORMAT_422) { - sizes[1] = inst_format.width * inst_format.height / 2; - sizes[2] = inst_format.width * inst_format.height / 2; - } else { - sizes[1] = inst_format.width * inst_format.height / 4; - sizes[2] = inst_format.width * inst_format.height / 4; - } - dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u | size[2]: %u\n", - __func__, sizes[0], sizes[1], sizes[2]); + for (i = 0; i < *num_planes; i++) { + sizes[i] = inst_format.plane_fmt[i].sizeimage; + dev_dbg(inst->dev->dev, "%s: size[%u]: %u\n", __func__, i, sizes[i]); } } @@ -1398,6 +1318,7 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count int ret = 0; dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + pm_runtime_resume_and_get(inst->dev->dev); v4l2_m2m_update_start_streaming_state(m2m_ctx, q); @@ -1429,13 +1350,15 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count if (ret) goto return_buffers; } - + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); return ret; free_bitstream_vbuf: wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf); return_buffers: wave5_return_bufs(q, VB2_BUF_STATE_QUEUED); + pm_runtime_put_autosuspend(inst->dev->dev); return ret; } @@ -1521,6 +1444,7 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) bool check_cmd = TRUE; dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + pm_runtime_resume_and_get(inst->dev->dev); while (check_cmd) { struct queue_status_info q_status; @@ -1544,12 +1468,13 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) streamoff_output(q); else streamoff_capture(q); + + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); } static const struct vb2_ops wave5_vpu_dec_vb2_ops = { .queue_setup = wave5_vpu_dec_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_queue = wave5_vpu_dec_buf_queue, .start_streaming = wave5_vpu_dec_start_streaming, .stop_streaming = wave5_vpu_dec_stop_streaming, @@ -1558,20 +1483,15 @@ static const struct vb2_ops wave5_vpu_dec_vb2_ops = { static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, struct v4l2_pix_format_mplane *dst_fmt) { - unsigned int dst_pix_fmt = dec_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; - const struct v4l2_format_info *dst_fmt_info = v4l2_format_info(dst_pix_fmt); - src_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt; - src_fmt->field = V4L2_FIELD_NONE; - src_fmt->flags = 0; - src_fmt->num_planes = 1; - wave5_update_pix_fmt(src_fmt, 720, 480); - - dst_fmt->pixelformat = dst_pix_fmt; - dst_fmt->field = V4L2_FIELD_NONE; - dst_fmt->flags = 0; - dst_fmt->num_planes = dst_fmt_info->mem_planes; - wave5_update_pix_fmt(dst_fmt, 736, 480); + wave5_update_pix_fmt(src_fmt, VPU_FMT_TYPE_CODEC, + W5_DEF_DEC_PIC_WIDTH, W5_DEF_DEC_PIC_HEIGHT, + &dec_hevc_frmsize); + + dst_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; + wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_RAW, + W5_DEF_DEC_PIC_WIDTH, W5_DEF_DEC_PIC_HEIGHT, + &dec_raw_frmsize); } static int wave5_vpu_dec_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) @@ -1630,7 +1550,7 @@ static void wave5_vpu_dec_device_run(void *priv) int ret = 0; dev_dbg(inst->dev->dev, "%s: Fill the ring buffer with new bitstream data", __func__); - + pm_runtime_resume_and_get(inst->dev->dev); ret = fill_ringbuffer(inst); if (ret) { dev_warn(inst->dev->dev, "Filling ring buffer failed\n"); @@ -1713,6 +1633,8 @@ static void wave5_vpu_dec_device_run(void *priv) finish_job_and_return: dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } @@ -1879,9 +1801,8 @@ static int wave5_vpu_open_dec(struct file *filp) if (ret) goto cleanup_inst; - if (dev->irq < 0 && !hrtimer_active(&dev->hrtimer) && list_empty(&dev->instances)) - hrtimer_start(&dev->hrtimer, ns_to_ktime(dev->vpu_poll_interval * NSEC_PER_MSEC), - HRTIMER_MODE_REL_PINNED); + if (list_empty(&dev->instances)) + pm_runtime_use_autosuspend(inst->dev->dev); list_add_tail(&inst->list, &dev->instances); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c index 3e35a05c2d8d..1e5fc5f8b856 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -5,70 +5,90 @@ * Copyright (C) 2021-2023 CHIPS&MEDIA INC */ +#include <linux/pm_runtime.h> #include "wave5-helper.h" #define VPU_ENC_DEV_NAME "C&M Wave5 VPU encoder" #define VPU_ENC_DRV_NAME "wave5-enc" +static const struct v4l2_frmsize_stepwise enc_frmsize[FMT_TYPES] = { + [VPU_FMT_TYPE_CODEC] = { + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .step_width = W5_ENC_CODEC_STEP_WIDTH, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .step_height = W5_ENC_CODEC_STEP_HEIGHT, + }, + [VPU_FMT_TYPE_RAW] = { + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .step_width = W5_ENC_RAW_STEP_WIDTH, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .step_height = W5_ENC_RAW_STEP_HEIGHT, + }, +}; + static const struct vpu_format enc_fmt_list[FMT_TYPES][MAX_FMTS] = { [VPU_FMT_TYPE_CODEC] = { { .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_H264, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC], }, }, [VPU_FMT_TYPE_RAW] = { { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV12, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV21, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, } }; @@ -105,46 +125,6 @@ invalid_state_switch: return -EINVAL; } -static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width, - unsigned int height) -{ - switch (pix_mp->pixelformat) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - pix_mp->width = width; - pix_mp->height = height; - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height * 3 / 2; - break; - case V4L2_PIX_FMT_YUV420M: - pix_mp->width = width; - pix_mp->height = height; - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 4; - pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[2].sizeimage = round_up(width, 32) * height / 4; - break; - case V4L2_PIX_FMT_NV12M: - case V4L2_PIX_FMT_NV21M: - pix_mp->width = width; - pix_mp->height = height; - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 2; - break; - default: - pix_mp->width = width; - pix_mp->height = height; - pix_mp->plane_fmt[0].bytesperline = 0; - pix_mp->plane_fmt[0].sizeimage = width * height / 8 * 3; - break; - } -} - static int start_encode(struct vpu_instance *inst, u32 *fail_res) { struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; @@ -153,13 +133,26 @@ static int start_encode(struct vpu_instance *inst, u32 *fail_res) struct vb2_v4l2_buffer *dst_buf; struct frame_buffer frame_buf; struct enc_param pic_param; - u32 stride = ALIGN(inst->dst_fmt.width, 32); - u32 luma_size = (stride * inst->dst_fmt.height); - u32 chroma_size = ((stride / 2) * (inst->dst_fmt.height / 2)); + const struct v4l2_format_info *info; + u32 stride = inst->src_fmt.plane_fmt[0].bytesperline; + u32 luma_size = 0; + u32 chroma_size = 0; memset(&pic_param, 0, sizeof(struct enc_param)); memset(&frame_buf, 0, sizeof(struct frame_buffer)); + info = v4l2_format_info(inst->src_fmt.pixelformat); + if (!info) + return -EINVAL; + + if (info->mem_planes == 1) { + luma_size = stride * inst->dst_fmt.height; + chroma_size = luma_size / (info->hdiv * info->vdiv); + } else { + luma_size = inst->src_fmt.plane_fmt[0].sizeimage; + chroma_size = inst->src_fmt.plane_fmt[1].sizeimage; + } + dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx); if (!dst_buf) { dev_dbg(inst->dev->dev, "%s: No destination buffer found\n", __func__); @@ -359,13 +352,8 @@ static int wave5_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_f return -EINVAL; } - fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; - fsize->stepwise.min_width = vpu_fmt->min_width; - fsize->stepwise.max_width = vpu_fmt->max_width; - fsize->stepwise.step_width = 1; - fsize->stepwise.min_height = vpu_fmt->min_height; - fsize->stepwise.max_height = vpu_fmt->max_height; - fsize->stepwise.step_height = 1; + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = enc_frmsize[VPU_FMT_TYPE_CODEC]; return 0; } @@ -390,7 +378,9 @@ static int wave5_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_f static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; + int width, height; dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, @@ -398,20 +388,19 @@ static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]); if (!vpu_fmt) { + width = inst->dst_fmt.width; + height = inst->dst_fmt.height; f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; - f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes; - wave5_update_pix_fmt(&f->fmt.pix_mp, inst->dst_fmt.width, inst->dst_fmt.height); + frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC]; } else { - int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); - int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); - + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; - f->fmt.pix_mp.num_planes = 1; - wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); + frmsize = vpu_fmt->v4l2_frmsize; } - f->fmt.pix_mp.flags = 0; - f->fmt.pix_mp.field = V4L2_FIELD_NONE; + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_CODEC, + width, height, frmsize); f->fmt.pix_mp.colorspace = inst->colorspace; f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; f->fmt.pix_mp.quantization = inst->quantization; @@ -498,7 +487,9 @@ static int wave5_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_f static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; + int width, height; dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, @@ -506,28 +497,27 @@ static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_fo vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_RAW]); if (!vpu_fmt) { + width = inst->src_fmt.width; + height = inst->src_fmt.height; f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; - f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes; - wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height); + frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW]; } else { - int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); - int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); - const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt); - + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; - f->fmt.pix_mp.num_planes = info->mem_planes; - wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); + frmsize = vpu_fmt->v4l2_frmsize; } - f->fmt.pix_mp.flags = 0; - f->fmt.pix_mp.field = V4L2_FIELD_NONE; - + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_RAW, + width, height, frmsize); return 0; } static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + const struct v4l2_format_info *info; int i, ret; dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", @@ -549,16 +539,20 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form inst->src_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; } - if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 || - inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M) { - inst->cbcr_interleave = true; - inst->nv21 = false; - } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 || - inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M) { - inst->cbcr_interleave = true; + info = v4l2_format_info(inst->src_fmt.pixelformat); + if (!info) + return -EINVAL; + + inst->cbcr_interleave = (info->comp_planes == 2) ? true : false; + + switch (inst->src_fmt.pixelformat) { + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV21M: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV61M: inst->nv21 = true; - } else { - inst->cbcr_interleave = false; + break; + default: inst->nv21 = false; } @@ -567,7 +561,15 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form inst->quantization = f->fmt.pix_mp.quantization; inst->xfer_func = f->fmt.pix_mp.xfer_func; - wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height); + vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->dst_fmt, VPU_FMT_TYPE_CODEC, + f->fmt.pix_mp.width, f->fmt.pix_mp.height, + vpu_fmt->v4l2_frmsize); + inst->conf_win.width = inst->dst_fmt.width; + inst->conf_win.height = inst->dst_fmt.height; return 0; } @@ -583,12 +585,17 @@ static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_se switch (s->target) { case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP: s->r.left = 0; s->r.top = 0; s->r.width = inst->dst_fmt.width; s->r.height = inst->dst_fmt.height; break; + case V4L2_SEL_TGT_CROP: + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->conf_win.width; + s->r.height = inst->conf_win.height; + break; default: return -EINVAL; } @@ -611,8 +618,10 @@ static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_se s->r.left = 0; s->r.top = 0; - s->r.width = inst->src_fmt.width; - s->r.height = inst->src_fmt.height; + s->r.width = min(s->r.width, inst->dst_fmt.width); + s->r.height = min(s->r.height, inst->dst_fmt.height); + + inst->conf_win = s->r; return 0; } @@ -1061,6 +1070,9 @@ static int wave5_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: inst->enc_param.entropy_coding_mode = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: + inst->enc_param.forced_idr_header_enable = ctrl->val; + break; case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: break; default: @@ -1125,13 +1137,23 @@ static void wave5_vpu_enc_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(m2m_ctx, vbuf); } -static void wave5_set_enc_openparam(struct enc_open_param *open_param, - struct vpu_instance *inst) +static int wave5_set_enc_openparam(struct enc_open_param *open_param, + struct vpu_instance *inst) { struct enc_wave_param input = inst->enc_param; + const struct v4l2_format_info *info; u32 num_ctu_row = ALIGN(inst->dst_fmt.height, 64) / 64; u32 num_mb_row = ALIGN(inst->dst_fmt.height, 16) / 16; + info = v4l2_format_info(inst->src_fmt.pixelformat); + if (!info) + return -EINVAL; + + if (info->hdiv == 2 && info->vdiv == 1) + open_param->src_format = FORMAT_422; + else + open_param->src_format = FORMAT_420; + open_param->wave_param.gop_preset_idx = PRESET_IDX_IPP_SINGLE; open_param->wave_param.hvs_qp_scale = 2; open_param->wave_param.hvs_max_delta_qp = 10; @@ -1147,8 +1169,8 @@ static void wave5_set_enc_openparam(struct enc_open_param *open_param, open_param->wave_param.lambda_scaling_enable = 1; open_param->line_buf_int_en = true; - open_param->pic_width = inst->dst_fmt.width; - open_param->pic_height = inst->dst_fmt.height; + open_param->pic_width = inst->conf_win.width; + open_param->pic_height = inst->conf_win.height; open_param->frame_rate_info = inst->frame_rate; open_param->rc_enable = inst->rc_enable; if (inst->rc_enable) { @@ -1219,6 +1241,9 @@ static void wave5_set_enc_openparam(struct enc_open_param *open_param, else open_param->wave_param.intra_refresh_arg = num_ctu_row; } + open_param->wave_param.forced_idr_header_enable = input.forced_idr_header_enable; + + return 0; } static int initialize_sequence(struct vpu_instance *inst) @@ -1306,6 +1331,7 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; int ret = 0; + pm_runtime_resume_and_get(inst->dev->dev); v4l2_m2m_update_start_streaming_state(m2m_ctx, q); if (inst->state == VPU_INST_STATE_NONE && q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { @@ -1313,7 +1339,12 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count memset(&open_param, 0, sizeof(struct enc_open_param)); - wave5_set_enc_openparam(&open_param, inst); + ret = wave5_set_enc_openparam(&open_param, inst); + if (ret) { + dev_dbg(inst->dev->dev, "%s: wave5_set_enc_openparam, fail: %d\n", + __func__, ret); + goto return_buffers; + } ret = wave5_vpu_enc_open(inst, &open_param); if (ret) { @@ -1360,9 +1391,13 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count if (ret) goto return_buffers; + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); return 0; return_buffers: wave5_return_bufs(q, VB2_BUF_STATE_QUEUED); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); return ret; } @@ -1404,6 +1439,7 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q) */ dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + pm_runtime_resume_and_get(inst->dev->dev); if (wave5_vpu_both_queues_are_streaming(inst)) switch_state(inst, VPU_INST_STATE_STOP); @@ -1428,12 +1464,13 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q) streamoff_output(inst, q); else streamoff_capture(inst, q); + + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); } static const struct vb2_ops wave5_vpu_enc_vb2_ops = { .queue_setup = wave5_vpu_enc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_queue = wave5_vpu_enc_buf_queue, .start_streaming = wave5_vpu_enc_start_streaming, .stop_streaming = wave5_vpu_enc_stop_streaming, @@ -1442,20 +1479,15 @@ static const struct vb2_ops wave5_vpu_enc_vb2_ops = { static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, struct v4l2_pix_format_mplane *dst_fmt) { - unsigned int src_pix_fmt = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; - const struct v4l2_format_info *src_fmt_info = v4l2_format_info(src_pix_fmt); - - src_fmt->pixelformat = src_pix_fmt; - src_fmt->field = V4L2_FIELD_NONE; - src_fmt->flags = 0; - src_fmt->num_planes = src_fmt_info->mem_planes; - wave5_update_pix_fmt(src_fmt, 416, 240); + src_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; + wave5_update_pix_fmt(src_fmt, VPU_FMT_TYPE_RAW, + W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT, + &enc_frmsize[VPU_FMT_TYPE_RAW]); dst_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt; - dst_fmt->field = V4L2_FIELD_NONE; - dst_fmt->flags = 0; - dst_fmt->num_planes = 1; - wave5_update_pix_fmt(dst_fmt, 416, 240); + wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_CODEC, + W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT, + &enc_frmsize[VPU_FMT_TYPE_CODEC]); } static int wave5_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) @@ -1474,6 +1506,7 @@ static void wave5_vpu_enc_device_run(void *priv) u32 fail_res = 0; int ret = 0; + pm_runtime_resume_and_get(inst->dev->dev); switch (inst->state) { case VPU_INST_STATE_PIC_RUN: ret = start_encode(inst, &fail_res); @@ -1487,6 +1520,8 @@ static void wave5_vpu_enc_device_run(void *priv) break; } dev_dbg(inst->dev->dev, "%s: leave with active job", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); return; default: WARN(1, "Execution of a job in state %s is invalid.\n", @@ -1494,6 +1529,8 @@ static void wave5_vpu_enc_device_run(void *priv) break; } dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } @@ -1701,6 +1738,9 @@ static int wave5_vpu_open_enc(struct file *filp) 0, 1, 1, 0); v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, + 0, 1, 1, 0); if (v4l2_ctrl_hdl->error) { ret = -ENODEV; @@ -1711,6 +1751,8 @@ static int wave5_vpu_open_enc(struct file *filp) v4l2_ctrl_handler_setup(v4l2_ctrl_hdl); wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt); + inst->conf_win.width = inst->dst_fmt.width; + inst->conf_win.height = inst->dst_fmt.height; inst->colorspace = V4L2_COLORSPACE_REC709; inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; inst->quantization = V4L2_QUANTIZATION_DEFAULT; @@ -1732,9 +1774,8 @@ static int wave5_vpu_open_enc(struct file *filp) if (ret) goto cleanup_inst; - if (dev->irq < 0 && !hrtimer_active(&dev->hrtimer) && list_empty(&dev->instances)) - hrtimer_start(&dev->hrtimer, ns_to_ktime(dev->vpu_poll_interval * NSEC_PER_MSEC), - HRTIMER_MODE_REL_PINNED); + if (list_empty(&dev->instances)) + pm_runtime_use_autosuspend(inst->dev->dev); list_add_tail(&inst->list, &dev->instances); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c index 7273254ecb03..6b294a2d6717 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c @@ -10,6 +10,7 @@ #include <linux/clk.h> #include <linux/firmware.h> #include <linux/interrupt.h> +#include <linux/pm_runtime.h> #include <linux/reset.h> #include "wave5-vpu.h" #include "wave5-regdefine.h" @@ -153,6 +154,45 @@ static int wave5_vpu_load_firmware(struct device *dev, const char *fw_name, return 0; } +static __maybe_unused int wave5_pm_suspend(struct device *dev) +{ + struct vpu_device *vpu = dev_get_drvdata(dev); + + if (pm_runtime_suspended(dev)) + return 0; + + if (vpu->irq < 0) + hrtimer_cancel(&vpu->hrtimer); + + wave5_vpu_sleep_wake(dev, true, NULL, 0); + clk_bulk_disable_unprepare(vpu->num_clks, vpu->clks); + + return 0; +} + +static __maybe_unused int wave5_pm_resume(struct device *dev) +{ + struct vpu_device *vpu = dev_get_drvdata(dev); + int ret = 0; + + wave5_vpu_sleep_wake(dev, false, NULL, 0); + ret = clk_bulk_prepare_enable(vpu->num_clks, vpu->clks); + if (ret) { + dev_err(dev, "Enabling clocks, fail: %d\n", ret); + return ret; + } + + if (vpu->irq < 0 && !hrtimer_active(&vpu->hrtimer)) + hrtimer_start(&vpu->hrtimer, ns_to_ktime(vpu->vpu_poll_interval * NSEC_PER_MSEC), + HRTIMER_MODE_REL_PINNED); + + return ret; +} + +static const struct dev_pm_ops wave5_pm_ops = { + SET_RUNTIME_PM_OPS(wave5_pm_suspend, wave5_pm_resume, NULL) +}; + static int wave5_vpu_probe(struct platform_device *pdev) { int ret; @@ -281,6 +321,12 @@ static int wave5_vpu_probe(struct platform_device *pdev) (match_data->flags & WAVE5_IS_DEC) ? "'DECODE'" : ""); dev_info(&pdev->dev, "Product Code: 0x%x\n", dev->product_code); dev_info(&pdev->dev, "Firmware Revision: %u\n", fw_revision); + + pm_runtime_set_autosuspend_delay(&pdev->dev, 100); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + wave5_vpu_sleep_wake(&pdev->dev, true, NULL, 0); + return 0; err_enc_unreg: @@ -310,6 +356,9 @@ static void wave5_vpu_remove(struct platform_device *pdev) hrtimer_cancel(&dev->hrtimer); } + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + mutex_destroy(&dev->dev_lock); mutex_destroy(&dev->hw_lock); reset_control_assert(dev->resets); @@ -337,9 +386,10 @@ static struct platform_driver wave5_vpu_driver = { .driver = { .name = VPU_PLATFORM_DEVICE_NAME, .of_match_table = of_match_ptr(wave5_dt_ids), + .pm = &wave5_pm_ops, }, .probe = wave5_vpu_probe, - .remove_new = wave5_vpu_remove, + .remove = wave5_vpu_remove, }; module_platform_driver(wave5_vpu_driver); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.h b/drivers/media/platform/chips-media/wave5/wave5-vpu.h index 32b7fd3730b5..3847332551fc 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu.h +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.h @@ -38,10 +38,7 @@ enum vpu_fmt_type { struct vpu_format { unsigned int v4l2_pix_fmt; - unsigned int max_width; - unsigned int min_width; - unsigned int max_height; - unsigned int min_height; + const struct v4l2_frmsize_stepwise *v4l2_frmsize; }; static inline struct vpu_instance *wave5_to_vpu_inst(struct v4l2_fh *vfh) diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c index 1a3efb638dde..e16b990041c2 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c @@ -6,6 +6,8 @@ */ #include <linux/bug.h> +#include <linux/pm_runtime.h> +#include <linux/delay.h> #include "wave5-vpuapi.h" #include "wave5-regdefine.h" #include "wave5.h" @@ -195,14 +197,20 @@ int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res) int retry = 0; struct vpu_device *vpu_dev = inst->dev; int i; + int inst_count = 0; + struct vpu_instance *inst_elm; *fail_res = 0; if (!inst->codec_info) return -EINVAL; + pm_runtime_resume_and_get(inst->dev->dev); + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); - if (ret) + if (ret) { + pm_runtime_put_sync(inst->dev->dev); return ret; + } do { ret = wave5_vpu_dec_finish_seq(inst, fail_res); @@ -232,9 +240,14 @@ int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res) wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_task); + list_for_each_entry(inst_elm, &vpu_dev->instances, list) + inst_count++; + if (inst_count == 1) + pm_runtime_dont_use_autosuspend(vpu_dev->dev); + unlock_and_return: mutex_unlock(&vpu_dev->hw_lock); - + pm_runtime_put_sync(inst->dev->dev); return ret; } @@ -697,25 +710,33 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res) int ret; int retry = 0; struct vpu_device *vpu_dev = inst->dev; + int inst_count = 0; + struct vpu_instance *inst_elm; *fail_res = 0; if (!inst->codec_info) return -EINVAL; + pm_runtime_resume_and_get(inst->dev->dev); + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); - if (ret) + if (ret) { + pm_runtime_resume_and_get(inst->dev->dev); return ret; + } do { ret = wave5_vpu_enc_finish_seq(inst, fail_res); if (ret < 0 && *fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING) { dev_warn(inst->dev->dev, "enc_finish_seq timed out\n"); + pm_runtime_resume_and_get(inst->dev->dev); mutex_unlock(&vpu_dev->hw_lock); return ret; } if (*fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING && retry++ >= MAX_FIRMWARE_CALL_RETRY) { + pm_runtime_resume_and_get(inst->dev->dev); mutex_unlock(&vpu_dev->hw_lock); return -ETIMEDOUT; } @@ -734,7 +755,13 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res) wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_task); + list_for_each_entry(inst_elm, &vpu_dev->instances, list) + inst_count++; + if (inst_count == 1) + pm_runtime_dont_use_autosuspend(vpu_dev->dev); + mutex_unlock(&vpu_dev->hw_lock); + pm_runtime_put_sync(inst->dev->dev); return 0; } diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h index d2370511faf8..45615c15beca 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h @@ -568,6 +568,7 @@ struct enc_wave_param { u32 lambda_scaling_enable: 1; /* enable lambda scaling using custom GOP */ u32 transform8x8_enable: 1; /* enable 8x8 intra prediction and 8x8 transform */ u32 mb_level_rc_enable: 1; /* enable MB-level rate control */ + u32 forced_idr_header_enable: 1; /* enable header encoding before IDR frame */ }; struct enc_open_param { diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h index e4bc2e467cb5..1ea9f5f31499 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h @@ -32,10 +32,29 @@ #define MAX_NUM_INSTANCE 32 -#define W5_MIN_ENC_PIC_WIDTH 256 -#define W5_MIN_ENC_PIC_HEIGHT 128 -#define W5_MAX_ENC_PIC_WIDTH 8192 -#define W5_MAX_ENC_PIC_HEIGHT 8192 +#define W5_DEF_DEC_PIC_WIDTH 720U +#define W5_DEF_DEC_PIC_HEIGHT 480U +#define W5_MIN_DEC_PIC_8_WIDTH 8U +#define W5_MIN_DEC_PIC_8_HEIGHT 8U +#define W5_MIN_DEC_PIC_32_WIDTH 32U +#define W5_MIN_DEC_PIC_32_HEIGHT 32U +#define W5_MAX_DEC_PIC_WIDTH 8192U +#define W5_MAX_DEC_PIC_HEIGHT 4320U +#define W5_DEC_CODEC_STEP_WIDTH 1U +#define W5_DEC_CODEC_STEP_HEIGHT 1U +#define W5_DEC_RAW_STEP_WIDTH 32U +#define W5_DEC_RAW_STEP_HEIGHT 16U + +#define W5_DEF_ENC_PIC_WIDTH 416U +#define W5_DEF_ENC_PIC_HEIGHT 240U +#define W5_MIN_ENC_PIC_WIDTH 256U +#define W5_MIN_ENC_PIC_HEIGHT 128U +#define W5_MAX_ENC_PIC_WIDTH 8192U +#define W5_MAX_ENC_PIC_HEIGHT 8192U +#define W5_ENC_CODEC_STEP_WIDTH 8U +#define W5_ENC_CODEC_STEP_HEIGHT 8U +#define W5_ENC_RAW_STEP_WIDTH 32U +#define W5_ENC_RAW_STEP_HEIGHT 16U // application specific configuration #define VPU_ENC_TIMEOUT 60000 diff --git a/drivers/media/platform/chips-media/wave5/wave5.h b/drivers/media/platform/chips-media/wave5/wave5.h index 2a29b9164f97..2caab356f3e1 100644 --- a/drivers/media/platform/chips-media/wave5/wave5.h +++ b/drivers/media/platform/chips-media/wave5/wave5.h @@ -62,6 +62,9 @@ int wave5_vpu_get_version(struct vpu_device *vpu_dev, u32 *revision); int wave5_vpu_init(struct device *dev, u8 *fw, size_t size); +int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code, + size_t size); + int wave5_vpu_reset(struct device *dev, enum sw_reset_mode reset_mode); int wave5_vpu_build_up_dec_param(struct vpu_instance *inst, struct dec_open_param *param); diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.c b/drivers/media/platform/imagination/e5010-jpeg-enc.c index 187f2d8abfbb..c194f830577f 100644 --- a/drivers/media/platform/imagination/e5010-jpeg-enc.c +++ b/drivers/media/platform/imagination/e5010-jpeg-enc.c @@ -1593,8 +1593,6 @@ static const struct vb2_ops e5010_video_ops = { .buf_finish = e5010_buf_finish, .buf_prepare = e5010_buf_prepare, .buf_out_validate = e5010_buf_out_validate, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = e5010_start_streaming, .stop_streaming = e5010_stop_streaming, }; @@ -1619,7 +1617,7 @@ MODULE_DEVICE_TABLE(of, e5010_of_match); static struct platform_driver e5010_driver = { .probe = e5010_probe, - .remove_new = e5010_remove, + .remove = e5010_remove, .driver = { .name = E5010_MODULE_NAME, .of_match_table = e5010_of_match, diff --git a/drivers/media/platform/intel/pxa_camera.c b/drivers/media/platform/intel/pxa_camera.c index f118aaac0b38..bef1e7137f23 100644 --- a/drivers/media/platform/intel/pxa_camera.c +++ b/drivers/media/platform/intel/pxa_camera.c @@ -1504,8 +1504,6 @@ static const struct vb2_ops pxac_vb2_ops = { .buf_cleanup = pxac_vb2_cleanup, .start_streaming = pxac_vb2_start_streaming, .stop_streaming = pxac_vb2_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev) @@ -2460,7 +2458,7 @@ static struct platform_driver pxa_camera_driver = { .of_match_table = pxa_camera_of_match, }, .probe = pxa_camera_probe, - .remove_new = pxa_camera_remove, + .remove = pxa_camera_remove, }; module_platform_driver(pxa_camera_driver); diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 5adcef80c698..5188f3189096 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -784,8 +784,6 @@ static const struct vb2_ops deinterlace_qops = { .queue_setup = deinterlace_queue_setup, .buf_prepare = deinterlace_buf_prepare, .buf_queue = deinterlace_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -993,7 +991,7 @@ static void deinterlace_remove(struct platform_device *pdev) static struct platform_driver deinterlace_pdrv = { .probe = deinterlace_probe, - .remove_new = deinterlace_remove, + .remove = deinterlace_remove, .driver = { .name = MEM2MEM_NAME, }, diff --git a/drivers/media/platform/marvell/mcam-core.c b/drivers/media/platform/marvell/mcam-core.c index c81593c969e0..9ec01228f907 100644 --- a/drivers/media/platform/marvell/mcam-core.c +++ b/drivers/media/platform/marvell/mcam-core.c @@ -1203,8 +1203,6 @@ static const struct vb2_ops mcam_vb2_ops = { .buf_queue = mcam_vb_buf_queue, .start_streaming = mcam_vb_start_streaming, .stop_streaming = mcam_vb_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; @@ -1267,8 +1265,6 @@ static const struct vb2_ops mcam_vb2_sg_ops = { .buf_cleanup = mcam_vb_sg_buf_cleanup, .start_streaming = mcam_vb_start_streaming, .stop_streaming = mcam_vb_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; #endif /* MCAM_MODE_DMA_SG */ diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c index ff9d151121d5..3fd4fc1b9c48 100644 --- a/drivers/media/platform/marvell/mmp-driver.c +++ b/drivers/media/platform/marvell/mmp-driver.c @@ -359,7 +359,7 @@ MODULE_DEVICE_TABLE(of, mmpcam_of_match); static struct platform_driver mmpcam_driver = { .probe = mmpcam_probe, - .remove_new = mmpcam_remove, + .remove = mmpcam_remove, .driver = { .name = "mmp-camera", .of_match_table = mmpcam_of_match, diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index ac48658e2de4..834d2a354692 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -884,8 +884,6 @@ static const struct vb2_ops mtk_jpeg_dec_qops = { .queue_setup = mtk_jpeg_queue_setup, .buf_prepare = mtk_jpeg_buf_prepare, .buf_queue = mtk_jpeg_dec_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = mtk_jpeg_dec_stop_streaming, }; @@ -893,8 +891,6 @@ static const struct vb2_ops mtk_jpeg_enc_qops = { .queue_setup = mtk_jpeg_queue_setup, .buf_prepare = mtk_jpeg_buf_prepare, .buf_queue = mtk_jpeg_enc_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = mtk_jpeg_enc_stop_streaming, }; @@ -1293,6 +1289,11 @@ static int mtk_jpeg_single_core_init(struct platform_device *pdev, return 0; } +static void mtk_jpeg_destroy_workqueue(void *data) +{ + destroy_workqueue(data); +} + static int mtk_jpeg_probe(struct platform_device *pdev) { struct mtk_jpeg_dev *jpeg; @@ -1337,6 +1338,11 @@ static int mtk_jpeg_probe(struct platform_device *pdev) | WQ_FREEZABLE); if (!jpeg->workqueue) return -EINVAL; + ret = devm_add_action_or_reset(&pdev->dev, + mtk_jpeg_destroy_workqueue, + jpeg->workqueue); + if (ret) + return ret; } ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); @@ -1950,7 +1956,7 @@ MODULE_DEVICE_TABLE(of, mtk_jpeg_match); static struct platform_driver mtk_jpeg_driver = { .probe = mtk_jpeg_probe, - .remove_new = mtk_jpeg_remove, + .remove = mtk_jpeg_remove, .driver = { .name = MTK_JPEG_NAME, .of_match_table = mtk_jpeg_match, diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c index 4a6ee211e18f..2c5d74939d0a 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c @@ -578,11 +578,6 @@ static int mtk_jpegdec_hw_init_irq(struct mtk_jpegdec_comp_dev *dev) return 0; } -static void mtk_jpegdec_destroy_workqueue(void *data) -{ - destroy_workqueue(data); -} - static int mtk_jpegdec_hw_probe(struct platform_device *pdev) { struct mtk_jpegdec_clk *jpegdec_clk; @@ -606,12 +601,6 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev) dev->plat_dev = pdev; dev->dev = &pdev->dev; - ret = devm_add_action_or_reset(&pdev->dev, - mtk_jpegdec_destroy_workqueue, - master_dev->workqueue); - if (ret) - return ret; - spin_lock_init(&dev->hw_lock); dev->hw_state = MTK_JPEG_HW_IDLE; diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c index 917cdf38f230..80fdc6ff57e0 100644 --- a/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c +++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c @@ -298,7 +298,7 @@ static const struct dev_pm_ops mtk_mdp_pm_ops = { static struct platform_driver mtk_mdp_driver = { .probe = mtk_mdp_probe, - .remove_new = mtk_mdp_remove, + .remove = mtk_mdp_remove, .driver = { .name = MTK_MDP_MODULE_NAME, .pm = &mtk_mdp_pm_ops, diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c index f14779e7596e..28c998bd3a81 100644 --- a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c @@ -584,8 +584,6 @@ static const struct vb2_ops mtk_mdp_m2m_qops = { .buf_queue = mtk_mdp_m2m_buf_queue, .stop_streaming = mtk_mdp_m2m_stop_streaming, .start_streaming = mtk_mdp_m2m_start_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int mtk_mdp_m2m_querycap(struct file *file, void *fh, diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c index 37e7b985d52c..5e94ff0d0756 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -413,7 +413,7 @@ static const struct dev_pm_ops mdp_pm_ops = { static struct platform_driver mdp_driver = { .probe = mdp_probe, - .remove_new = mdp_remove, + .remove = mdp_remove, .driver = { .name = MDP_MODULE_NAME, .pm = &mdp_pm_ops, diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c index 0e69128a3772..59ce5cce0698 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c @@ -266,8 +266,6 @@ static void mdp_m2m_buf_queue(struct vb2_buffer *vb) static const struct vb2_ops mdp_m2m_qops = { .queue_setup = mdp_m2m_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = mdp_m2m_buf_prepare, .start_streaming = mdp_m2m_start_streaming, .stop_streaming = mdp_m2m_stop_streaming, diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c index 2073781ccadb..9247d92d431d 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c @@ -591,7 +591,7 @@ static void mtk_vcodec_dec_remove(struct platform_device *pdev) static struct platform_driver mtk_vcodec_dec_driver = { .probe = mtk_vcodec_probe, - .remove_new = mtk_vcodec_dec_remove, + .remove = mtk_vcodec_dec_remove, .driver = { .name = MTK_VCODEC_DEC_NAME, .of_match_table = mtk_vcodec_match, diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c index e62c1c18758b..aa9bdee7a96c 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c @@ -598,8 +598,6 @@ static void mtk_init_vdec_params(struct mtk_vcodec_dec_ctx *ctx) static const struct vb2_ops mtk_vdec_frame_vb2_ops = { .queue_setup = vb2ops_vdec_queue_setup, .buf_prepare = vb2ops_vdec_buf_prepare, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = vb2ops_vdec_start_streaming, .buf_queue = vb2ops_vdec_stateful_buf_queue, diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c index 3307dc15fc1d..afa224da0f41 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c @@ -856,8 +856,6 @@ static int vb2ops_vdec_out_buf_validate(struct vb2_buffer *vb) static const struct vb2_ops mtk_vdec_request_vb2_ops = { .queue_setup = vb2ops_vdec_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = vb2ops_vdec_start_streaming, .stop_streaming = vb2ops_vdec_stop_streaming, diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c index 7eaf0e24c9fc..a01dc25a7699 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c @@ -1009,8 +1009,6 @@ static const struct vb2_ops mtk_venc_vb2_ops = { .buf_out_validate = vb2ops_venc_buf_out_validate, .buf_prepare = vb2ops_venc_buf_prepare, .buf_queue = vb2ops_venc_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = vb2ops_venc_start_streaming, .stop_streaming = vb2ops_venc_stop_streaming, }; diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c index 3cb8a1622222..a1e4483abcdb 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c @@ -473,7 +473,7 @@ static void mtk_vcodec_enc_remove(struct platform_device *pdev) static struct platform_driver mtk_vcodec_enc_driver = { .probe = mtk_vcodec_probe, - .remove_new = mtk_vcodec_enc_remove, + .remove = mtk_vcodec_enc_remove, .driver = { .name = MTK_VCODEC_ENC_NAME, .of_match_table = mtk_vcodec_enc_match, diff --git a/drivers/media/platform/mediatek/vpu/mtk_vpu.c b/drivers/media/platform/mediatek/vpu/mtk_vpu.c index 724ae7c2ab3b..8d8319f0cd22 100644 --- a/drivers/media/platform/mediatek/vpu/mtk_vpu.c +++ b/drivers/media/platform/mediatek/vpu/mtk_vpu.c @@ -1041,7 +1041,7 @@ static const struct dev_pm_ops mtk_vpu_pm = { static struct platform_driver mtk_vpu_driver = { .probe = mtk_vpu_probe, - .remove_new = mtk_vpu_remove, + .remove = mtk_vpu_remove, .driver = { .name = "mtk_vpu", .pm = &mtk_vpu_pm, diff --git a/drivers/media/platform/microchip/microchip-csi2dc.c b/drivers/media/platform/microchip/microchip-csi2dc.c index fee73260bb1e..70303a0b6919 100644 --- a/drivers/media/platform/microchip/microchip-csi2dc.c +++ b/drivers/media/platform/microchip/microchip-csi2dc.c @@ -782,7 +782,7 @@ MODULE_DEVICE_TABLE(of, csi2dc_of_match); static struct platform_driver csi2dc_driver = { .probe = csi2dc_probe, - .remove_new = csi2dc_remove, + .remove = csi2dc_remove, .driver = { .name = "microchip-csi2dc", .pm = &csi2dc_dev_pm_ops, diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c index 28e56f6a695d..a7cdc743fda7 100644 --- a/drivers/media/platform/microchip/microchip-isc-base.c +++ b/drivers/media/platform/microchip/microchip-isc-base.c @@ -465,8 +465,6 @@ static void isc_buffer_queue(struct vb2_buffer *vb) static const struct vb2_ops isc_vb2_ops = { .queue_setup = isc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = isc_buffer_prepare, .start_streaming = isc_start_streaming, .stop_streaming = isc_stop_streaming, diff --git a/drivers/media/platform/microchip/microchip-sama5d2-isc.c b/drivers/media/platform/microchip/microchip-sama5d2-isc.c index 60b6d922d764..66d3d7891991 100644 --- a/drivers/media/platform/microchip/microchip-sama5d2-isc.c +++ b/drivers/media/platform/microchip/microchip-sama5d2-isc.c @@ -658,7 +658,7 @@ MODULE_DEVICE_TABLE(of, microchip_isc_of_match); static struct platform_driver microchip_isc_driver = { .probe = microchip_isc_probe, - .remove_new = microchip_isc_remove, + .remove = microchip_isc_remove, .driver = { .name = "microchip-sama5d2-isc", .pm = µchip_isc_dev_pm_ops, diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c index e97abe3e35af..b0302dfc3278 100644 --- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c +++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c @@ -621,7 +621,7 @@ MODULE_DEVICE_TABLE(of, microchip_xisc_of_match); static struct platform_driver microchip_xisc_driver = { .probe = microchip_xisc_probe, - .remove_new = microchip_xisc_remove, + .remove = microchip_xisc_remove, .driver = { .name = "microchip-sama7g5-xisc", .pm = µchip_xisc_dev_pm_ops, diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c index 60fbb9140035..4f5d75645b2b 100644 --- a/drivers/media/platform/nuvoton/npcm-video.c +++ b/drivers/media/platform/nuvoton/npcm-video.c @@ -1558,8 +1558,6 @@ static const struct regmap_config npcm_video_ece_regmap_cfg = { static const struct vb2_ops npcm_video_vb2_ops = { .queue_setup = npcm_video_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = npcm_video_buf_prepare, .buf_finish = npcm_video_buf_finish, .start_streaming = npcm_video_start_streaming, @@ -1814,7 +1812,7 @@ static struct platform_driver npcm_video_driver = { .of_match_table = npcm_video_match, }, .probe = npcm_video_probe, - .remove_new = npcm_video_remove, + .remove = npcm_video_remove, }; module_platform_driver(npcm_video_driver); diff --git a/drivers/media/platform/nvidia/tegra-vde/iommu.c b/drivers/media/platform/nvidia/tegra-vde/iommu.c index 5521ed3e465f..b1d9d841d944 100644 --- a/drivers/media/platform/nvidia/tegra-vde/iommu.c +++ b/drivers/media/platform/nvidia/tegra-vde/iommu.c @@ -78,9 +78,10 @@ int tegra_vde_iommu_init(struct tegra_vde *vde) arm_iommu_release_mapping(mapping); } #endif - vde->domain = iommu_domain_alloc(&platform_bus_type); - if (!vde->domain) { - err = -ENOMEM; + vde->domain = iommu_paging_domain_alloc(dev); + if (IS_ERR(vde->domain)) { + err = PTR_ERR(vde->domain); + vde->domain = NULL; goto put_group; } diff --git a/drivers/media/platform/nvidia/tegra-vde/v4l2.c b/drivers/media/platform/nvidia/tegra-vde/v4l2.c index 0f48ce6f243e..e3726cab0c82 100644 --- a/drivers/media/platform/nvidia/tegra-vde/v4l2.c +++ b/drivers/media/platform/nvidia/tegra-vde/v4l2.c @@ -328,8 +328,6 @@ static const struct vb2_ops tegra_qops = { .buf_request_complete = tegra_buf_request_complete, .start_streaming = tegra_start_streaming, .stop_streaming = tegra_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int tegra_queue_init(void *priv, @@ -929,13 +927,13 @@ int tegra_vde_v4l2_init(struct tegra_vde *vde) media_device_init(&vde->mdev); video_set_drvdata(&vde->vdev, vde); - vde->vdev.lock = &vde->v4l2_lock, - vde->vdev.fops = &tegra_v4l2_fops, - vde->vdev.vfl_dir = VFL_DIR_M2M, - vde->vdev.release = video_device_release_empty, + vde->vdev.lock = &vde->v4l2_lock; + vde->vdev.fops = &tegra_v4l2_fops; + vde->vdev.vfl_dir = VFL_DIR_M2M; + vde->vdev.release = video_device_release_empty; vde->vdev.v4l2_dev = &vde->v4l2_dev; - vde->vdev.ioctl_ops = &tegra_v4l2_ioctl_ops, - vde->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, + vde->vdev.ioctl_ops = &tegra_v4l2_ioctl_ops; + vde->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; vde->v4l2_dev.mdev = &vde->mdev; vde->mdev.ops = &tegra_media_device_ops; diff --git a/drivers/media/platform/nvidia/tegra-vde/vde.c b/drivers/media/platform/nvidia/tegra-vde/vde.c index 81a0d3b76b88..3232392c60e2 100644 --- a/drivers/media/platform/nvidia/tegra-vde/vde.c +++ b/drivers/media/platform/nvidia/tegra-vde/vde.c @@ -535,7 +535,7 @@ MODULE_DEVICE_TABLE(of, tegra_vde_of_match); static struct platform_driver tegra_vde_driver = { .probe = tegra_vde_probe, - .remove_new = tegra_vde_remove, + .remove = tegra_vde_remove, .shutdown = tegra_vde_shutdown, .driver = { .name = "tegra-vde", diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c index 0024d6175ad9..66582e7f92fc 100644 --- a/drivers/media/platform/nxp/dw100/dw100.c +++ b/drivers/media/platform/nxp/dw100/dw100.c @@ -558,8 +558,6 @@ static const struct vb2_ops dw100_qops = { .buf_queue = dw100_buf_queue, .start_streaming = dw100_start_streaming, .stop_streaming = dw100_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int dw100_m2m_queue_init(void *priv, struct vb2_queue *src_vq, @@ -1311,7 +1309,7 @@ static void dw100_hw_set_destination(struct dw100_device *dw_dev, } dev_dbg(&dw_dev->pdev->dev, - "Set HW source registers for %ux%u - stride %u, pixfmt: %p4cc, dma:%pad\n", + "Set HW destination registers for %ux%u - stride %u, pixfmt: %p4cc, dma:%pad\n", width, height, stride, &fourcc, &addr_y); /* Pixel Format */ @@ -1688,7 +1686,7 @@ MODULE_DEVICE_TABLE(of, dw100_dt_ids); static struct platform_driver dw100_driver = { .probe = dw100_probe, - .remove_new = dw100_remove, + .remove = dw100_remove, .driver = { .name = DRV_NAME, .pm = &dw100_pm, diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 1d8913813037..7f5fe551179b 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -1965,8 +1965,6 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) static const struct vb2_ops mxc_jpeg_qops = { .queue_setup = mxc_jpeg_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_out_validate = mxc_jpeg_buf_out_validate, .buf_prepare = mxc_jpeg_buf_prepare, .start_streaming = mxc_jpeg_start_streaming, @@ -2679,6 +2677,8 @@ static void mxc_jpeg_detach_pm_domains(struct mxc_jpeg_dev *jpeg) int i; for (i = 0; i < jpeg->num_domains; i++) { + if (jpeg->pd_dev[i] && !pm_runtime_suspended(jpeg->pd_dev[i])) + pm_runtime_force_suspend(jpeg->pd_dev[i]); if (jpeg->pd_link[i] && !IS_ERR(jpeg->pd_link[i])) device_link_del(jpeg->pd_link[i]); if (jpeg->pd_dev[i] && !IS_ERR(jpeg->pd_dev[i])) @@ -2842,6 +2842,7 @@ static int mxc_jpeg_probe(struct platform_device *pdev) jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M; jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; + video_set_drvdata(jpeg->dec_vdev, jpeg); if (mode == MXC_JPEG_ENCODE) { v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_DECODER_CMD); v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_TRY_DECODER_CMD); @@ -2854,7 +2855,6 @@ static int mxc_jpeg_probe(struct platform_device *pdev) dev_err(dev, "failed to register video device\n"); goto err_vdev_register; } - video_set_drvdata(jpeg->dec_vdev, jpeg); if (mode == MXC_JPEG_ENCODE) v4l2_info(&jpeg->v4l2_dev, "encoder device registered as /dev/video%d (%d,%d)\n", @@ -2888,7 +2888,6 @@ err_clk: return ret; } -#ifdef CONFIG_PM static int mxc_jpeg_runtime_resume(struct device *dev) { struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); @@ -2911,9 +2910,7 @@ static int mxc_jpeg_runtime_suspend(struct device *dev) return 0; } -#endif -#ifdef CONFIG_PM_SLEEP static int mxc_jpeg_suspend(struct device *dev) { struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); @@ -2934,12 +2931,10 @@ static int mxc_jpeg_resume(struct device *dev) v4l2_m2m_resume(jpeg->m2m_dev); return ret; } -#endif static const struct dev_pm_ops mxc_jpeg_pm_ops = { - SET_RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend, - mxc_jpeg_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(mxc_jpeg_suspend, mxc_jpeg_resume) + RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend, mxc_jpeg_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(mxc_jpeg_suspend, mxc_jpeg_resume) }; static void mxc_jpeg_remove(struct platform_device *pdev) @@ -2959,11 +2954,11 @@ MODULE_DEVICE_TABLE(of, mxc_jpeg_match); static struct platform_driver mxc_jpeg_driver = { .probe = mxc_jpeg_probe, - .remove_new = mxc_jpeg_remove, + .remove = mxc_jpeg_remove, .driver = { .name = "mxc-jpeg", .of_match_table = mxc_jpeg_match, - .pm = &mxc_jpeg_pm_ops, + .pm = pm_ptr(&mxc_jpeg_pm_ops), }, }; module_platform_driver(mxc_jpeg_driver); diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 44e1402e8be1..29523bb84d95 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -1570,7 +1570,7 @@ MODULE_DEVICE_TABLE(of, mipi_csis_of_match); static struct platform_driver mipi_csis_driver = { .probe = mipi_csis_probe, - .remove_new = mipi_csis_remove, + .remove = mipi_csis_remove, .driver = { .of_match_table = mipi_csis_of_match, .name = CSIS_DRIVER_NAME, diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index e4427e6487fb..7f8ffbac582f 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -1606,8 +1606,6 @@ static const struct vb2_ops pxp_qops = { .buf_queue = pxp_buf_queue, .start_streaming = pxp_start_streaming, .stop_streaming = pxp_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -1943,7 +1941,7 @@ MODULE_DEVICE_TABLE(of, pxp_dt_ids); static struct platform_driver pxp_driver = { .probe = pxp_probe, - .remove_new = pxp_remove, + .remove = pxp_remove, .driver = { .name = MEM2MEM_NAME, .of_match_table = pxp_dt_ids, diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 9566ff738818..34a92642bbfe 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -1507,8 +1507,6 @@ static const struct vb2_ops imx7_csi_video_qops = { .buf_init = imx7_csi_video_buf_init, .buf_prepare = imx7_csi_video_buf_prepare, .buf_queue = imx7_csi_video_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = imx7_csi_video_start_streaming, .stop_streaming = imx7_csi_video_stop_streaming, }; @@ -2281,7 +2279,7 @@ MODULE_DEVICE_TABLE(of, imx7_csi_of_match); static struct platform_driver imx7_csi_driver = { .probe = imx7_csi_probe, - .remove_new = imx7_csi_remove, + .remove = imx7_csi_remove, .driver = { .of_match_table = imx7_csi_of_match, .name = "imx7-csi", diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c index c2013995049c..aaf58063677c 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c @@ -535,7 +535,7 @@ MODULE_DEVICE_TABLE(of, mxc_isi_of_match); static struct platform_driver mxc_isi_driver = { .probe = mxc_isi_probe, - .remove_new = mxc_isi_remove, + .remove = mxc_isi_remove, .driver = { .of_match_table = mxc_isi_of_match, .name = MXC_ISI_DRIVER_NAME, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c index 9745d6219a16..794050a6a919 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c @@ -269,8 +269,6 @@ static const struct vb2_ops mxc_isi_m2m_vb2_qops = { .buf_init = mxc_isi_m2m_vb2_buffer_init, .buf_prepare = mxc_isi_m2m_vb2_buffer_prepare, .buf_queue = mxc_isi_m2m_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = mxc_isi_m2m_vb2_start_streaming, .stop_streaming = mxc_isi_m2m_vb2_stop_streaming, }; diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c index 4091f1c0e78b..c0ba34ea82fd 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c @@ -987,8 +987,6 @@ static const struct vb2_ops mxc_isi_vb2_qops = { .buf_init = mxc_isi_vb2_buffer_init, .buf_prepare = mxc_isi_vb2_buffer_prepare, .buf_queue = mxc_isi_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = mxc_isi_vb2_start_streaming, .stop_streaming = mxc_isi_vb2_stop_streaming, }; diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c index d4a6c5532969..1f2657cf6e82 100644 --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c @@ -953,7 +953,7 @@ MODULE_DEVICE_TABLE(of, imx8mq_mipi_csi_of_match); static struct platform_driver imx8mq_mipi_csi_driver = { .probe = imx8mq_mipi_csi_probe, - .remove_new = imx8mq_mipi_csi_remove, + .remove = imx8mq_mipi_csi_remove, .driver = { .of_match_table = imx8mq_mipi_csi_of_match, .name = MIPI_CSI2_DRIVER_NAME, diff --git a/drivers/media/platform/nxp/mx2_emmaprp.c b/drivers/media/platform/nxp/mx2_emmaprp.c index 023ed40c6b08..0c6cc120fd2a 100644 --- a/drivers/media/platform/nxp/mx2_emmaprp.c +++ b/drivers/media/platform/nxp/mx2_emmaprp.c @@ -677,8 +677,6 @@ static const struct vb2_ops emmaprp_qops = { .queue_setup = emmaprp_queue_setup, .buf_prepare = emmaprp_buf_prepare, .buf_queue = emmaprp_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -902,7 +900,7 @@ static void emmaprp_remove(struct platform_device *pdev) static struct platform_driver emmaprp_pdrv = { .probe = emmaprp_probe, - .remove_new = emmaprp_remove, + .remove = emmaprp_remove, .driver = { .name = MEM2MEM_NAME, }, diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 2f7361dfd461..5af2b382a843 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -212,14 +212,25 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on) if (ret < 0) return ret; + ret = regulator_bulk_enable(csiphy->num_supplies, + csiphy->supplies); + if (ret < 0) { + pm_runtime_put_sync(dev); + return ret; + } + ret = csiphy_set_clock_rates(csiphy); if (ret < 0) { + regulator_bulk_disable(csiphy->num_supplies, + csiphy->supplies); pm_runtime_put_sync(dev); return ret; } ret = camss_enable_clocks(csiphy->nclocks, csiphy->clock, dev); if (ret < 0) { + regulator_bulk_disable(csiphy->num_supplies, + csiphy->supplies); pm_runtime_put_sync(dev); return ret; } @@ -234,6 +245,8 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on) camss_disable_clocks(csiphy->nclocks, csiphy->clock); + regulator_bulk_disable(csiphy->num_supplies, csiphy->supplies); + pm_runtime_put_sync(dev); } @@ -583,6 +596,7 @@ int msm_csiphy_subdev_init(struct camss *camss, return PTR_ERR(csiphy->base); if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_8x96) { csiphy->base_clk_mux = devm_platform_ioremap_resource_byname(pdev, res->reg[1]); @@ -676,7 +690,27 @@ int msm_csiphy_subdev_init(struct camss *camss, } } - return 0; + /* CSIPHY supplies */ + for (i = 0; i < ARRAY_SIZE(res->regulators); i++) { + if (res->regulators[i]) + csiphy->num_supplies++; + } + + if (csiphy->num_supplies) { + csiphy->supplies = devm_kmalloc_array(camss->dev, + csiphy->num_supplies, + sizeof(*csiphy->supplies), + GFP_KERNEL); + if (!csiphy->supplies) + return -ENOMEM; + } + + for (i = 0; i < csiphy->num_supplies; i++) + csiphy->supplies[i].supply = res->regulators[i]; + + ret = devm_regulator_bulk_get(camss->dev, csiphy->num_supplies, + csiphy->supplies); + return ret; } /* diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index 47f0b6b09eba..eebc1ff1cfab 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -91,6 +91,8 @@ struct csiphy_device { bool *rate_set; int nclocks; u32 timer_clk_rate; + struct regulator_bulk_data *supplies; + int num_supplies; struct csiphy_config cfg; struct v4l2_mbus_framefmt fmt[MSM_CSIPHY_PADS_NUM]; const struct csiphy_subdev_resources *res; diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index a12dcc7ff438..2dc585c6123d 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -830,6 +830,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) ispif_select_cid(ispif, intf, cid, vfe, 1); ispif_config_irq(ispif, intf, vfe, 1); if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, @@ -848,6 +849,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&ispif->config_lock); if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, @@ -1111,6 +1113,7 @@ int msm_ispif_subdev_init(struct camss *camss, if (camss->res->version == CAMSS_8x16) ispif->line_num = 2; else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) ispif->line_num = 4; else @@ -1130,6 +1133,7 @@ int msm_ispif_subdev_init(struct camss *camss, ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x16); } else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) { ispif->line[i].formats = ispif_formats_8x96; ispif->line[i].nformats = @@ -1162,6 +1166,7 @@ int msm_ispif_subdev_init(struct camss *camss, ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c index 1bd3a6ef1d04..9a9007c3ff33 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -938,7 +938,10 @@ static irqreturn_t vfe_isr(int irq, void *dev) */ static void vfe_4_1_pm_domain_off(struct vfe_device *vfe) { - /* nop */ + if (!vfe->res->has_pd) + return; + + vfe_pm_domain_off(vfe); } /* @@ -947,7 +950,10 @@ static void vfe_4_1_pm_domain_off(struct vfe_device *vfe) */ static int vfe_4_1_pm_domain_on(struct vfe_device *vfe) { - return 0; + if (!vfe->res->has_pd) + return 0; + + return vfe_pm_domain_on(vfe); } static const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_1 = { diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 83c5a36d071f..80a62ba11295 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -285,6 +285,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, switch (vfe->camss->res->version) { case CAMSS_8x16: + case CAMSS_8x53: switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_1X16: { diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 3b8fc31d957c..aa021fd5e123 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -310,8 +310,6 @@ static void video_stop_streaming(struct vb2_queue *q) static const struct vb2_ops msm_video_vb2_q_ops = { .queue_setup = video_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_init = video_buf_init, .buf_prepare = video_buf_prepare, .buf_queue = video_buf_queue, diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index d64985ca6e88..9fb31f4c18ad 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -152,6 +152,160 @@ static const struct camss_subdev_resources vfe_res_8x16[] = { } }; +static const struct camss_subdev_resources csid_res_8x53[] = { + /* CSID0 */ + { + .regulators = { "vdda" }, + .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", + "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 310000000, + 400000000, 465000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid0" }, + .interrupt = { "csid0" }, + .csid = { + .hw_ops = &csid_ops_4_7, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_7 + } + }, + + /* CSID1 */ + { + .regulators = { "vdda" }, + .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", + "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 310000000, + 400000000, 465000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid1" }, + .interrupt = { "csid1" }, + .csid = { + .hw_ops = &csid_ops_4_7, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_7 + } + }, + + /* CSID2 */ + { + .regulators = { "vdda" }, + .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", + "csi2", "csi2_phy", "csi2_pix", "csi2_rdi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 310000000, + 400000000, 465000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid2" }, + .interrupt = { "csid2" }, + .csid = { + .hw_ops = &csid_ops_4_7, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_7 + } + }, +}; + +static const struct camss_subdev_resources ispif_res_8x53 = { + /* ISPIF */ + .clock = { "top_ahb", "ahb", "ispif_ahb", + "csi0", "csi0_pix", "csi0_rdi", + "csi1", "csi1_pix", "csi1_rdi", + "csi2", "csi2_pix", "csi2_rdi" }, + .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" }, + .reg = { "ispif", "csi_clk_mux" }, + .interrupt = { "ispif" }, +}; + +static const struct camss_subdev_resources vfe_res_8x53[] = { + /* VFE0 */ + { + .regulators = {}, + .clock = { "top_ahb", "ahb", "ispif_ahb", + "vfe0", "csi_vfe0", "vfe0_ahb", "vfe0_axi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 50000000, 100000000, 133330000, + 160000000, 200000000, 266670000, + 310000000, 400000000, 465000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .vfe = { + .line_num = 3, + .has_pd = true, + .pd_name = "vfe0", + .hw_ops = &vfe_ops_4_1, + .formats_rdi = &vfe_formats_rdi_8x16, + .formats_pix = &vfe_formats_pix_8x16 + } + }, + + /* VFE1 */ + { + .regulators = {}, + .clock = { "top_ahb", "ahb", "ispif_ahb", + "vfe1", "csi_vfe1", "vfe1_ahb", "vfe1_axi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 50000000, 100000000, 133330000, + 160000000, 200000000, 266670000, + 310000000, 400000000, 465000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, + .vfe = { + .line_num = 3, + .has_pd = true, + .pd_name = "vfe1", + .hw_ops = &vfe_ops_4_1, + .formats_rdi = &vfe_formats_rdi_8x16, + .formats_pix = &vfe_formats_pix_8x16 + } + } +}; + +static const struct resources_icc icc_res_8x53[] = { + { + .name = "cam_ahb", + .icc_bw_tbl.avg = 38400, + .icc_bw_tbl.peak = 76800, + }, + { + .name = "cam_vfe0_mem", + .icc_bw_tbl.avg = 939524, + .icc_bw_tbl.peak = 1342177, + }, + { + .name = "cam_vfe1_mem", + .icc_bw_tbl.avg = 939524, + .icc_bw_tbl.peak = 1342177, + }, +}; + static const struct camss_subdev_resources csiphy_res_8x96[] = { /* CSIPHY0 */ { @@ -837,7 +991,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { static const struct camss_subdev_resources csiphy_res_8250[] = { /* CSIPHY0 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy0", "csiphy0_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -850,7 +1004,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY1 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy1", "csiphy1_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -863,7 +1017,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY2 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy2", "csiphy2_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -876,7 +1030,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY3 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy3", "csiphy3_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -889,7 +1043,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY4 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy4", "csiphy4_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -902,7 +1056,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY5 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy5", "csiphy5_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -918,7 +1072,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { static const struct camss_subdev_resources csid_res_8250[] = { /* CSID0 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = {}, .clock = { "vfe0_csid", "vfe0_cphy_rx", "vfe0", "vfe0_areg", "vfe0_ahb" }, .clock_rate = { { 400000000 }, { 400000000 }, @@ -935,7 +1089,7 @@ static const struct camss_subdev_resources csid_res_8250[] = { }, /* CSID1 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = {}, .clock = { "vfe1_csid", "vfe1_cphy_rx", "vfe1", "vfe1_areg", "vfe1_ahb" }, .clock_rate = { { 400000000 }, { 400000000 }, @@ -952,7 +1106,7 @@ static const struct camss_subdev_resources csid_res_8250[] = { }, /* CSID2 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = {}, .clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "vfe_lite_ahb" }, .clock_rate = { { 400000000 }, { 400000000 }, @@ -969,7 +1123,7 @@ static const struct camss_subdev_resources csid_res_8250[] = { }, /* CSID3 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = {}, .clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "vfe_lite_ahb" }, .clock_rate = { { 400000000 }, { 400000000 }, @@ -1780,6 +1934,7 @@ err_cleanup: */ static int camss_init_subdevices(struct camss *camss) { + struct platform_device *pdev = to_platform_device(camss->dev); const struct camss_resources *res = camss->res; unsigned int i; int ret; @@ -1806,6 +1961,17 @@ static int camss_init_subdevices(struct camss *camss) } } + /* Get optional CSID wrapper regs shared between CSID devices */ + if (res->csid_wrapper_res) { + char *reg = res->csid_wrapper_res->reg; + void __iomem *base; + + base = devm_platform_ioremap_resource_byname(pdev, reg); + if (IS_ERR(base)) + return PTR_ERR(base); + camss->csid_wrapper_base = base; + } + for (i = 0; i < camss->res->csid_num; i++) { ret = msm_csid_subdev_init(camss, &camss->csid[i], &res->csid_res[i], i); @@ -2130,10 +2296,8 @@ static int camss_configure_pd(struct camss *camss) if (camss->res->pd_name) { camss->genpd = dev_pm_domain_attach_by_name(camss->dev, camss->res->pd_name); - if (IS_ERR(camss->genpd)) { - ret = PTR_ERR(camss->genpd); - goto fail_pm; - } + if (IS_ERR(camss->genpd)) + return PTR_ERR(camss->genpd); } if (!camss->genpd) { @@ -2143,14 +2307,13 @@ static int camss_configure_pd(struct camss *camss) */ camss->genpd = dev_pm_domain_attach_by_id(camss->dev, camss->genpd_num - 1); + if (IS_ERR(camss->genpd)) + return PTR_ERR(camss->genpd); } - if (IS_ERR_OR_NULL(camss->genpd)) { - if (!camss->genpd) - ret = -ENODEV; - else - ret = PTR_ERR(camss->genpd); - goto fail_pm; - } + + if (!camss->genpd) + return -ENODEV; + camss->genpd_link = device_link_add(camss->dev, camss->genpd, DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); @@ -2239,6 +2402,7 @@ static int camss_probe(struct platform_device *pdev) return -ENOMEM; if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_8x96) { camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL); if (!camss->ispif) @@ -2380,6 +2544,20 @@ static const struct camss_resources msm8916_resources = { .link_entities = camss_link_entities }; +static const struct camss_resources msm8953_resources = { + .version = CAMSS_8x53, + .icc_res = icc_res_8x53, + .icc_path_num = ARRAY_SIZE(icc_res_8x53), + .csiphy_res = csiphy_res_8x96, + .csid_res = csid_res_8x53, + .ispif_res = &ispif_res_8x53, + .vfe_res = vfe_res_8x53, + .csiphy_num = ARRAY_SIZE(csiphy_res_8x96), + .csid_num = ARRAY_SIZE(csid_res_8x53), + .vfe_num = ARRAY_SIZE(vfe_res_8x53), + .link_entities = camss_link_entities +}; + static const struct camss_resources msm8996_resources = { .version = CAMSS_8x96, .csiphy_res = csiphy_res_8x96, @@ -2446,6 +2624,7 @@ static const struct camss_resources sc8280xp_resources = { static const struct of_device_id camss_dt_match[] = { { .compatible = "qcom,msm8916-camss", .data = &msm8916_resources }, + { .compatible = "qcom,msm8953-camss", .data = &msm8953_resources }, { .compatible = "qcom,msm8996-camss", .data = &msm8996_resources }, { .compatible = "qcom,sdm660-camss", .data = &sdm660_resources }, { .compatible = "qcom,sdm845-camss", .data = &sdm845_resources }, @@ -2497,7 +2676,7 @@ static const struct dev_pm_ops camss_pm_ops = { static struct platform_driver qcom_camss_driver = { .probe = camss_probe, - .remove_new = camss_remove, + .remove = camss_remove, .driver = { .name = "qcom-camss", .of_match_table = camss_dt_match, diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 73c47c07fc30..9da7f48f5dd7 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -66,6 +66,10 @@ struct resources_icc { struct icc_bw_tbl icc_bw_tbl; }; +struct resources_wrapper { + char *reg; +}; + enum pm_domain { PM_DOMAIN_VFE0 = 0, PM_DOMAIN_VFE1 = 1, @@ -74,6 +78,7 @@ enum pm_domain { enum camss_version { CAMSS_8x16, + CAMSS_8x53, CAMSS_8x96, CAMSS_660, CAMSS_845, @@ -93,6 +98,7 @@ struct camss_resources { const struct camss_subdev_resources *csid_res; const struct camss_subdev_resources *ispif_res; const struct camss_subdev_resources *vfe_res; + const struct resources_wrapper *csid_wrapper_res; const struct resources_icc *icc_res; const unsigned int icc_path_num; const unsigned int csiphy_num; @@ -110,6 +116,7 @@ struct camss { struct csid_device *csid; struct ispif_device *ispif; struct vfe_device *vfe; + void __iomem *csid_wrapper_base; atomic_t ref_count; int genpd_num; struct device *genpd; diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 84e95a46dfc9..2d27c5167246 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -19,6 +19,7 @@ #include <linux/pm_domain.h> #include <linux/pm_runtime.h> #include <media/videobuf2-v4l2.h> +#include <media/v4l2-ctrls.h> #include <media/v4l2-mem2mem.h> #include <media/v4l2-ioctl.h> @@ -412,8 +413,8 @@ err_of_depopulate: of_platform_depopulate(dev); err_runtime_disable: pm_runtime_put_noidle(dev); - pm_runtime_set_suspended(dev); pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); hfi_destroy(core); err_core_deinit: hfi_core_deinit(core, false); @@ -502,6 +503,30 @@ err_cpucfg_path: return ret; } +void venus_close_common(struct venus_inst *inst) +{ + /* + * First, remove the inst from the ->instances list, so that + * to_instance() will return NULL. + */ + hfi_session_destroy(inst); + /* + * Second, make sure we don't have IRQ/IRQ-thread currently running + * or pending execution, which would race with the inst destruction. + */ + synchronize_irq(inst->core->irq); + + v4l2_m2m_ctx_release(inst->m2m_ctx); + v4l2_m2m_release(inst->m2m_dev); + v4l2_fh_del(&inst->fh); + v4l2_fh_exit(&inst->fh); + v4l2_ctrl_handler_free(&inst->ctrl_handler); + + mutex_destroy(&inst->lock); + mutex_destroy(&inst->ctx_q_lock); +} +EXPORT_SYMBOL_GPL(venus_close_common); + static __maybe_unused int venus_runtime_resume(struct device *dev) { struct venus_core *core = dev_get_drvdata(dev); @@ -752,7 +777,7 @@ static const struct venus_resources sdm845_res_v2 = { .vcodec_clks_num = 2, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" }, .vcodec_pmdomains_num = 3, - .opp_pmdomain = (const char *[]) { "cx", NULL }, + .opp_pmdomain = (const char *[]) { "cx" }, .vcodec_num = 2, .max_load = 3110400, /* 4096x2160@90 */ .hfi_version = HFI_VERSION_4XX, @@ -801,7 +826,7 @@ static const struct venus_resources sc7180_res = { .vcodec_clks_num = 2, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, - .opp_pmdomain = (const char *[]) { "cx", NULL }, + .opp_pmdomain = (const char *[]) { "cx" }, .vcodec_num = 1, .hfi_version = HFI_VERSION_4XX, .vpu_version = VPU_VERSION_AR50, @@ -858,7 +883,7 @@ static const struct venus_resources sm8250_res = { .vcodec_clks_num = 1, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, - .opp_pmdomain = (const char *[]) { "mx", NULL }, + .opp_pmdomain = (const char *[]) { "mx" }, .vcodec_num = 1, .max_load = 7833600, .hfi_version = HFI_VERSION_6XX, @@ -917,7 +942,7 @@ static const struct venus_resources sc7280_res = { .vcodec_clks_num = 2, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, - .opp_pmdomain = (const char *[]) { "cx", NULL }, + .opp_pmdomain = (const char *[]) { "cx" }, .vcodec_num = 1, .hfi_version = HFI_VERSION_6XX, .vpu_version = VPU_VERSION_IRIS2_1, @@ -949,7 +974,7 @@ MODULE_DEVICE_TABLE(of, venus_dt_match); static struct platform_driver qcom_venus_driver = { .probe = venus_probe, - .remove_new = venus_remove, + .remove = venus_remove, .driver = { .name = "qcom-venus", .of_match_table = venus_dt_match, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 55202b89e1b9..44f1c3bc4186 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -26,6 +26,7 @@ #define VIDC_CLKS_NUM_MAX 4 #define VIDC_VCODEC_CLKS_NUM_MAX 2 #define VIDC_RESETS_NUM_MAX 2 +#define VIDC_MAX_HIER_CODING_LAYER 6 extern int venus_fw_debug; @@ -132,9 +133,7 @@ struct venus_format { * @vcodec1_clks: an array of vcodec1 struct clk pointers * @video_path: an interconnect handle to video to/from memory path * @cpucfg_path: an interconnect handle to cpu configuration path - * @has_opp_table: does OPP table exist * @pmdomains: a pointer to a list of pmdomains - * @opp_dl_venus: an device-link for device OPP * @opp_pmdomain: an OPP power-domain * @resets: an array of reset signals * @vdev_dec: a reference to video device structure for decoder instances @@ -186,10 +185,8 @@ struct venus_core { struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; struct icc_path *video_path; struct icc_path *cpucfg_path; - bool has_opp_table; struct dev_pm_domain_list *pmdomains; - struct device_link *opp_dl_venus; - struct device *opp_pmdomain; + struct dev_pm_domain_list *opp_pmdomain; struct reset_control *resets[VIDC_RESETS_NUM_MAX]; struct video_device *vdev_dec; struct video_device *vdev_enc; @@ -255,6 +252,7 @@ struct venc_controls { u32 rc_enable; u32 const_quality; u32 frame_skip_mode; + u32 layer_bitrate; u32 h264_i_period; u32 h264_entropy_mode; @@ -273,6 +271,8 @@ struct venc_controls { s32 h264_loop_filter_alpha; s32 h264_loop_filter_beta; u32 h264_8x8_transform; + u32 h264_hier_layers; + u32 h264_hier_layer_bitrate[VIDC_MAX_HIER_CODING_LAYER]; u32 hevc_i_qp; u32 hevc_p_qp; @@ -564,4 +564,6 @@ is_fw_rev_or_older(struct venus_core *core, u32 vmajor, u32 vminor, u32 vrev) (core)->venus_ver.minor == vminor && (core)->venus_ver.rev <= vrev); } + +void venus_close_common(struct venus_inst *inst); #endif diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index ea8a2bd9419e..33a5a659c0ad 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -864,7 +864,6 @@ static int venc_power_v4(struct device *dev, int on) static int vcodec_domains_get(struct venus_core *core) { int ret; - struct device **opp_virt_dev; struct device *dev = core->dev; const struct venus_resources *res = core->res; struct dev_pm_domain_attach_data vcodec_data = { @@ -872,6 +871,11 @@ static int vcodec_domains_get(struct venus_core *core) .num_pd_names = res->vcodec_pmdomains_num, .pd_flags = PD_FLAG_NO_DEV_LINK, }; + struct dev_pm_domain_attach_data opp_pd_data = { + .pd_names = res->opp_pmdomain, + .num_pd_names = 1, + .pd_flags = PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP, + }; if (!res->vcodec_pmdomains_num) goto skip_pmdomains; @@ -881,37 +885,15 @@ static int vcodec_domains_get(struct venus_core *core) return ret; skip_pmdomains: - if (!core->res->opp_pmdomain) + if (!res->opp_pmdomain) return 0; /* Attach the power domain for setting performance state */ - ret = devm_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev); - if (ret) - goto opp_attach_err; - - core->opp_pmdomain = *opp_virt_dev; - core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain, - DL_FLAG_RPM_ACTIVE | - DL_FLAG_PM_RUNTIME | - DL_FLAG_STATELESS); - if (!core->opp_dl_venus) { - ret = -ENODEV; - goto opp_attach_err; - } + ret = devm_pm_domain_attach_list(dev, &opp_pd_data, &core->opp_pmdomain); + if (ret < 0) + return ret; return 0; - -opp_attach_err: - return ret; -} - -static void vcodec_domains_put(struct venus_core *core) -{ - if (!core->has_opp_table) - return; - - if (core->opp_dl_venus) - device_link_del(core->opp_dl_venus); } static int core_resets_reset(struct venus_core *core) @@ -1000,9 +982,7 @@ static int core_get_v4(struct venus_core *core) if (core->res->opp_pmdomain) { ret = devm_pm_opp_of_add_table(dev); - if (!ret) { - core->has_opp_table = true; - } else if (ret != -ENODEV) { + if (ret && ret != -ENODEV) { dev_err(dev, "invalid OPP table in device tree\n"); return ret; } @@ -1013,10 +993,6 @@ static int core_get_v4(struct venus_core *core) static void core_put_v4(struct venus_core *core) { - if (legacy_binding) - return; - - vcodec_domains_put(core); } static int core_power_v4(struct venus_core *core, int on) diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index d12089370d91..98c22b9f9372 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -1735,7 +1735,7 @@ err_m2m_release: err_session_destroy: hfi_session_destroy(inst); err_ctrl_deinit: - vdec_ctrl_deinit(inst); + v4l2_ctrl_handler_free(&inst->ctrl_handler); err_free: kfree(inst); return ret; @@ -1746,18 +1746,9 @@ static int vdec_close(struct file *file) struct venus_inst *inst = to_inst(file); vdec_pm_get(inst); - cancel_work_sync(&inst->delayed_process_work); - v4l2_m2m_ctx_release(inst->m2m_ctx); - v4l2_m2m_release(inst->m2m_dev); - vdec_ctrl_deinit(inst); + venus_close_common(inst); ida_destroy(&inst->dpb_ids); - hfi_session_destroy(inst); - mutex_destroy(&inst->lock); - mutex_destroy(&inst->ctx_q_lock); - v4l2_fh_del(&inst->fh); - v4l2_fh_exit(&inst->fh); - vdec_pm_put(inst, false); kfree(inst); @@ -1875,7 +1866,7 @@ MODULE_DEVICE_TABLE(of, vdec_dt_match); static struct platform_driver qcom_venus_dec_driver = { .probe = vdec_probe, - .remove_new = vdec_remove, + .remove = vdec_remove, .driver = { .name = "qcom-venus-decoder", .of_match_table = vdec_dt_match, diff --git a/drivers/media/platform/qcom/venus/vdec.h b/drivers/media/platform/qcom/venus/vdec.h index 6b262d0bf561..0cf981108ff0 100644 --- a/drivers/media/platform/qcom/venus/vdec.h +++ b/drivers/media/platform/qcom/venus/vdec.h @@ -9,6 +9,5 @@ struct venus_inst; int vdec_ctrl_init(struct venus_inst *inst); -void vdec_ctrl_deinit(struct venus_inst *inst); #endif diff --git a/drivers/media/platform/qcom/venus/vdec_ctrls.c b/drivers/media/platform/qcom/venus/vdec_ctrls.c index 7e0f29bf7fae..36ed955b0419 100644 --- a/drivers/media/platform/qcom/venus/vdec_ctrls.c +++ b/drivers/media/platform/qcom/venus/vdec_ctrls.c @@ -187,8 +187,3 @@ int vdec_ctrl_init(struct venus_inst *inst) return 0; } - -void vdec_ctrl_deinit(struct venus_inst *inst) -{ - v4l2_ctrl_handler_free(&inst->ctrl_handler); -} diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 3ec2fb8d9fab..c1c543535aaf 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -734,6 +734,29 @@ static int venc_set_properties(struct venus_inst *inst) if (ret) return ret; + if (ctr->layer_bitrate) { + unsigned int i; + + ptype = HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER; + ret = hfi_session_set_property(inst, ptype, &ctr->h264_hier_layers); + if (ret) + return ret; + + ptype = HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER; + ret = hfi_session_set_property(inst, ptype, &ctr->layer_bitrate); + if (ret) + return ret; + + for (i = 0; i < ctr->h264_hier_layers; ++i) { + ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; + brate.bitrate = ctr->h264_hier_layer_bitrate[i]; + brate.layer_id = i; + + ret = hfi_session_set_property(inst, ptype, &brate); + if (ret) + return ret; + } + } } if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || @@ -823,18 +846,33 @@ static int venc_set_properties(struct venus_inst *inst) return ret; } - if (!ctr->bitrate) - bitrate = 64000; - else - bitrate = ctr->bitrate; + if (!ctr->layer_bitrate) { + if (!ctr->bitrate) + bitrate = 64000; + else + bitrate = ctr->bitrate; - ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; - brate.bitrate = bitrate; - brate.layer_id = 0; + ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; + brate.bitrate = bitrate; + brate.layer_id = 0; - ret = hfi_session_set_property(inst, ptype, &brate); - if (ret) - return ret; + ret = hfi_session_set_property(inst, ptype, &brate); + if (ret) + return ret; + + if (!ctr->bitrate_peak) + bitrate *= 2; + else + bitrate = ctr->bitrate_peak; + + ptype = HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE; + brate.bitrate = bitrate; + brate.layer_id = 0; + + ret = hfi_session_set_property(inst, ptype, &brate); + if (ret) + return ret; + } if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { @@ -849,19 +887,6 @@ static int venc_set_properties(struct venus_inst *inst) return ret; } - if (!ctr->bitrate_peak) - bitrate *= 2; - else - bitrate = ctr->bitrate_peak; - - ptype = HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE; - brate.bitrate = bitrate; - brate.layer_id = 0; - - ret = hfi_session_set_property(inst, ptype, &brate); - if (ret) - return ret; - ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP; if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { quant.qp_i = ctr->hevc_i_qp; @@ -1503,7 +1528,7 @@ err_m2m_release: err_session_destroy: hfi_session_destroy(inst); err_ctrl_deinit: - venc_ctrl_deinit(inst); + v4l2_ctrl_handler_free(&inst->ctrl_handler); err_free: kfree(inst); return ret; @@ -1514,18 +1539,8 @@ static int venc_close(struct file *file) struct venus_inst *inst = to_inst(file); venc_pm_get(inst); - - v4l2_m2m_ctx_release(inst->m2m_ctx); - v4l2_m2m_release(inst->m2m_dev); - venc_ctrl_deinit(inst); - hfi_session_destroy(inst); - mutex_destroy(&inst->lock); - mutex_destroy(&inst->ctx_q_lock); - v4l2_fh_del(&inst->fh); - v4l2_fh_exit(&inst->fh); - + venus_close_common(inst); inst->enc_state = VENUS_ENC_STATE_DEINIT; - venc_pm_put(inst, false); kfree(inst); @@ -1643,7 +1658,7 @@ MODULE_DEVICE_TABLE(of, venc_dt_match); static struct platform_driver qcom_venus_enc_driver = { .probe = venc_probe, - .remove_new = venc_remove, + .remove = venc_remove, .driver = { .name = "qcom-venus-encoder", .of_match_table = venc_dt_match, diff --git a/drivers/media/platform/qcom/venus/venc.h b/drivers/media/platform/qcom/venus/venc.h index 4ea37fdcd9b8..719d0f73b14b 100644 --- a/drivers/media/platform/qcom/venus/venc.h +++ b/drivers/media/platform/qcom/venus/venc.h @@ -9,6 +9,5 @@ struct venus_inst; int venc_ctrl_init(struct venus_inst *inst); -void venc_ctrl_deinit(struct venus_inst *inst); #endif diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index d9d2a293f3ef..51801a962ed2 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -67,12 +67,28 @@ static int venc_calc_bpframes(u32 gop_size, u32 conseq_b, u32 *bf, u32 *pf) return 0; } +static int dynamic_bitrate_update(struct venus_inst *inst, u32 bitrate, + u32 layer_id) +{ + int ret = 0; + + mutex_lock(&inst->lock); + if (inst->streamon_out && inst->streamon_cap) { + u32 ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; + struct hfi_bitrate brate = { .bitrate = bitrate, .layer_id = layer_id }; + + ret = hfi_session_set_property(inst, ptype, &brate); + } + mutex_unlock(&inst->lock); + + return ret; +} + static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) { struct venus_inst *inst = ctrl_to_inst(ctrl); struct venc_controls *ctr = &inst->controls.enc; struct hfi_enable en = { .enable = 1 }; - struct hfi_bitrate brate; struct hfi_ltr_use ltr_use; struct hfi_ltr_mark ltr_mark; u32 bframes; @@ -85,19 +101,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_MPEG_VIDEO_BITRATE: ctr->bitrate = ctrl->val; - mutex_lock(&inst->lock); - if (inst->streamon_out && inst->streamon_cap) { - ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; - brate.bitrate = ctr->bitrate; - brate.layer_id = 0; - - ret = hfi_session_set_property(inst, ptype, &brate); - if (ret) { - mutex_unlock(&inst->lock); - return ret; - } - } - mutex_unlock(&inst->lock); + ret = dynamic_bitrate_update(inst, ctr->bitrate, 0); + if (ret) + return ret; break; case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: ctr->bitrate_peak = ctrl->val; @@ -340,6 +346,55 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) ctr->h264_8x8_transform = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: + if (ctrl->val != V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P) + return -EINVAL; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING: + ctr->layer_bitrate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER: + if (ctrl->val > VIDC_MAX_HIER_CODING_LAYER) + return -EINVAL; + ctr->h264_hier_layers = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR: + ctr->h264_hier_layer_bitrate[0] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[0], 0); + if (ret) + return ret; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR: + ctr->h264_hier_layer_bitrate[1] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[1], 1); + if (ret) + return ret; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR: + ctr->h264_hier_layer_bitrate[2] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[2], 2); + if (ret) + return ret; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR: + ctr->h264_hier_layer_bitrate[3] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[3], 3); + if (ret) + return ret; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR: + ctr->h264_hier_layer_bitrate[4] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[4], 4); + if (ret) + return ret; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR: + ctr->h264_hier_layer_bitrate[5] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[5], 5); + if (ret) + return ret; + break; + default: return -EINVAL; } @@ -622,6 +677,49 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, 0, ((4096 * 2304) >> 8), 1, 0); + if (IS_V4(inst->core) || IS_V6(inst->core)) { + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + 1, V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, 0, 1, 1, 0); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, 0, + VIDC_MAX_HIER_CODING_LAYER, 1, 0); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + BITRATE_MIN, BITRATE_MAX, BITRATE_STEP, BITRATE_DEFAULT); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + BITRATE_MIN, BITRATE_MAX, + BITRATE_STEP, BITRATE_DEFAULT); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + BITRATE_MIN, BITRATE_MAX, + BITRATE_STEP, BITRATE_DEFAULT); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + BITRATE_MIN, BITRATE_MAX, + BITRATE_STEP, BITRATE_DEFAULT); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + BITRATE_MIN, BITRATE_MAX, + BITRATE_STEP, BITRATE_DEFAULT); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + BITRATE_MIN, BITRATE_MAX, + BITRATE_STEP, BITRATE_DEFAULT); + } + ret = inst->ctrl_handler.error; if (ret) goto err; @@ -635,8 +733,3 @@ err: v4l2_ctrl_handler_free(&inst->ctrl_handler); return ret; } - -void venc_ctrl_deinit(struct venus_inst *inst) -{ - v4l2_ctrl_handler_free(&inst->ctrl_handler); -} diff --git a/drivers/media/platform/raspberrypi/Kconfig b/drivers/media/platform/raspberrypi/Kconfig index e928f979019e..bd5101ffefb5 100644 --- a/drivers/media/platform/raspberrypi/Kconfig +++ b/drivers/media/platform/raspberrypi/Kconfig @@ -3,3 +3,4 @@ comment "Raspberry Pi media platform drivers" source "drivers/media/platform/raspberrypi/pisp_be/Kconfig" +source "drivers/media/platform/raspberrypi/rp1-cfe/Kconfig" diff --git a/drivers/media/platform/raspberrypi/Makefile b/drivers/media/platform/raspberrypi/Makefile index c0d1a2dab486..af7fde84eefe 100644 --- a/drivers/media/platform/raspberrypi/Makefile +++ b/drivers/media/platform/raspberrypi/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += pisp_be/ +obj-y += rp1-cfe/ diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c index 65ff2382cffe..7596ae1f7de6 100644 --- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c +++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c @@ -1781,7 +1781,7 @@ MODULE_DEVICE_TABLE(of, pispbe_of_match); static struct platform_driver pispbe_pdrv = { .probe = pispbe_probe, - .remove_new = pispbe_remove, + .remove = pispbe_remove, .driver = { .name = PISPBE_NAME, .of_match_table = pispbe_of_match, diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/Kconfig b/drivers/media/platform/raspberrypi/rp1-cfe/Kconfig new file mode 100644 index 000000000000..327b61f1134b --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/Kconfig @@ -0,0 +1,15 @@ +# RP1 V4L2 camera support + +config VIDEO_RP1_CFE + tristate "Raspberry Pi RP1 Camera Front End (CFE) video capture driver" + depends on VIDEO_DEV + depends on PM + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + help + Say Y here to enable support for the Raspberry Pi RP1 Camera Front End. + + To compile this driver as a module, choose M here. The module will be + called rp1-cfe. diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/Makefile b/drivers/media/platform/raspberrypi/rp1-cfe/Makefile new file mode 100644 index 000000000000..3f0d0fc8570e --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for RP1 Camera Front End driver +# +rp1-cfe-objs := cfe.o csi2.o pisp-fe.o dphy.o +obj-$(CONFIG_VIDEO_RP1_CFE) += rp1-cfe.o diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe-fmts.h b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-fmts.h new file mode 100644 index 000000000000..7aecf7f83733 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-fmts.h @@ -0,0 +1,332 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * RP1 Camera Front End formats definition + * + * Copyright (C) 2021-2024 - Raspberry Pi Ltd. + */ +#ifndef _CFE_FMTS_H_ +#define _CFE_FMTS_H_ + +#include "cfe.h" +#include <media/mipi-csi2.h> + +static const struct cfe_fmt formats[] = { + /* YUV Formats */ + { + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + }, + { + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + }, + { + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + }, + { + /* RGB Formats */ + .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RGB565, + }, + { .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RGB565, + }, + { + .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RGB555, + }, + { + .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RGB555, + }, + { + .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ + .code = MEDIA_BUS_FMT_RGB888_1X24, + .depth = 24, + .csi_dt = MIPI_CSI2_DT_RGB888, + }, + { + .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ + .code = MEDIA_BUS_FMT_BGR888_1X24, + .depth = 24, + .csi_dt = MIPI_CSI2_DT_RGB888, + }, + { + .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ + .code = MEDIA_BUS_FMT_ARGB8888_1X32, + .depth = 32, + .csi_dt = 0x0, + }, + + /* Bayer Formats */ + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10P, + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10P, + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10P, + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10P, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12P, + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12P, + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12P, + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12P, + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR14P, + .code = MEDIA_BUS_FMT_SBGGR14_1X14, + .depth = 14, + .csi_dt = MIPI_CSI2_DT_RAW14, + .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG14P, + .code = MEDIA_BUS_FMT_SGBRG14_1X14, + .depth = 14, + .csi_dt = MIPI_CSI2_DT_RAW14, + .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG14P, + .code = MEDIA_BUS_FMT_SGRBG14_1X14, + .depth = 14, + .csi_dt = MIPI_CSI2_DT_RAW14, + .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB14P, + .code = MEDIA_BUS_FMT_SRGGB14_1X14, + .depth = 14, + .csi_dt = MIPI_CSI2_DT_RAW14, + .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR16, + .code = MEDIA_BUS_FMT_SBGGR16_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RAW16, + .flags = CFE_FORMAT_FLAG_FE_OUT, + .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG16, + .code = MEDIA_BUS_FMT_SGBRG16_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RAW16, + .flags = CFE_FORMAT_FLAG_FE_OUT, + .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG16, + .code = MEDIA_BUS_FMT_SGRBG16_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RAW16, + .flags = CFE_FORMAT_FLAG_FE_OUT, + .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB16, + .code = MEDIA_BUS_FMT_SRGGB16_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RAW16, + .flags = CFE_FORMAT_FLAG_FE_OUT, + .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + /* PiSP Compressed Mode 1 */ + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_RGGB, + .code = MEDIA_BUS_FMT_SRGGB16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_BGGR, + .code = MEDIA_BUS_FMT_SBGGR16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_GBRG, + .code = MEDIA_BUS_FMT_SGBRG16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_GRBG, + .code = MEDIA_BUS_FMT_SGRBG16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + /* Greyscale format */ + { + .fourcc = V4L2_PIX_FMT_GREY, + .code = MEDIA_BUS_FMT_Y8_1X8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_Y10P, + .code = MEDIA_BUS_FMT_Y10_1X10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_Y12P, + .code = MEDIA_BUS_FMT_Y12_1X12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_Y14P, + .code = MEDIA_BUS_FMT_Y14_1X14, + .depth = 14, + .csi_dt = MIPI_CSI2_DT_RAW14, + .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_Y16, + .code = MEDIA_BUS_FMT_Y16_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RAW16, + .flags = CFE_FORMAT_FLAG_FE_OUT, + .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_MONO, + .code = MEDIA_BUS_FMT_Y16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + + /* Embedded data formats */ + { + .fourcc = V4L2_META_FMT_GENERIC_8, + .code = MEDIA_BUS_FMT_META_8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_EMBEDDED_8B, + .flags = CFE_FORMAT_FLAG_META_CAP, + }, + { + .fourcc = V4L2_META_FMT_GENERIC_CSI2_10, + .code = MEDIA_BUS_FMT_META_10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_EMBEDDED_8B, + .flags = CFE_FORMAT_FLAG_META_CAP, + }, + { + .fourcc = V4L2_META_FMT_GENERIC_CSI2_12, + .code = MEDIA_BUS_FMT_META_12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_EMBEDDED_8B, + .flags = CFE_FORMAT_FLAG_META_CAP, + }, + + /* Frontend formats */ + { + .fourcc = V4L2_META_FMT_RPI_FE_CFG, + .code = MEDIA_BUS_FMT_FIXED, + .flags = CFE_FORMAT_FLAG_META_OUT, + }, + { + .fourcc = V4L2_META_FMT_RPI_FE_STATS, + .code = MEDIA_BUS_FMT_FIXED, + .flags = CFE_FORMAT_FLAG_META_CAP, + }, +}; + +#endif /* _CFE_FMTS_H_ */ diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace.h b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace.h new file mode 100644 index 000000000000..1a36259f51b7 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace.h @@ -0,0 +1,202 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 Raspberry Pi Ltd. + * Copyright (c) 2024 Ideas on Board Oy + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cfe + +#if !defined(_CFE_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _CFE_TRACE_H + +#include <linux/tracepoint.h> +#include <media/videobuf2-v4l2.h> + +TRACE_EVENT(cfe_return_buffer, + TP_PROTO(u32 node_id, u32 buf_idx, u32 queue_id), + TP_ARGS(node_id, buf_idx, queue_id), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, buf_idx) + __field(u32, queue_id) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->buf_idx = buf_idx; + __entry->queue_id = queue_id; + ), + TP_printk("node=%u buf=%u, queue=%u", __entry->node_id, + __entry->buf_idx, __entry->queue_id) +); + +DECLARE_EVENT_CLASS(cfe_buffer_template, + TP_PROTO(u32 node_id, struct vb2_buffer *buf), + TP_ARGS(node_id, buf), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, buf_idx) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->buf_idx = buf->index; + ), + TP_printk("node=%u buf=%u", __entry->node_id, __entry->buf_idx) +); + +DEFINE_EVENT(cfe_buffer_template, cfe_buffer_prepare, + TP_PROTO(u32 node_id, struct vb2_buffer *buf), + TP_ARGS(node_id, buf)); + +TRACE_EVENT(cfe_buffer_queue, + TP_PROTO(u32 node_id, struct vb2_buffer *buf, bool schedule_now), + TP_ARGS(node_id, buf, schedule_now), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, buf_idx) + __field(bool, schedule_now) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->buf_idx = buf->index; + __entry->schedule_now = schedule_now; + ), + TP_printk("node=%u buf=%u%s", __entry->node_id, __entry->buf_idx, + __entry->schedule_now ? " schedule immediately" : "") +); + +DEFINE_EVENT(cfe_buffer_template, cfe_csi2_schedule, + TP_PROTO(u32 node_id, struct vb2_buffer *buf), + TP_ARGS(node_id, buf)); + +DEFINE_EVENT(cfe_buffer_template, cfe_fe_schedule, + TP_PROTO(u32 node_id, struct vb2_buffer *buf), + TP_ARGS(node_id, buf)); + +TRACE_EVENT(cfe_buffer_complete, + TP_PROTO(u32 node_id, struct vb2_v4l2_buffer *buf), + TP_ARGS(node_id, buf), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, buf_idx) + __field(u32, seq) + __field(u64, ts) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->buf_idx = buf->vb2_buf.index; + __entry->seq = buf->sequence; + __entry->ts = buf->vb2_buf.timestamp; + ), + TP_printk("node=%u buf=%u seq=%u ts=%llu", __entry->node_id, + __entry->buf_idx, __entry->seq, __entry->ts) +); + +TRACE_EVENT(cfe_frame_start, + TP_PROTO(u32 node_id, u32 fs_count), + TP_ARGS(node_id, fs_count), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, fs_count) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->fs_count = fs_count; + ), + TP_printk("node=%u fs_count=%u", __entry->node_id, __entry->fs_count) +); + +TRACE_EVENT(cfe_frame_end, + TP_PROTO(u32 node_id, u32 fs_count), + TP_ARGS(node_id, fs_count), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, fs_count) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->fs_count = fs_count; + ), + TP_printk("node=%u fs_count=%u", __entry->node_id, __entry->fs_count) +); + +TRACE_EVENT(cfe_prepare_next_job, + TP_PROTO(bool fe_enabled), + TP_ARGS(fe_enabled), + TP_STRUCT__entry( + __field(bool, fe_enabled) + ), + TP_fast_assign( + __entry->fe_enabled = fe_enabled; + ), + TP_printk("fe_enabled=%u", __entry->fe_enabled) +); + +/* These are copied from csi2.c */ +#define CSI2_STATUS_IRQ_FS(x) (BIT(0) << (x)) +#define CSI2_STATUS_IRQ_FE(x) (BIT(4) << (x)) +#define CSI2_STATUS_IRQ_FE_ACK(x) (BIT(8) << (x)) +#define CSI2_STATUS_IRQ_LE(x) (BIT(12) << (x)) +#define CSI2_STATUS_IRQ_LE_ACK(x) (BIT(16) << (x)) + +TRACE_EVENT(csi2_irq, + TP_PROTO(u32 channel, u32 status, u32 dbg), + TP_ARGS(channel, status, dbg), + TP_STRUCT__entry( + __field(u32, channel) + __field(u32, status) + __field(u32, dbg) + ), + TP_fast_assign( + __entry->channel = channel; + __entry->status = status; + __entry->dbg = dbg; + ), + TP_printk("ch=%u flags=[ %s%s%s%s%s] frame=%u line=%u\n", + __entry->channel, + (__entry->status & CSI2_STATUS_IRQ_FS(__entry->channel)) ? + "FS " : "", + (__entry->status & CSI2_STATUS_IRQ_FE(__entry->channel)) ? + "FE " : "", + (__entry->status & CSI2_STATUS_IRQ_FE_ACK(__entry->channel)) ? + "FE_ACK " : "", + (__entry->status & CSI2_STATUS_IRQ_LE(__entry->channel)) ? + "LE " : "", + (__entry->status & CSI2_STATUS_IRQ_LE_ACK(__entry->channel)) ? + "LE_ACK " : "", + __entry->dbg >> 16, __entry->dbg & 0xffff) +); + +TRACE_EVENT(fe_irq, + TP_PROTO(u32 status, u32 output_status, u32 frame_status, + u32 error_status, u32 int_status), + TP_ARGS(status, output_status, frame_status, error_status, int_status), + TP_STRUCT__entry( + __field(u32, status) + __field(u32, output_status) + __field(u32, frame_status) + __field(u32, error_status) + __field(u32, int_status) + ), + TP_fast_assign( + __entry->status = status; + __entry->output_status = output_status; + __entry->frame_status = frame_status; + __entry->error_status = error_status; + __entry->int_status = int_status; + ), + TP_printk("status 0x%x out_status 0x%x frame_status 0x%x error_status 0x%x int_status 0x%x", + __entry->status, + __entry->output_status, + __entry->frame_status, + __entry->error_status, + __entry->int_status) +); + +#endif /* _CFE_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE ../../drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace +#include <trace/define_trace.h> diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c new file mode 100644 index 000000000000..12660087b12f --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c @@ -0,0 +1,2509 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RP1 Camera Front End Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ + +#include <linux/clk.h> +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/fwnode.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/lcm.h> +#include <linux/math.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/videodev2.h> + +#include <media/v4l2-async.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mc.h> +#include <media/videobuf2-dma-contig.h> + +#include <linux/media/raspberrypi/pisp_fe_config.h> +#include <linux/media/raspberrypi/pisp_fe_statistics.h> + +#include "cfe-fmts.h" +#include "cfe.h" +#include "csi2.h" +#include "pisp-fe.h" + +#define CREATE_TRACE_POINTS +#include "cfe-trace.h" + +#define CFE_MODULE_NAME "rp1-cfe" +#define CFE_VERSION "1.0" + +#define cfe_dbg(cfe, fmt, arg...) dev_dbg(&(cfe)->pdev->dev, fmt, ##arg) +#define cfe_info(cfe, fmt, arg...) dev_info(&(cfe)->pdev->dev, fmt, ##arg) +#define cfe_err(cfe, fmt, arg...) dev_err(&(cfe)->pdev->dev, fmt, ##arg) + +/* MIPICFG registers */ +#define MIPICFG_CFG 0x004 +#define MIPICFG_INTR 0x028 +#define MIPICFG_INTE 0x02c +#define MIPICFG_INTF 0x030 +#define MIPICFG_INTS 0x034 + +#define MIPICFG_CFG_SEL_CSI BIT(0) + +#define MIPICFG_INT_CSI_DMA BIT(0) +#define MIPICFG_INT_CSI_HOST BIT(2) +#define MIPICFG_INT_PISP_FE BIT(4) + +#define BPL_ALIGNMENT 16 +#define MAX_BYTESPERLINE 0xffffff00 +#define MAX_BUFFER_SIZE 0xffffff00 +/* + * Max width is therefore determined by the max stride divided by the number of + * bits per pixel. + * + * However, to avoid overflow issues let's use a 16k maximum. This lets us + * calculate 16k * 16k * 4 with 32bits. If we need higher maximums, a careful + * review and adjustment of the code is needed so that it will deal with + * overflows correctly. + */ +#define MAX_WIDTH 16384 +#define MAX_HEIGHT MAX_WIDTH +/* Define a nominal minimum image size */ +#define MIN_WIDTH 16 +#define MIN_HEIGHT 16 + +#define MIN_META_WIDTH 4 +#define MIN_META_HEIGHT 1 + +const struct v4l2_mbus_framefmt cfe_default_format = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_RAW, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .xfer_func = V4L2_XFER_FUNC_NONE, +}; + +enum node_ids { + /* CSI2 HW output nodes first. */ + CSI2_CH0, + CSI2_CH1, + CSI2_CH2, + CSI2_CH3, + /* FE only nodes from here on. */ + FE_OUT0, + FE_OUT1, + FE_STATS, + FE_CONFIG, + NUM_NODES +}; + +struct node_description { + enum node_ids id; + const char *name; + unsigned int caps; + unsigned int pad_flags; + unsigned int link_pad; +}; + +/* Must match the ordering of enum ids */ +static const struct node_description node_desc[NUM_NODES] = { + [CSI2_CH0] = { + .name = "csi2-ch0", + .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_PAD_FIRST_SOURCE + 0 + }, + /* + * At the moment the main userspace component (libcamera) doesn't + * support metadata with video nodes that support both video and + * metadata. So for the time being this node is set to only support + * V4L2_CAP_META_CAPTURE. + */ + [CSI2_CH1] = { + .name = "csi2-ch1", + .caps = V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_PAD_FIRST_SOURCE + 1 + }, + [CSI2_CH2] = { + .name = "csi2-ch2", + .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_PAD_FIRST_SOURCE + 2 + }, + [CSI2_CH3] = { + .name = "csi2-ch3", + .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_PAD_FIRST_SOURCE + 3 + }, + [FE_OUT0] = { + .name = "fe-image0", + .caps = V4L2_CAP_VIDEO_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_OUTPUT0_PAD + }, + [FE_OUT1] = { + .name = "fe-image1", + .caps = V4L2_CAP_VIDEO_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_OUTPUT1_PAD + }, + [FE_STATS] = { + .name = "fe-stats", + .caps = V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_STATS_PAD + }, + [FE_CONFIG] = { + .name = "fe-config", + .caps = V4L2_CAP_META_OUTPUT, + .pad_flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_CONFIG_PAD + }, +}; + +#define is_fe_node(node) (((node)->id) >= FE_OUT0) +#define is_csi2_node(node) (!is_fe_node(node)) + +#define node_supports_image_output(node) \ + (node_desc[(node)->id].caps & V4L2_CAP_VIDEO_CAPTURE) +#define node_supports_meta_output(node) \ + (node_desc[(node)->id].caps & V4L2_CAP_META_CAPTURE) +#define node_supports_image_input(node) \ + (node_desc[(node)->id].caps & V4L2_CAP_VIDEO_OUTPUT) +#define node_supports_meta_input(node) \ + (node_desc[(node)->id].caps & V4L2_CAP_META_OUTPUT) +#define node_supports_image(node) \ + (node_supports_image_output(node) || node_supports_image_input(node)) +#define node_supports_meta(node) \ + (node_supports_meta_output(node) || node_supports_meta_input(node)) + +#define is_image_output_node(node) \ + ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) +#define is_image_input_node(node) \ + ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) +#define is_image_node(node) \ + (is_image_output_node(node) || is_image_input_node(node)) +#define is_meta_output_node(node) \ + ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_CAPTURE) +#define is_meta_input_node(node) \ + ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_OUTPUT) +#define is_meta_node(node) \ + (is_meta_output_node(node) || is_meta_input_node(node)) + +/* To track state across all nodes. */ +#define NODE_REGISTERED BIT(0) +#define NODE_ENABLED BIT(1) +#define NODE_STREAMING BIT(2) +#define FS_INT BIT(3) +#define FE_INT BIT(4) +#define NUM_STATES 5 + +struct cfe_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +struct cfe_config_buffer { + struct cfe_buffer buf; + struct pisp_fe_config config; +}; + +static inline struct cfe_buffer *to_cfe_buffer(struct vb2_buffer *vb) +{ + return container_of(vb, struct cfe_buffer, vb.vb2_buf); +} + +static inline +struct cfe_config_buffer *to_cfe_config_buffer(struct cfe_buffer *buf) +{ + return container_of(buf, struct cfe_config_buffer, buf); +} + +struct cfe_node { + /* Node id */ + enum node_ids id; + /* Pointer pointing to current v4l2_buffer */ + struct cfe_buffer *cur_frm; + /* Pointer pointing to next v4l2_buffer */ + struct cfe_buffer *next_frm; + /* Used to store current pixel format */ + struct v4l2_format vid_fmt; + /* Used to store current meta format */ + struct v4l2_format meta_fmt; + /* Buffer queue used in video-buf */ + struct vb2_queue buffer_queue; + /* Queue of filled frames */ + struct list_head dma_queue; + /* lock used to access this structure */ + struct mutex lock; + /* Identifies video device for this channel */ + struct video_device video_dev; + /* Pointer to the parent handle */ + struct cfe_device *cfe; + /* Media pad for this node */ + struct media_pad pad; + /* Frame-start counter */ + unsigned int fs_count; + /* Timestamp of the current buffer */ + u64 ts; +}; + +struct cfe_device { + struct dentry *debugfs; + struct kref kref; + + /* peripheral base address */ + void __iomem *mipi_cfg_base; + + struct clk *clk; + + /* V4l2 device */ + struct v4l2_device v4l2_dev; + struct media_device mdev; + struct media_pipeline pipe; + + /* IRQ lock for node state and DMA queues */ + spinlock_t state_lock; + bool job_ready; + bool job_queued; + + /* parent device */ + struct platform_device *pdev; + /* subdevice async Notifier */ + struct v4l2_async_notifier notifier; + + /* Source sub device */ + struct v4l2_subdev *source_sd; + /* Source subdev's pad */ + u32 source_pad; + + struct cfe_node node[NUM_NODES]; + DECLARE_BITMAP(node_flags, NUM_STATES * NUM_NODES); + + struct csi2_device csi2; + struct pisp_fe_device fe; + + int fe_csi2_channel; + + /* Mask of enabled streams */ + u64 streams_mask; +}; + +static inline bool is_fe_enabled(struct cfe_device *cfe) +{ + return cfe->fe_csi2_channel != -1; +} + +static inline struct cfe_device *to_cfe_device(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct cfe_device, v4l2_dev); +} + +static inline u32 cfg_reg_read(struct cfe_device *cfe, u32 offset) +{ + return readl(cfe->mipi_cfg_base + offset); +} + +static inline void cfg_reg_write(struct cfe_device *cfe, u32 offset, u32 val) +{ + writel(val, cfe->mipi_cfg_base + offset); +} + +static bool check_state(struct cfe_device *cfe, unsigned long state, + unsigned int node_id) +{ + unsigned long bit; + + for_each_set_bit(bit, &state, sizeof(state)) { + if (!test_bit(bit + (node_id * NUM_STATES), cfe->node_flags)) + return false; + } + + return true; +} + +static void set_state(struct cfe_device *cfe, unsigned long state, + unsigned int node_id) +{ + unsigned long bit; + + for_each_set_bit(bit, &state, sizeof(state)) + set_bit(bit + (node_id * NUM_STATES), cfe->node_flags); +} + +static void clear_state(struct cfe_device *cfe, unsigned long state, + unsigned int node_id) +{ + unsigned long bit; + + for_each_set_bit(bit, &state, sizeof(state)) + clear_bit(bit + (node_id * NUM_STATES), cfe->node_flags); +} + +static bool test_any_node(struct cfe_device *cfe, unsigned long cond) +{ + for (unsigned int i = 0; i < NUM_NODES; i++) { + if (check_state(cfe, cond, i)) + return true; + } + + return false; +} + +static bool test_all_nodes(struct cfe_device *cfe, unsigned long precond, + unsigned long cond) +{ + for (unsigned int i = 0; i < NUM_NODES; i++) { + if (check_state(cfe, precond, i)) { + if (!check_state(cfe, cond, i)) + return false; + } + } + + return true; +} + +static int mipi_cfg_regs_show(struct seq_file *s, void *data) +{ + struct cfe_device *cfe = s->private; + int ret; + + ret = pm_runtime_resume_and_get(&cfe->pdev->dev); + if (ret) + return ret; + +#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", cfg_reg_read(cfe, reg)) + DUMP(MIPICFG_CFG); + DUMP(MIPICFG_INTR); + DUMP(MIPICFG_INTE); + DUMP(MIPICFG_INTF); + DUMP(MIPICFG_INTS); +#undef DUMP + + pm_runtime_put(&cfe->pdev->dev); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(mipi_cfg_regs); + +/* Format setup functions */ +const struct cfe_fmt *find_format_by_code(u32 code) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].code == code) + return &formats[i]; + } + + return NULL; +} + +const struct cfe_fmt *find_format_by_pix(u32 pixelformat) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].fourcc == pixelformat) + return &formats[i]; + } + + return NULL; +} + +static const struct cfe_fmt *find_format_by_code_and_fourcc(u32 code, + u32 fourcc) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].code == code && formats[i].fourcc == fourcc) + return &formats[i]; + } + + return NULL; +} + +/* + * Given the mbus code, find the 16 bit remapped code. Returns 0 if no remap + * possible. + */ +u32 cfe_find_16bit_code(u32 code) +{ + const struct cfe_fmt *cfe_fmt; + + cfe_fmt = find_format_by_code(code); + + if (!cfe_fmt || !cfe_fmt->remap[CFE_REMAP_16BIT]) + return 0; + + cfe_fmt = find_format_by_pix(cfe_fmt->remap[CFE_REMAP_16BIT]); + if (!cfe_fmt) + return 0; + + return cfe_fmt->code; +} + +/* + * Given the mbus code, find the 8 bit compressed code. Returns 0 if no remap + * possible. + */ +u32 cfe_find_compressed_code(u32 code) +{ + const struct cfe_fmt *cfe_fmt; + + cfe_fmt = find_format_by_code(code); + + if (!cfe_fmt || !cfe_fmt->remap[CFE_REMAP_COMPRESSED]) + return 0; + + cfe_fmt = find_format_by_pix(cfe_fmt->remap[CFE_REMAP_COMPRESSED]); + if (!cfe_fmt) + return 0; + + return cfe_fmt->code; +} + +static void cfe_calc_vid_format_size_bpl(struct cfe_device *cfe, + const struct cfe_fmt *fmt, + struct v4l2_format *f) +{ + unsigned int min_bytesperline; + + v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 2, + &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0, 0); + + min_bytesperline = + ALIGN((f->fmt.pix.width * fmt->depth) >> 3, BPL_ALIGNMENT); + + if (f->fmt.pix.bytesperline > min_bytesperline && + f->fmt.pix.bytesperline <= MAX_BYTESPERLINE) + f->fmt.pix.bytesperline = + ALIGN(f->fmt.pix.bytesperline, BPL_ALIGNMENT); + else + f->fmt.pix.bytesperline = min_bytesperline; + + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + + cfe_dbg(cfe, "%s: %p4cc size: %ux%u bpl:%u img_size:%u\n", __func__, + &f->fmt.pix.pixelformat, f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); +} + +static void cfe_calc_meta_format_size_bpl(struct cfe_device *cfe, + const struct cfe_fmt *fmt, + struct v4l2_format *f) +{ + v4l_bound_align_image(&f->fmt.meta.width, MIN_META_WIDTH, MAX_WIDTH, 2, + &f->fmt.meta.height, MIN_META_HEIGHT, MAX_HEIGHT, + 0, 0); + + f->fmt.meta.bytesperline = (f->fmt.meta.width * fmt->depth) >> 3; + f->fmt.meta.buffersize = f->fmt.meta.height * f->fmt.pix.bytesperline; + + cfe_dbg(cfe, "%s: %p4cc size: %ux%u bpl:%u buf_size:%u\n", __func__, + &f->fmt.meta.dataformat, f->fmt.meta.width, f->fmt.meta.height, + f->fmt.meta.bytesperline, f->fmt.meta.buffersize); +} + +static void cfe_schedule_next_csi2_job(struct cfe_device *cfe) +{ + struct cfe_buffer *buf; + dma_addr_t addr; + + for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; i++) { + struct cfe_node *node = &cfe->node[i]; + unsigned int stride, size; + + if (!check_state(cfe, NODE_STREAMING, i)) + continue; + + buf = list_first_entry(&node->dma_queue, struct cfe_buffer, + list); + node->next_frm = buf; + list_del(&buf->list); + + trace_cfe_csi2_schedule(node->id, &buf->vb.vb2_buf); + + if (is_meta_node(node)) { + size = node->meta_fmt.fmt.meta.buffersize; + /* We use CSI2_CH_CTRL_PACK_BYTES, so stride == 0 */ + stride = 0; + } else { + size = node->vid_fmt.fmt.pix.sizeimage; + stride = node->vid_fmt.fmt.pix.bytesperline; + } + + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + csi2_set_buffer(&cfe->csi2, node->id, addr, stride, size); + } +} + +static void cfe_schedule_next_pisp_job(struct cfe_device *cfe) +{ + struct vb2_buffer *vb2_bufs[FE_NUM_PADS] = { 0 }; + struct cfe_config_buffer *config_buf; + struct cfe_buffer *buf; + + for (unsigned int i = CSI2_NUM_CHANNELS; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + + if (!check_state(cfe, NODE_STREAMING, i)) + continue; + + buf = list_first_entry(&node->dma_queue, struct cfe_buffer, + list); + + trace_cfe_fe_schedule(node->id, &buf->vb.vb2_buf); + + node->next_frm = buf; + vb2_bufs[node_desc[i].link_pad] = &buf->vb.vb2_buf; + list_del(&buf->list); + } + + config_buf = to_cfe_config_buffer(cfe->node[FE_CONFIG].next_frm); + pisp_fe_submit_job(&cfe->fe, vb2_bufs, &config_buf->config); +} + +static bool cfe_check_job_ready(struct cfe_device *cfe) +{ + for (unsigned int i = 0; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + + if (!check_state(cfe, NODE_ENABLED, i)) + continue; + + if (list_empty(&node->dma_queue)) + return false; + } + + return true; +} + +static void cfe_prepare_next_job(struct cfe_device *cfe) +{ + trace_cfe_prepare_next_job(is_fe_enabled(cfe)); + + cfe->job_queued = true; + cfe_schedule_next_csi2_job(cfe); + if (is_fe_enabled(cfe)) + cfe_schedule_next_pisp_job(cfe); + + /* Flag if another job is ready after this. */ + cfe->job_ready = cfe_check_job_ready(cfe); +} + +static void cfe_process_buffer_complete(struct cfe_node *node, + enum vb2_buffer_state state) +{ + trace_cfe_buffer_complete(node->id, &node->cur_frm->vb); + + node->cur_frm->vb.sequence = node->fs_count - 1; + vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state); +} + +static void cfe_queue_event_sof(struct cfe_node *node) +{ + struct v4l2_event event = { + .type = V4L2_EVENT_FRAME_SYNC, + .u.frame_sync.frame_sequence = node->fs_count - 1, + }; + + v4l2_event_queue(&node->video_dev, &event); +} + +static void cfe_sof_isr(struct cfe_node *node) +{ + struct cfe_device *cfe = node->cfe; + bool matching_fs = true; + + trace_cfe_frame_start(node->id, node->fs_count); + + /* + * If the sensor is producing unexpected frame event ordering over a + * sustained period of time, guard against the possibility of coming + * here and orphaning the cur_frm if it's not been dequeued already. + * Unfortunately, there is not enough hardware state to tell if this + * may have occurred. + */ + if (WARN(node->cur_frm, "%s: [%s] Orphaned frame at seq %u\n", + __func__, node_desc[node->id].name, node->fs_count)) + cfe_process_buffer_complete(node, VB2_BUF_STATE_ERROR); + + node->cur_frm = node->next_frm; + node->next_frm = NULL; + node->fs_count++; + + node->ts = ktime_get_ns(); + for (unsigned int i = 0; i < NUM_NODES; i++) { + if (!check_state(cfe, NODE_STREAMING, i) || i == node->id) + continue; + /* + * This checks if any other node has seen a FS. If yes, use the + * same timestamp, eventually across all node buffers. + */ + if (cfe->node[i].fs_count >= node->fs_count) + node->ts = cfe->node[i].ts; + /* + * This checks if all other node have seen a matching FS. If + * yes, we can flag another job to be queued. + */ + if (matching_fs && cfe->node[i].fs_count != node->fs_count) + matching_fs = false; + } + + if (matching_fs) + cfe->job_queued = false; + + if (node->cur_frm) + node->cur_frm->vb.vb2_buf.timestamp = node->ts; + + set_state(cfe, FS_INT, node->id); + clear_state(cfe, FE_INT, node->id); + + if (is_image_output_node(node)) + cfe_queue_event_sof(node); +} + +static void cfe_eof_isr(struct cfe_node *node) +{ + struct cfe_device *cfe = node->cfe; + + trace_cfe_frame_end(node->id, node->fs_count - 1); + + if (node->cur_frm) + cfe_process_buffer_complete(node, VB2_BUF_STATE_DONE); + + node->cur_frm = NULL; + set_state(cfe, FE_INT, node->id); + clear_state(cfe, FS_INT, node->id); +} + +static irqreturn_t cfe_isr(int irq, void *dev) +{ + struct cfe_device *cfe = dev; + bool sof[NUM_NODES] = { 0 }, eof[NUM_NODES] = { 0 }; + u32 sts; + + sts = cfg_reg_read(cfe, MIPICFG_INTS); + + if (sts & MIPICFG_INT_CSI_DMA) + csi2_isr(&cfe->csi2, sof, eof); + + if (sts & MIPICFG_INT_PISP_FE) + pisp_fe_isr(&cfe->fe, sof + CSI2_NUM_CHANNELS, + eof + CSI2_NUM_CHANNELS); + + spin_lock(&cfe->state_lock); + + for (unsigned int i = 0; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + + /* + * The check_state(NODE_STREAMING) is to ensure we do not loop + * over the CSI2_CHx nodes when the FE is active since they + * generate interrupts even though the node is not streaming. + */ + if (!check_state(cfe, NODE_STREAMING, i) || !(sof[i] || eof[i])) + continue; + + /* + * There are 3 cases where we could get FS + FE_ACK at + * the same time: + * 1) FE of the current frame, and FS of the next frame. + * 2) FS + FE of the same frame. + * 3) FE of the current frame, and FS + FE of the next + * frame. To handle this, see the sof handler below. + * + * (1) is handled implicitly by the ordering of the FE and FS + * handlers below. + */ + if (eof[i]) { + /* + * The condition below tests for (2). Run the FS handler + * first before the FE handler, both for the current + * frame. + */ + if (sof[i] && !check_state(cfe, FS_INT, i)) { + cfe_sof_isr(node); + sof[i] = false; + } + + cfe_eof_isr(node); + } + + if (sof[i]) { + /* + * The condition below tests for (3). In such cases, we + * come in here with FS flag set in the node state from + * the previous frame since it only gets cleared in + * cfe_eof_isr(). Handle the FE for the previous + * frame first before the FS handler for the current + * frame. + */ + if (check_state(cfe, FS_INT, node->id) && + !check_state(cfe, FE_INT, node->id)) { + cfe_dbg(cfe, "%s: [%s] Handling missing previous FE interrupt\n", + __func__, node_desc[node->id].name); + cfe_eof_isr(node); + } + + cfe_sof_isr(node); + } + + if (!cfe->job_queued && cfe->job_ready) + cfe_prepare_next_job(cfe); + } + + spin_unlock(&cfe->state_lock); + + return IRQ_HANDLED; +} + +/* + * Stream helpers + */ + +static int cfe_get_vc_dt_fallback(struct cfe_device *cfe, u8 *vc, u8 *dt) +{ + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *fmt; + const struct cfe_fmt *cfe_fmt; + + state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); + + fmt = v4l2_subdev_state_get_format(state, CSI2_PAD_SINK, 0); + if (!fmt) + return -EINVAL; + + cfe_fmt = find_format_by_code(fmt->code); + if (!cfe_fmt) + return -EINVAL; + + *vc = 0; + *dt = cfe_fmt->csi_dt; + + return 0; +} + +static int cfe_get_vc_dt(struct cfe_device *cfe, unsigned int channel, u8 *vc, + u8 *dt) +{ + struct v4l2_mbus_frame_desc remote_desc; + struct v4l2_subdev_state *state; + u32 sink_stream; + unsigned int i; + int ret; + + state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); + + ret = v4l2_subdev_routing_find_opposite_end(&state->routing, + CSI2_PAD_FIRST_SOURCE + channel, 0, NULL, &sink_stream); + if (ret) + return ret; + + ret = v4l2_subdev_call(cfe->source_sd, pad, get_frame_desc, + cfe->source_pad, &remote_desc); + if (ret == -ENOIOCTLCMD) { + cfe_dbg(cfe, "source does not support get_frame_desc, use fallback\n"); + return cfe_get_vc_dt_fallback(cfe, vc, dt); + } else if (ret) { + cfe_err(cfe, "Failed to get frame descriptor\n"); + return ret; + } + + if (remote_desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { + cfe_err(cfe, "Frame descriptor does not describe CSI-2 link"); + return -EINVAL; + } + + for (i = 0; i < remote_desc.num_entries; i++) { + if (remote_desc.entry[i].stream == sink_stream) + break; + } + + if (i == remote_desc.num_entries) { + cfe_err(cfe, "Stream %u not found in remote frame desc\n", + sink_stream); + return -EINVAL; + } + + *vc = remote_desc.entry[i].bus.csi2.vc; + *dt = remote_desc.entry[i].bus.csi2.dt; + + return 0; +} + +static int cfe_start_channel(struct cfe_node *node) +{ + struct cfe_device *cfe = node->cfe; + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *source_fmt; + const struct cfe_fmt *fmt; + unsigned long flags; + bool start_fe; + int ret; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + start_fe = is_fe_enabled(cfe) && + test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); + + state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); + + if (start_fe) { + unsigned int width, height; + u8 vc, dt; + + cfe_dbg(cfe, "%s: %s using csi2 channel %d\n", __func__, + node_desc[FE_OUT0].name, cfe->fe_csi2_channel); + + ret = cfe_get_vc_dt(cfe, cfe->fe_csi2_channel, &vc, &dt); + if (ret) + return ret; + + source_fmt = v4l2_subdev_state_get_format(state, + node_desc[cfe->fe_csi2_channel].link_pad); + fmt = find_format_by_code(source_fmt->code); + + width = source_fmt->width; + height = source_fmt->height; + + /* Must have a valid CSI2 datatype. */ + WARN_ON(!fmt->csi_dt); + + /* + * Start the associated CSI2 Channel as well. + * + * Must write to the ADDR register to latch the ctrl values + * even if we are connected to the front end. Once running, + * this is handled by the CSI2 AUTO_ARM mode. + */ + csi2_start_channel(&cfe->csi2, cfe->fe_csi2_channel, + CSI2_MODE_FE_STREAMING, + true, false, width, height, vc, dt); + csi2_set_buffer(&cfe->csi2, cfe->fe_csi2_channel, 0, 0, -1); + pisp_fe_start(&cfe->fe); + } + + if (is_csi2_node(node)) { + unsigned int width = 0, height = 0; + u8 vc, dt; + + ret = cfe_get_vc_dt(cfe, node->id, &vc, &dt); + if (ret) { + if (start_fe) { + csi2_stop_channel(&cfe->csi2, + cfe->fe_csi2_channel); + pisp_fe_stop(&cfe->fe); + } + + return ret; + } + + u32 mode = CSI2_MODE_NORMAL; + + source_fmt = v4l2_subdev_state_get_format(state, + node_desc[node->id].link_pad); + fmt = find_format_by_code(source_fmt->code); + + /* Must have a valid CSI2 datatype. */ + WARN_ON(!fmt->csi_dt); + + if (is_image_output_node(node)) { + u32 pixfmt; + + width = source_fmt->width; + height = source_fmt->height; + + pixfmt = node->vid_fmt.fmt.pix.pixelformat; + + if (pixfmt == fmt->remap[CFE_REMAP_16BIT]) { + mode = CSI2_MODE_REMAP; + } else if (pixfmt == fmt->remap[CFE_REMAP_COMPRESSED]) { + mode = CSI2_MODE_COMPRESSED; + csi2_set_compression(&cfe->csi2, node->id, + CSI2_COMPRESSION_DELTA, 0, + 0); + } + } + /* Unconditionally start this CSI2 channel. */ + csi2_start_channel(&cfe->csi2, node->id, + mode, + /* Auto arm */ + false, + /* Pack bytes */ + is_meta_node(node) ? true : false, + width, height, vc, dt); + } + + spin_lock_irqsave(&cfe->state_lock, flags); + if (cfe->job_ready && test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) + cfe_prepare_next_job(cfe); + spin_unlock_irqrestore(&cfe->state_lock, flags); + + return 0; +} + +static void cfe_stop_channel(struct cfe_node *node, bool fe_stop) +{ + struct cfe_device *cfe = node->cfe; + + cfe_dbg(cfe, "%s: [%s] fe_stop %u\n", __func__, + node_desc[node->id].name, fe_stop); + + if (fe_stop) { + csi2_stop_channel(&cfe->csi2, cfe->fe_csi2_channel); + pisp_fe_stop(&cfe->fe); + } + + if (is_csi2_node(node)) + csi2_stop_channel(&cfe->csi2, node->id); +} + +static void cfe_return_buffers(struct cfe_node *node, + enum vb2_buffer_state state) +{ + struct cfe_device *cfe = node->cfe; + struct cfe_buffer *buf, *tmp; + unsigned long flags; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + spin_lock_irqsave(&cfe->state_lock, flags); + list_for_each_entry_safe(buf, tmp, &node->dma_queue, list) { + list_del(&buf->list); + trace_cfe_return_buffer(node->id, buf->vb.vb2_buf.index, 2); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + + if (node->cur_frm) { + trace_cfe_return_buffer(node->id, + node->cur_frm->vb.vb2_buf.index, 0); + vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state); + } + if (node->next_frm && node->cur_frm != node->next_frm) { + trace_cfe_return_buffer(node->id, + node->next_frm->vb.vb2_buf.index, 1); + vb2_buffer_done(&node->next_frm->vb.vb2_buf, state); + } + + node->cur_frm = NULL; + node->next_frm = NULL; + spin_unlock_irqrestore(&cfe->state_lock, flags); +} + +/* + * vb2 ops + */ + +static int cfe_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct cfe_node *node = vb2_get_drv_priv(vq); + struct cfe_device *cfe = node->cfe; + unsigned int size = is_image_node(node) ? + node->vid_fmt.fmt.pix.sizeimage : + node->meta_fmt.fmt.meta.buffersize; + + cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, + node->buffer_queue.type); + + if (vq->max_num_buffers + *nbuffers < 3) + *nbuffers = 3 - vq->max_num_buffers; + + if (*nplanes) { + if (sizes[0] < size) { + cfe_err(cfe, "sizes[0] %i < size %u\n", sizes[0], size); + return -EINVAL; + } + size = sizes[0]; + } + + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int cfe_buffer_prepare(struct vb2_buffer *vb) +{ + struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue); + struct cfe_device *cfe = node->cfe; + struct cfe_buffer *buf = to_cfe_buffer(vb); + unsigned long size; + + trace_cfe_buffer_prepare(node->id, vb); + + size = is_image_node(node) ? node->vid_fmt.fmt.pix.sizeimage : + node->meta_fmt.fmt.meta.buffersize; + if (vb2_plane_size(vb, 0) < size) { + cfe_err(cfe, "data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); + + if (node->id == FE_CONFIG) { + struct cfe_config_buffer *b = to_cfe_config_buffer(buf); + void *addr = vb2_plane_vaddr(vb, 0); + + memcpy(&b->config, addr, sizeof(struct pisp_fe_config)); + return pisp_fe_validate_config(&cfe->fe, &b->config, + &cfe->node[FE_OUT0].vid_fmt, + &cfe->node[FE_OUT1].vid_fmt); + } + + return 0; +} + +static void cfe_buffer_queue(struct vb2_buffer *vb) +{ + struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue); + struct cfe_device *cfe = node->cfe; + struct cfe_buffer *buf = to_cfe_buffer(vb); + unsigned long flags; + bool schedule_now; + + spin_lock_irqsave(&cfe->state_lock, flags); + + list_add_tail(&buf->list, &node->dma_queue); + + if (!cfe->job_ready) + cfe->job_ready = cfe_check_job_ready(cfe); + + schedule_now = !cfe->job_queued && cfe->job_ready && + test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); + + trace_cfe_buffer_queue(node->id, vb, schedule_now); + + if (schedule_now) + cfe_prepare_next_job(cfe); + + spin_unlock_irqrestore(&cfe->state_lock, flags); +} + +static s64 cfe_get_source_link_freq(struct cfe_device *cfe) +{ + struct v4l2_subdev_state *state; + s64 link_freq; + u32 bpp; + + state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); + + /* + * v4l2_get_link_freq() uses V4L2_CID_LINK_FREQ first, and falls back + * to V4L2_CID_PIXEL_RATE if V4L2_CID_LINK_FREQ is not available. + * + * With multistream input there is no single pixel rate, and thus we + * cannot use V4L2_CID_PIXEL_RATE, so we pass 0 as the bpp which + * causes v4l2_get_link_freq() to return an error if it falls back to + * V4L2_CID_PIXEL_RATE. + */ + + if (state->routing.num_routes == 1) { + struct v4l2_subdev_route *route = &state->routing.routes[0]; + struct v4l2_mbus_framefmt *source_fmt; + const struct cfe_fmt *fmt; + + source_fmt = v4l2_subdev_state_get_format(state, + route->sink_pad, + route->sink_stream); + + fmt = find_format_by_code(source_fmt->code); + if (!fmt) + return -EINVAL; + + bpp = fmt->depth; + } else { + bpp = 0; + } + + link_freq = v4l2_get_link_freq(cfe->source_sd->ctrl_handler, bpp, + 2 * cfe->csi2.dphy.active_lanes); + if (link_freq < 0) + cfe_err(cfe, "failed to get link freq for subdev '%s'\n", + cfe->source_sd->name); + + return link_freq; +} + +static int cfe_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct v4l2_mbus_config mbus_config = { 0 }; + struct cfe_node *node = vb2_get_drv_priv(vq); + struct cfe_device *cfe = node->cfe; + struct v4l2_subdev_state *state; + struct v4l2_subdev_route *route; + s64 link_freq; + int ret; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + if (!check_state(cfe, NODE_ENABLED, node->id)) { + cfe_err(cfe, "%s node link is not enabled.\n", + node_desc[node->id].name); + ret = -EINVAL; + goto err_streaming; + } + + ret = pm_runtime_resume_and_get(&cfe->pdev->dev); + if (ret < 0) { + cfe_err(cfe, "pm_runtime_resume_and_get failed\n"); + goto err_streaming; + } + + /* When using the Frontend, we must enable the FE_CONFIG node. */ + if (is_fe_enabled(cfe) && + !check_state(cfe, NODE_ENABLED, cfe->node[FE_CONFIG].id)) { + cfe_err(cfe, "FE enabled, but FE_CONFIG node is not\n"); + ret = -EINVAL; + goto err_pm_put; + } + + ret = media_pipeline_start(&node->pad, &cfe->pipe); + if (ret < 0) { + cfe_err(cfe, "Failed to start media pipeline: %d\n", ret); + goto err_pm_put; + } + + state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd); + + clear_state(cfe, FS_INT | FE_INT, node->id); + set_state(cfe, NODE_STREAMING, node->id); + node->fs_count = 0; + + ret = cfe_start_channel(node); + if (ret) + goto err_unlock_state; + + if (!test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) { + cfe_dbg(cfe, "Streaming on hold, as all nodes are not set to streaming yet\n"); + v4l2_subdev_unlock_state(state); + return 0; + } + + cfg_reg_write(cfe, MIPICFG_CFG, MIPICFG_CFG_SEL_CSI); + cfg_reg_write(cfe, MIPICFG_INTE, + MIPICFG_INT_CSI_DMA | MIPICFG_INT_PISP_FE); + + ret = v4l2_subdev_call(cfe->source_sd, pad, get_mbus_config, 0, + &mbus_config); + if (ret < 0 && ret != -ENOIOCTLCMD) { + cfe_err(cfe, "g_mbus_config failed\n"); + goto err_clear_inte; + } + + cfe->csi2.dphy.active_lanes = mbus_config.bus.mipi_csi2.num_data_lanes; + if (!cfe->csi2.dphy.active_lanes) + cfe->csi2.dphy.active_lanes = cfe->csi2.dphy.max_lanes; + if (cfe->csi2.dphy.active_lanes > cfe->csi2.dphy.max_lanes) { + cfe_err(cfe, "Device has requested %u data lanes, which is >%u configured in DT\n", + cfe->csi2.dphy.active_lanes, cfe->csi2.dphy.max_lanes); + ret = -EINVAL; + goto err_clear_inte; + } + + link_freq = cfe_get_source_link_freq(cfe); + if (link_freq < 0) + goto err_clear_inte; + + cfe->csi2.dphy.dphy_rate = div_s64(link_freq * 2, 1000000); + csi2_open_rx(&cfe->csi2); + + cfe->streams_mask = 0; + + for_each_active_route(&state->routing, route) + cfe->streams_mask |= BIT_ULL(route->sink_stream); + + ret = v4l2_subdev_enable_streams(cfe->source_sd, cfe->source_pad, + cfe->streams_mask); + if (ret) { + cfe_err(cfe, "stream on failed in subdev\n"); + goto err_disable_cfe; + } + + cfe_dbg(cfe, "Streaming enabled\n"); + + v4l2_subdev_unlock_state(state); + + return 0; + +err_disable_cfe: + csi2_close_rx(&cfe->csi2); +err_clear_inte: + cfg_reg_write(cfe, MIPICFG_INTE, 0); + + cfe_stop_channel(node, + is_fe_enabled(cfe) && test_all_nodes(cfe, NODE_ENABLED, + NODE_STREAMING)); +err_unlock_state: + v4l2_subdev_unlock_state(state); + media_pipeline_stop(&node->pad); +err_pm_put: + pm_runtime_put(&cfe->pdev->dev); +err_streaming: + cfe_return_buffers(node, VB2_BUF_STATE_QUEUED); + clear_state(cfe, NODE_STREAMING, node->id); + + return ret; +} + +static void cfe_stop_streaming(struct vb2_queue *vq) +{ + struct cfe_node *node = vb2_get_drv_priv(vq); + struct cfe_device *cfe = node->cfe; + unsigned long flags; + bool fe_stop; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + spin_lock_irqsave(&cfe->state_lock, flags); + fe_stop = is_fe_enabled(cfe) && + test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); + + cfe->job_ready = false; + clear_state(cfe, NODE_STREAMING, node->id); + spin_unlock_irqrestore(&cfe->state_lock, flags); + + cfe_stop_channel(node, fe_stop); + + if (!test_any_node(cfe, NODE_STREAMING)) { + struct v4l2_subdev_state *state; + int ret; + + state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd); + + ret = v4l2_subdev_disable_streams(cfe->source_sd, + cfe->source_pad, + cfe->streams_mask); + if (ret) + cfe_err(cfe, "stream disable failed in subdev\n"); + + v4l2_subdev_unlock_state(state); + + csi2_close_rx(&cfe->csi2); + + cfg_reg_write(cfe, MIPICFG_INTE, 0); + + cfe_dbg(cfe, "%s: Streaming disabled\n", __func__); + } + + media_pipeline_stop(&node->pad); + + /* Clear all queued buffers for the node */ + cfe_return_buffers(node, VB2_BUF_STATE_ERROR); + + pm_runtime_put(&cfe->pdev->dev); +} + +static const struct vb2_ops cfe_video_qops = { + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .queue_setup = cfe_queue_setup, + .buf_prepare = cfe_buffer_prepare, + .buf_queue = cfe_buffer_queue, + .start_streaming = cfe_start_streaming, + .stop_streaming = cfe_stop_streaming, +}; + +/* + * v4l2 ioctl ops + */ + +static int cfe_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, CFE_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, CFE_MODULE_NAME, sizeof(cap->card)); + + cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE | + V4L2_CAP_META_OUTPUT; + + return 0; +} + +static int cfe_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + unsigned int i, j; + + if (!node_supports_image_output(node)) + return -EINVAL; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) { + if (f->mbus_code && formats[i].code != f->mbus_code) + continue; + + if (formats[i].flags & CFE_FORMAT_FLAG_META_OUT || + formats[i].flags & CFE_FORMAT_FLAG_META_CAP) + continue; + + if (is_fe_node(node) && + !(formats[i].flags & CFE_FORMAT_FLAG_FE_OUT)) + continue; + + if (j == f->index) { + f->pixelformat = formats[i].fourcc; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return 0; + } + j++; + } + + return -EINVAL; +} + +static int cfe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + + if (!node_supports_image(node)) + return -EINVAL; + + *f = node->vid_fmt; + + return 0; +} + +static int cfe_validate_fmt_vid_cap(struct cfe_node *node, + struct v4l2_format *f) +{ + struct cfe_device *cfe = node->cfe; + const struct cfe_fmt *fmt; + + cfe_dbg(cfe, "%s: [%s] %ux%u, V4L2 pix %p4cc\n", __func__, + node_desc[node->id].name, f->fmt.pix.width, f->fmt.pix.height, + &f->fmt.pix.pixelformat); + + if (!node_supports_image_output(node)) + return -EINVAL; + + /* + * Default to a format that works for both CSI2 and FE. + */ + fmt = find_format_by_pix(f->fmt.pix.pixelformat); + if (!fmt) + fmt = find_format_by_code(MEDIA_BUS_FMT_SBGGR10_1X10); + + f->fmt.pix.pixelformat = fmt->fourcc; + + if (is_fe_node(node) && fmt->remap[CFE_REMAP_16BIT]) { + f->fmt.pix.pixelformat = fmt->remap[CFE_REMAP_16BIT]; + fmt = find_format_by_pix(f->fmt.pix.pixelformat); + } + + f->fmt.pix.field = V4L2_FIELD_NONE; + + cfe_calc_vid_format_size_bpl(cfe, fmt, f); + + return 0; +} + +static int cfe_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + struct vb2_queue *q = &node->buffer_queue; + int ret; + + if (vb2_is_busy(q)) + return -EBUSY; + + ret = cfe_validate_fmt_vid_cap(node, f); + if (ret) + return ret; + + node->vid_fmt = *f; + + cfe_dbg(cfe, "%s: Set %ux%u, V4L2 pix %p4cc\n", __func__, + node->vid_fmt.fmt.pix.width, node->vid_fmt.fmt.pix.height, + &node->vid_fmt.fmt.pix.pixelformat); + + return 0; +} + +static int cfe_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + return cfe_validate_fmt_vid_cap(node, f); +} + +static int cfe_enum_fmt_meta(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + if (!node_supports_meta(node)) + return -EINVAL; + + switch (node->id) { + case CSI2_CH0...CSI2_CH3: + f->flags = V4L2_FMT_FLAG_META_LINE_BASED; + + switch (f->index) { + case 0: + f->pixelformat = V4L2_META_FMT_GENERIC_8; + return 0; + case 1: + f->pixelformat = V4L2_META_FMT_GENERIC_CSI2_10; + return 0; + case 2: + f->pixelformat = V4L2_META_FMT_GENERIC_CSI2_12; + return 0; + default: + return -EINVAL; + } + default: + break; + } + + if (f->index != 0) + return -EINVAL; + + switch (node->id) { + case FE_STATS: + f->pixelformat = V4L2_META_FMT_RPI_FE_STATS; + return 0; + case FE_CONFIG: + f->pixelformat = V4L2_META_FMT_RPI_FE_CFG; + return 0; + default: + return -EINVAL; + } +} + +static int cfe_validate_fmt_meta(struct cfe_node *node, struct v4l2_format *f) +{ + struct cfe_device *cfe = node->cfe; + const struct cfe_fmt *fmt; + + switch (node->id) { + case CSI2_CH0...CSI2_CH3: + cfe_dbg(cfe, "%s: [%s] %ux%u, V4L2 meta %p4cc\n", __func__, + node_desc[node->id].name, f->fmt.meta.width, + f->fmt.meta.height, &f->fmt.meta.dataformat); + break; + case FE_STATS: + case FE_CONFIG: + cfe_dbg(cfe, "%s: [%s] %u bytes, V4L2 meta %p4cc\n", __func__, + node_desc[node->id].name, f->fmt.meta.buffersize, + &f->fmt.meta.dataformat); + break; + default: + return -EINVAL; + } + + if (!node_supports_meta(node)) + return -EINVAL; + + switch (node->id) { + case CSI2_CH0...CSI2_CH3: + fmt = find_format_by_pix(f->fmt.meta.dataformat); + if (!fmt || !(fmt->flags & CFE_FORMAT_FLAG_META_CAP)) + fmt = find_format_by_pix(V4L2_META_FMT_GENERIC_CSI2_10); + + f->fmt.meta.dataformat = fmt->fourcc; + + cfe_calc_meta_format_size_bpl(cfe, fmt, f); + + return 0; + case FE_STATS: + f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_STATS; + f->fmt.meta.buffersize = sizeof(struct pisp_statistics); + return 0; + case FE_CONFIG: + f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_CFG; + f->fmt.meta.buffersize = sizeof(struct pisp_fe_config); + return 0; + default: + return -EINVAL; + } +} + +static int cfe_g_fmt_meta(struct file *file, void *priv, struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + if (!node_supports_meta(node)) + return -EINVAL; + + *f = node->meta_fmt; + + return 0; +} + +static int cfe_s_fmt_meta(struct file *file, void *priv, struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + struct vb2_queue *q = &node->buffer_queue; + int ret; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + if (vb2_is_busy(q)) + return -EBUSY; + + if (!node_supports_meta(node)) + return -EINVAL; + + ret = cfe_validate_fmt_meta(node, f); + if (ret) + return ret; + + node->meta_fmt = *f; + + cfe_dbg(cfe, "%s: Set %p4cc\n", __func__, + &node->meta_fmt.fmt.meta.dataformat); + + return 0; +} + +static int cfe_try_fmt_meta(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + return cfe_validate_fmt_meta(node, f); +} + +static int cfe_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + const struct cfe_fmt *fmt; + + cfe_dbg(cfe, "%s [%s]\n", __func__, node_desc[node->id].name); + + if (fsize->index > 0) + return -EINVAL; + + /* check for valid format */ + fmt = find_format_by_pix(fsize->pixel_format); + if (!fmt) { + cfe_dbg(cfe, "Invalid pixel code: %x\n", fsize->pixel_format); + return -EINVAL; + } + + /* TODO: Do we have limits on the step_width? */ + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = MIN_WIDTH; + fsize->stepwise.max_width = MAX_WIDTH; + fsize->stepwise.step_width = 2; + fsize->stepwise.min_height = MIN_HEIGHT; + fsize->stepwise.max_height = MAX_HEIGHT; + fsize->stepwise.step_height = 1; + + return 0; +} + +static int cfe_vb2_ioctl_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct video_device *vdev = video_devdata(file); + struct cfe_node *node = video_get_drvdata(vdev); + struct cfe_device *cfe = node->cfe; + int ret; + + cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, + p->type); + + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + p->type != V4L2_BUF_TYPE_META_CAPTURE && + p->type != V4L2_BUF_TYPE_META_OUTPUT) + return -EINVAL; + + ret = vb2_queue_change_type(vdev->queue, p->type); + if (ret) + return ret; + + return vb2_ioctl_reqbufs(file, priv, p); +} + +static int cfe_vb2_ioctl_create_bufs(struct file *file, void *priv, + struct v4l2_create_buffers *p) +{ + struct video_device *vdev = video_devdata(file); + struct cfe_node *node = video_get_drvdata(vdev); + struct cfe_device *cfe = node->cfe; + int ret; + + cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, + p->format.type); + + if (p->format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + p->format.type != V4L2_BUF_TYPE_META_CAPTURE && + p->format.type != V4L2_BUF_TYPE_META_OUTPUT) + return -EINVAL; + + ret = vb2_queue_change_type(vdev->queue, p->format.type); + if (ret) + return ret; + + return vb2_ioctl_create_bufs(file, priv, p); +} + +static int cfe_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + struct cfe_node *node = video_get_drvdata(fh->vdev); + + switch (sub->type) { + case V4L2_EVENT_FRAME_SYNC: + if (!node_supports_image_output(node)) + break; + + return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + if (!node_supports_image_output(node) && + !node_supports_meta_output(node)) + break; + + return v4l2_event_subscribe(fh, sub, 4, NULL); + } + + return v4l2_ctrl_subscribe_event(fh, sub); +} + +static const struct v4l2_ioctl_ops cfe_ioctl_ops = { + .vidioc_querycap = cfe_querycap, + .vidioc_enum_fmt_vid_cap = cfe_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cfe_g_fmt, + .vidioc_s_fmt_vid_cap = cfe_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cfe_try_fmt_vid_cap, + + .vidioc_enum_fmt_meta_cap = cfe_enum_fmt_meta, + .vidioc_g_fmt_meta_cap = cfe_g_fmt_meta, + .vidioc_s_fmt_meta_cap = cfe_s_fmt_meta, + .vidioc_try_fmt_meta_cap = cfe_try_fmt_meta, + + .vidioc_enum_fmt_meta_out = cfe_enum_fmt_meta, + .vidioc_g_fmt_meta_out = cfe_g_fmt_meta, + .vidioc_s_fmt_meta_out = cfe_s_fmt_meta, + .vidioc_try_fmt_meta_out = cfe_try_fmt_meta, + + .vidioc_enum_framesizes = cfe_enum_framesizes, + + .vidioc_reqbufs = cfe_vb2_ioctl_reqbufs, + .vidioc_create_bufs = cfe_vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .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 = cfe_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static void cfe_notify(struct v4l2_subdev *sd, unsigned int notification, + void *arg) +{ + struct cfe_device *cfe = to_cfe_device(sd->v4l2_dev); + + switch (notification) { + case V4L2_DEVICE_NOTIFY_EVENT: + for (unsigned int i = 0; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + + if (check_state(cfe, NODE_REGISTERED, i)) + continue; + + v4l2_event_queue(&node->video_dev, arg); + } + break; + default: + break; + } +} + +/* cfe capture driver file operations */ +static const struct v4l2_file_operations cfe_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +static int cfe_video_link_validate(struct media_link *link) +{ + struct video_device *vd = container_of(link->sink->entity, + struct video_device, entity); + struct cfe_node *node = container_of(vd, struct cfe_node, video_dev); + struct cfe_device *cfe = node->cfe; + struct v4l2_mbus_framefmt *source_fmt; + struct v4l2_subdev_state *state; + struct v4l2_subdev *source_sd; + int ret = 0; + + cfe_dbg(cfe, "%s: [%s] link \"%s\":%u -> \"%s\":%u\n", __func__, + node_desc[node->id].name, + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index); + + if (!media_entity_remote_source_pad_unique(link->sink->entity)) { + cfe_err(cfe, "video node %s pad not connected\n", vd->name); + return -ENOTCONN; + } + + source_sd = media_entity_to_v4l2_subdev(link->source->entity); + + state = v4l2_subdev_lock_and_get_active_state(source_sd); + + source_fmt = v4l2_subdev_state_get_format(state, link->source->index); + if (!source_fmt) { + ret = -EINVAL; + goto out; + } + + if (is_image_output_node(node)) { + struct v4l2_pix_format *pix_fmt = &node->vid_fmt.fmt.pix; + const struct cfe_fmt *fmt; + + if (source_fmt->width != pix_fmt->width || + source_fmt->height != pix_fmt->height) { + cfe_err(cfe, "Wrong width or height %ux%u (remote pad set to %ux%u)\n", + pix_fmt->width, pix_fmt->height, + source_fmt->width, source_fmt->height); + ret = -EINVAL; + goto out; + } + + fmt = find_format_by_code_and_fourcc(source_fmt->code, + pix_fmt->pixelformat); + if (!fmt) { + cfe_err(cfe, "Format mismatch!\n"); + ret = -EINVAL; + goto out; + } + } else if (is_csi2_node(node) && is_meta_output_node(node)) { + struct v4l2_meta_format *meta_fmt = &node->meta_fmt.fmt.meta; + const struct cfe_fmt *fmt; + + if (source_fmt->width != meta_fmt->width || + source_fmt->height != meta_fmt->height) { + cfe_err(cfe, "Wrong width or height %ux%u (remote pad set to %ux%u)\n", + meta_fmt->width, meta_fmt->height, + source_fmt->width, source_fmt->height); + ret = -EINVAL; + goto out; + } + + fmt = find_format_by_code_and_fourcc(source_fmt->code, + meta_fmt->dataformat); + if (!fmt) { + cfe_err(cfe, "Format mismatch!\n"); + ret = -EINVAL; + goto out; + } + } + +out: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static const struct media_entity_operations cfe_media_entity_ops = { + .link_validate = cfe_video_link_validate, +}; + +static int cfe_video_link_notify(struct media_link *link, u32 flags, + unsigned int notification) +{ + struct media_device *mdev = link->graph_obj.mdev; + struct cfe_device *cfe = container_of(mdev, struct cfe_device, mdev); + struct media_entity *fe = &cfe->fe.sd.entity; + struct media_entity *csi2 = &cfe->csi2.sd.entity; + unsigned long lock_flags; + + if (notification != MEDIA_DEV_NOTIFY_POST_LINK_CH) + return 0; + + cfe_dbg(cfe, "%s: %s[%u] -> %s[%u] 0x%x", __func__, + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index, flags); + + spin_lock_irqsave(&cfe->state_lock, lock_flags); + + for (unsigned int i = 0; i < NUM_NODES; i++) { + if (link->sink->entity != &cfe->node[i].video_dev.entity && + link->source->entity != &cfe->node[i].video_dev.entity) + continue; + + if (link->flags & MEDIA_LNK_FL_ENABLED) + set_state(cfe, NODE_ENABLED, i); + else + clear_state(cfe, NODE_ENABLED, i); + + break; + } + + spin_unlock_irqrestore(&cfe->state_lock, lock_flags); + + if (link->source->entity != csi2) + return 0; + if (link->sink->entity != fe) + return 0; + if (link->sink->index != 0) + return 0; + + cfe->fe_csi2_channel = -1; + if (link->flags & MEDIA_LNK_FL_ENABLED) { + if (link->source->index == node_desc[CSI2_CH0].link_pad) + cfe->fe_csi2_channel = CSI2_CH0; + else if (link->source->index == node_desc[CSI2_CH1].link_pad) + cfe->fe_csi2_channel = CSI2_CH1; + else if (link->source->index == node_desc[CSI2_CH2].link_pad) + cfe->fe_csi2_channel = CSI2_CH2; + else if (link->source->index == node_desc[CSI2_CH3].link_pad) + cfe->fe_csi2_channel = CSI2_CH3; + } + + if (is_fe_enabled(cfe)) + cfe_dbg(cfe, "%s: Found CSI2:%d -> FE:0 link\n", __func__, + cfe->fe_csi2_channel); + else + cfe_dbg(cfe, "%s: Unable to find CSI2:x -> FE:0 link\n", + __func__); + + return 0; +} + +static const struct media_device_ops cfe_media_device_ops = { + .link_notify = cfe_video_link_notify, +}; + +static void cfe_release(struct kref *kref) +{ + struct cfe_device *cfe = container_of(kref, struct cfe_device, kref); + + media_device_cleanup(&cfe->mdev); + + kfree(cfe); +} + +static void cfe_put(struct cfe_device *cfe) +{ + kref_put(&cfe->kref, cfe_release); +} + +static void cfe_get(struct cfe_device *cfe) +{ + kref_get(&cfe->kref); +} + +static void cfe_node_release(struct video_device *vdev) +{ + struct cfe_node *node = video_get_drvdata(vdev); + + cfe_put(node->cfe); +} + +static int cfe_register_node(struct cfe_device *cfe, int id) +{ + struct video_device *vdev; + const struct cfe_fmt *fmt; + struct vb2_queue *q; + struct cfe_node *node = &cfe->node[id]; + int ret; + + node->cfe = cfe; + node->id = id; + + if (node_supports_image(node)) { + if (node_supports_image_output(node)) + node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + else + node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + fmt = find_format_by_code(cfe_default_format.code); + if (!fmt) { + cfe_err(cfe, "Failed to find format code\n"); + return -EINVAL; + } + + node->vid_fmt.fmt.pix.pixelformat = fmt->fourcc; + v4l2_fill_pix_format(&node->vid_fmt.fmt.pix, + &cfe_default_format); + + ret = cfe_validate_fmt_vid_cap(node, &node->vid_fmt); + if (ret) + return ret; + } + + if (node_supports_meta(node)) { + if (node_supports_meta_output(node)) + node->meta_fmt.type = V4L2_BUF_TYPE_META_CAPTURE; + else + node->meta_fmt.type = V4L2_BUF_TYPE_META_OUTPUT; + + ret = cfe_validate_fmt_meta(node, &node->meta_fmt); + if (ret) + return ret; + } + + mutex_init(&node->lock); + + q = &node->buffer_queue; + q->type = node_supports_image(node) ? node->vid_fmt.type : + node->meta_fmt.type; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = node; + q->ops = &cfe_video_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = id == FE_CONFIG ? sizeof(struct cfe_config_buffer) + : sizeof(struct cfe_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &node->lock; + q->min_queued_buffers = 1; + q->dev = &cfe->pdev->dev; + + ret = vb2_queue_init(q); + if (ret) { + cfe_err(cfe, "vb2_queue_init() failed\n"); + return ret; + } + + INIT_LIST_HEAD(&node->dma_queue); + + vdev = &node->video_dev; + vdev->release = cfe_node_release; + vdev->fops = &cfe_fops; + vdev->ioctl_ops = &cfe_ioctl_ops; + vdev->entity.ops = &cfe_media_entity_ops; + vdev->v4l2_dev = &cfe->v4l2_dev; + vdev->vfl_dir = (node_supports_image_output(node) || + node_supports_meta_output(node)) ? + VFL_DIR_RX : + VFL_DIR_TX; + vdev->queue = q; + vdev->lock = &node->lock; + vdev->device_caps = node_desc[id].caps; + vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; + + /* Define the device names */ + snprintf(vdev->name, sizeof(vdev->name), "%s-%s", CFE_MODULE_NAME, + node_desc[id].name); + + video_set_drvdata(vdev, node); + node->pad.flags = node_desc[id].pad_flags; + media_entity_pads_init(&vdev->entity, 1, &node->pad); + + if (!node_supports_image(node)) { + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_ENUM_FRAMEINTERVALS); + v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_FRAMESIZES); + } + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + cfe_err(cfe, "Unable to register video device %s\n", + vdev->name); + return ret; + } + + cfe_info(cfe, "Registered [%s] node id %d as /dev/video%u\n", + vdev->name, id, vdev->num); + + /* + * Acquire a reference to cfe, which will be released when the video + * device will be unregistered and userspace will have closed all open + * file handles. + */ + cfe_get(cfe); + set_state(cfe, NODE_REGISTERED, id); + + return 0; +} + +static void cfe_unregister_nodes(struct cfe_device *cfe) +{ + for (unsigned int i = 0; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + + if (check_state(cfe, NODE_REGISTERED, i)) { + clear_state(cfe, NODE_REGISTERED, i); + video_unregister_device(&node->video_dev); + } + } +} + +static int cfe_link_node_pads(struct cfe_device *cfe) +{ + struct media_pad *remote_pad; + int ret; + + /* Source -> CSI2 */ + + ret = v4l2_create_fwnode_links_to_pad(cfe->source_sd, + &cfe->csi2.pad[CSI2_PAD_SINK], + MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); + + if (ret) { + cfe_err(cfe, "Failed to create links to the source: %d\n", ret); + return ret; + } + + remote_pad = media_pad_remote_pad_unique(&cfe->csi2.pad[CSI2_PAD_SINK]); + if (IS_ERR(remote_pad)) { + ret = PTR_ERR(remote_pad); + cfe_err(cfe, "Failed to get unique remote source pad: %d\n", + ret); + return ret; + } + + cfe->source_pad = remote_pad->index; + + for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; i++) { + struct cfe_node *node = &cfe->node[i]; + + if (!check_state(cfe, NODE_REGISTERED, i)) + continue; + + /* CSI2 channel # -> /dev/video# */ + ret = media_create_pad_link(&cfe->csi2.sd.entity, + node_desc[i].link_pad, + &node->video_dev.entity, 0, 0); + if (ret) + return ret; + + if (node_supports_image(node)) { + /* CSI2 channel # -> FE Input */ + ret = media_create_pad_link(&cfe->csi2.sd.entity, + node_desc[i].link_pad, + &cfe->fe.sd.entity, + FE_STREAM_PAD, 0); + if (ret) + return ret; + } + } + + for (unsigned int i = CSI2_NUM_CHANNELS; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + struct media_entity *src, *dst; + unsigned int src_pad, dst_pad; + + if (node_desc[i].pad_flags & MEDIA_PAD_FL_SINK) { + /* FE -> /dev/video# */ + src = &cfe->fe.sd.entity; + src_pad = node_desc[i].link_pad; + dst = &node->video_dev.entity; + dst_pad = 0; + } else { + /* /dev/video# -> FE */ + dst = &cfe->fe.sd.entity; + dst_pad = node_desc[i].link_pad; + src = &node->video_dev.entity; + src_pad = 0; + } + + ret = media_create_pad_link(src, src_pad, dst, dst_pad, 0); + if (ret) + return ret; + } + + return 0; +} + +static int cfe_probe_complete(struct cfe_device *cfe) +{ + int ret; + + cfe->v4l2_dev.notify = cfe_notify; + + for (unsigned int i = 0; i < NUM_NODES; i++) { + ret = cfe_register_node(cfe, i); + if (ret) { + cfe_err(cfe, "Unable to register video node %u.\n", i); + goto unregister; + } + } + + ret = cfe_link_node_pads(cfe); + if (ret) { + cfe_err(cfe, "Unable to link node pads.\n"); + goto unregister; + } + + ret = v4l2_device_register_subdev_nodes(&cfe->v4l2_dev); + if (ret) { + cfe_err(cfe, "Unable to register subdev nodes.\n"); + goto unregister; + } + + return 0; + +unregister: + cfe_unregister_nodes(cfe); + return ret; +} + +static int cfe_async_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asd) +{ + struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); + + if (cfe->source_sd) { + cfe_err(cfe, "Rejecting subdev %s (Already set!!)", + subdev->name); + return 0; + } + + cfe->source_sd = subdev; + + cfe_dbg(cfe, "Using source %s for capture\n", subdev->name); + + return 0; +} + +static int cfe_async_complete(struct v4l2_async_notifier *notifier) +{ + struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); + + return cfe_probe_complete(cfe); +} + +static const struct v4l2_async_notifier_operations cfe_async_ops = { + .bound = cfe_async_bound, + .complete = cfe_async_complete, +}; + +static int cfe_register_async_nf(struct cfe_device *cfe) +{ + struct platform_device *pdev = cfe->pdev; + struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct fwnode_handle *local_ep_fwnode; + struct v4l2_async_connection *asd; + int ret; + + local_ep_fwnode = fwnode_graph_get_endpoint_by_id(pdev->dev.fwnode, 0, + 0, 0); + if (!local_ep_fwnode) { + cfe_err(cfe, "Failed to find local endpoint fwnode\n"); + return -ENODEV; + } + + /* Parse the local endpoint and validate its configuration. */ + ret = v4l2_fwnode_endpoint_parse(local_ep_fwnode, &ep); + if (ret) { + cfe_err(cfe, "Failed to find remote endpoint fwnode\n"); + goto err_put_local_fwnode; + } + + for (unsigned int lane = 0; lane < ep.bus.mipi_csi2.num_data_lanes; + lane++) { + if (ep.bus.mipi_csi2.data_lanes[lane] != lane + 1) { + cfe_err(cfe, "Data lanes reordering not supported\n"); + ret = -EINVAL; + goto err_put_local_fwnode; + } + } + + cfe->csi2.dphy.max_lanes = ep.bus.mipi_csi2.num_data_lanes; + cfe->csi2.bus_flags = ep.bus.mipi_csi2.flags; + + /* Initialize and register the async notifier. */ + v4l2_async_nf_init(&cfe->notifier, &cfe->v4l2_dev); + cfe->notifier.ops = &cfe_async_ops; + + asd = v4l2_async_nf_add_fwnode_remote(&cfe->notifier, local_ep_fwnode, + struct v4l2_async_connection); + if (IS_ERR(asd)) { + ret = PTR_ERR(asd); + cfe_err(cfe, "Error adding subdevice: %d\n", ret); + goto err_put_local_fwnode; + } + + ret = v4l2_async_nf_register(&cfe->notifier); + if (ret) { + cfe_err(cfe, "Error registering async notifier: %d\n", ret); + goto err_nf_cleanup; + } + + fwnode_handle_put(local_ep_fwnode); + + return 0; + +err_nf_cleanup: + v4l2_async_nf_cleanup(&cfe->notifier); +err_put_local_fwnode: + fwnode_handle_put(local_ep_fwnode); + + return ret; +} + +static int cfe_probe(struct platform_device *pdev) +{ + struct cfe_device *cfe; + char debugfs_name[32]; + int ret; + + cfe = kzalloc(sizeof(*cfe), GFP_KERNEL); + if (!cfe) + return -ENOMEM; + + platform_set_drvdata(pdev, cfe); + + kref_init(&cfe->kref); + cfe->pdev = pdev; + cfe->fe_csi2_channel = -1; + spin_lock_init(&cfe->state_lock); + + cfe->csi2.base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(cfe->csi2.base)) { + dev_err(&pdev->dev, "Failed to get dma io block\n"); + ret = PTR_ERR(cfe->csi2.base); + goto err_cfe_put; + } + + cfe->csi2.dphy.base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(cfe->csi2.dphy.base)) { + dev_err(&pdev->dev, "Failed to get host io block\n"); + ret = PTR_ERR(cfe->csi2.dphy.base); + goto err_cfe_put; + } + + cfe->mipi_cfg_base = devm_platform_ioremap_resource(pdev, 2); + if (IS_ERR(cfe->mipi_cfg_base)) { + dev_err(&pdev->dev, "Failed to get mipi cfg io block\n"); + ret = PTR_ERR(cfe->mipi_cfg_base); + goto err_cfe_put; + } + + cfe->fe.base = devm_platform_ioremap_resource(pdev, 3); + if (IS_ERR(cfe->fe.base)) { + dev_err(&pdev->dev, "Failed to get pisp fe io block\n"); + ret = PTR_ERR(cfe->fe.base); + goto err_cfe_put; + } + + ret = platform_get_irq(pdev, 0); + if (ret <= 0) { + ret = -EINVAL; + goto err_cfe_put; + } + + ret = devm_request_irq(&pdev->dev, ret, cfe_isr, 0, "rp1-cfe", cfe); + if (ret) { + dev_err(&pdev->dev, "Unable to request interrupt\n"); + ret = -EINVAL; + goto err_cfe_put; + } + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + dev_err(&pdev->dev, "DMA enable failed\n"); + goto err_cfe_put; + } + + ret = vb2_dma_contig_set_max_seg_size(&pdev->dev, UINT_MAX); + if (ret) + goto err_cfe_put; + + /* TODO: Enable clock only when running. */ + cfe->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(cfe->clk)) { + ret = dev_err_probe(&pdev->dev, PTR_ERR(cfe->clk), + "clock not found\n"); + goto err_cfe_put; + } + + cfe->mdev.dev = &pdev->dev; + cfe->mdev.ops = &cfe_media_device_ops; + strscpy(cfe->mdev.model, CFE_MODULE_NAME, sizeof(cfe->mdev.model)); + strscpy(cfe->mdev.serial, "", sizeof(cfe->mdev.serial)); + snprintf(cfe->mdev.bus_info, sizeof(cfe->mdev.bus_info), "platform:%s", + dev_name(&pdev->dev)); + + media_device_init(&cfe->mdev); + + cfe->v4l2_dev.mdev = &cfe->mdev; + + ret = v4l2_device_register(&pdev->dev, &cfe->v4l2_dev); + if (ret) { + cfe_err(cfe, "Unable to register v4l2 device.\n"); + goto err_cfe_put; + } + + snprintf(debugfs_name, sizeof(debugfs_name), "rp1-cfe:%s", + dev_name(&pdev->dev)); + cfe->debugfs = debugfs_create_dir(debugfs_name, NULL); + debugfs_create_file("regs", 0440, cfe->debugfs, cfe, + &mipi_cfg_regs_fops); + + /* Enable the block power domain */ + pm_runtime_enable(&pdev->dev); + + ret = pm_runtime_resume_and_get(&cfe->pdev->dev); + if (ret) + goto err_runtime_disable; + + cfe->csi2.v4l2_dev = &cfe->v4l2_dev; + ret = csi2_init(&cfe->csi2, cfe->debugfs); + if (ret) { + cfe_err(cfe, "Failed to init csi2 (%d)\n", ret); + goto err_runtime_put; + } + + cfe->fe.v4l2_dev = &cfe->v4l2_dev; + ret = pisp_fe_init(&cfe->fe, cfe->debugfs); + if (ret) { + cfe_err(cfe, "Failed to init pisp fe (%d)\n", ret); + goto err_csi2_uninit; + } + + cfe->mdev.hw_revision = cfe->fe.hw_revision; + ret = media_device_register(&cfe->mdev); + if (ret < 0) { + cfe_err(cfe, "Unable to register media-controller device.\n"); + goto err_pisp_fe_uninit; + } + + ret = cfe_register_async_nf(cfe); + if (ret) { + cfe_err(cfe, "Failed to connect subdevs\n"); + goto err_media_unregister; + } + + pm_runtime_put(&cfe->pdev->dev); + + return 0; + +err_media_unregister: + media_device_unregister(&cfe->mdev); +err_pisp_fe_uninit: + pisp_fe_uninit(&cfe->fe); +err_csi2_uninit: + csi2_uninit(&cfe->csi2); +err_runtime_put: + pm_runtime_put(&cfe->pdev->dev); +err_runtime_disable: + pm_runtime_disable(&pdev->dev); + debugfs_remove(cfe->debugfs); + v4l2_device_unregister(&cfe->v4l2_dev); +err_cfe_put: + cfe_put(cfe); + + return ret; +} + +static void cfe_remove(struct platform_device *pdev) +{ + struct cfe_device *cfe = platform_get_drvdata(pdev); + + debugfs_remove(cfe->debugfs); + + v4l2_async_nf_unregister(&cfe->notifier); + v4l2_async_nf_cleanup(&cfe->notifier); + + media_device_unregister(&cfe->mdev); + cfe_unregister_nodes(cfe); + + pisp_fe_uninit(&cfe->fe); + csi2_uninit(&cfe->csi2); + + pm_runtime_disable(&pdev->dev); + + v4l2_device_unregister(&cfe->v4l2_dev); + + cfe_put(cfe); +} + +static int cfe_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cfe_device *cfe = platform_get_drvdata(pdev); + + clk_disable_unprepare(cfe->clk); + + return 0; +} + +static int cfe_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cfe_device *cfe = platform_get_drvdata(pdev); + int ret; + + ret = clk_prepare_enable(cfe->clk); + if (ret) { + dev_err(dev, "Unable to enable clock\n"); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops cfe_pm_ops = { + SET_RUNTIME_PM_OPS(cfe_runtime_suspend, cfe_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static const struct of_device_id cfe_of_match[] = { + { .compatible = "raspberrypi,rp1-cfe" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, cfe_of_match); + +static struct platform_driver cfe_driver = { + .probe = cfe_probe, + .remove = cfe_remove, + .driver = { + .name = CFE_MODULE_NAME, + .of_match_table = cfe_of_match, + .pm = &cfe_pm_ops, + }, +}; + +module_platform_driver(cfe_driver); + +MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>"); +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>"); +MODULE_DESCRIPTION("Raspberry Pi RP1 Camera Front End driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(CFE_VERSION); diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe.h b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.h new file mode 100644 index 000000000000..c63cc314be3c --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * RP1 CFE Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ +#ifndef _RP1_CFE_ +#define _RP1_CFE_ + +#include <linux/media-bus-format.h> +#include <linux/types.h> +#include <linux/videodev2.h> + +extern bool cfe_debug_verbose; + +enum cfe_remap_types { + CFE_REMAP_16BIT, + CFE_REMAP_COMPRESSED, + CFE_NUM_REMAP, +}; + +#define CFE_FORMAT_FLAG_META_OUT BIT(0) +#define CFE_FORMAT_FLAG_META_CAP BIT(1) +#define CFE_FORMAT_FLAG_FE_OUT BIT(2) + +struct cfe_fmt { + u32 fourcc; + u32 code; + u8 depth; + u8 csi_dt; + u32 remap[CFE_NUM_REMAP]; + u32 flags; +}; + +extern const struct v4l2_mbus_framefmt cfe_default_format; + +const struct cfe_fmt *find_format_by_code(u32 code); +const struct cfe_fmt *find_format_by_pix(u32 pixelformat); +u32 cfe_find_16bit_code(u32 code); +u32 cfe_find_compressed_code(u32 code); + +#endif diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c new file mode 100644 index 000000000000..35c2ab1e2cd4 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c @@ -0,0 +1,586 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RP1 CSI-2 Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ + +#include <linux/delay.h> +#include <linux/moduleparam.h> +#include <linux/pm_runtime.h> +#include <linux/seq_file.h> + +#include <media/videobuf2-dma-contig.h> + +#include "cfe.h" +#include "csi2.h" + +#include "cfe-trace.h" + +static bool csi2_track_errors; +module_param_named(track_csi2_errors, csi2_track_errors, bool, 0); +MODULE_PARM_DESC(track_csi2_errors, "track csi-2 errors"); + +#define csi2_dbg(csi2, fmt, arg...) dev_dbg((csi2)->v4l2_dev->dev, fmt, ##arg) +#define csi2_err(csi2, fmt, arg...) dev_err((csi2)->v4l2_dev->dev, fmt, ##arg) + +/* CSI2-DMA registers */ +#define CSI2_STATUS 0x000 +#define CSI2_QOS 0x004 +#define CSI2_DISCARDS_OVERFLOW 0x008 +#define CSI2_DISCARDS_INACTIVE 0x00c +#define CSI2_DISCARDS_UNMATCHED 0x010 +#define CSI2_DISCARDS_LEN_LIMIT 0x014 + +#define CSI2_DISCARDS_AMOUNT_SHIFT 0 +#define CSI2_DISCARDS_AMOUNT_MASK GENMASK(23, 0) +#define CSI2_DISCARDS_DT_SHIFT 24 +#define CSI2_DISCARDS_DT_MASK GENMASK(29, 24) +#define CSI2_DISCARDS_VC_SHIFT 30 +#define CSI2_DISCARDS_VC_MASK GENMASK(31, 30) + +#define CSI2_LLEV_PANICS 0x018 +#define CSI2_ULEV_PANICS 0x01c +#define CSI2_IRQ_MASK 0x020 +#define CSI2_IRQ_MASK_IRQ_OVERFLOW BIT(0) +#define CSI2_IRQ_MASK_IRQ_DISCARD_OVERFLOW BIT(1) +#define CSI2_IRQ_MASK_IRQ_DISCARD_LENGTH_LIMIT BIT(2) +#define CSI2_IRQ_MASK_IRQ_DISCARD_UNMATCHED BIT(3) +#define CSI2_IRQ_MASK_IRQ_DISCARD_INACTIVE BIT(4) +#define CSI2_IRQ_MASK_IRQ_ALL \ + (CSI2_IRQ_MASK_IRQ_OVERFLOW | CSI2_IRQ_MASK_IRQ_DISCARD_OVERFLOW | \ + CSI2_IRQ_MASK_IRQ_DISCARD_LENGTH_LIMIT | \ + CSI2_IRQ_MASK_IRQ_DISCARD_UNMATCHED | \ + CSI2_IRQ_MASK_IRQ_DISCARD_INACTIVE) + +#define CSI2_CTRL 0x024 +#define CSI2_CH_CTRL(x) ((x) * 0x40 + 0x28) +#define CSI2_CH_ADDR0(x) ((x) * 0x40 + 0x2c) +#define CSI2_CH_ADDR1(x) ((x) * 0x40 + 0x3c) +#define CSI2_CH_STRIDE(x) ((x) * 0x40 + 0x30) +#define CSI2_CH_LENGTH(x) ((x) * 0x40 + 0x34) +#define CSI2_CH_DEBUG(x) ((x) * 0x40 + 0x38) +#define CSI2_CH_FRAME_SIZE(x) ((x) * 0x40 + 0x40) +#define CSI2_CH_COMP_CTRL(x) ((x) * 0x40 + 0x44) +#define CSI2_CH_FE_FRAME_ID(x) ((x) * 0x40 + 0x48) + +/* CSI2_STATUS */ +#define CSI2_STATUS_IRQ_FS(x) (BIT(0) << (x)) +#define CSI2_STATUS_IRQ_FE(x) (BIT(4) << (x)) +#define CSI2_STATUS_IRQ_FE_ACK(x) (BIT(8) << (x)) +#define CSI2_STATUS_IRQ_LE(x) (BIT(12) << (x)) +#define CSI2_STATUS_IRQ_LE_ACK(x) (BIT(16) << (x)) +#define CSI2_STATUS_IRQ_CH_MASK(x) \ + (CSI2_STATUS_IRQ_FS(x) | CSI2_STATUS_IRQ_FE(x) | \ + CSI2_STATUS_IRQ_FE_ACK(x) | CSI2_STATUS_IRQ_LE(x) | \ + CSI2_STATUS_IRQ_LE_ACK(x)) +#define CSI2_STATUS_IRQ_OVERFLOW BIT(20) +#define CSI2_STATUS_IRQ_DISCARD_OVERFLOW BIT(21) +#define CSI2_STATUS_IRQ_DISCARD_LEN_LIMIT BIT(22) +#define CSI2_STATUS_IRQ_DISCARD_UNMATCHED BIT(23) +#define CSI2_STATUS_IRQ_DISCARD_INACTIVE BIT(24) + +/* CSI2_CTRL */ +#define CSI2_CTRL_EOP_IS_EOL BIT(0) + +/* CSI2_CH_CTRL */ +#define CSI2_CH_CTRL_DMA_EN BIT(0) +#define CSI2_CH_CTRL_FORCE BIT(3) +#define CSI2_CH_CTRL_AUTO_ARM BIT(4) +#define CSI2_CH_CTRL_IRQ_EN_FS BIT(13) +#define CSI2_CH_CTRL_IRQ_EN_FE BIT(14) +#define CSI2_CH_CTRL_IRQ_EN_FE_ACK BIT(15) +#define CSI2_CH_CTRL_IRQ_EN_LE BIT(16) +#define CSI2_CH_CTRL_IRQ_EN_LE_ACK BIT(17) +#define CSI2_CH_CTRL_FLUSH_FE BIT(28) +#define CSI2_CH_CTRL_PACK_LINE BIT(29) +#define CSI2_CH_CTRL_PACK_BYTES BIT(30) +#define CSI2_CH_CTRL_CH_MODE_MASK GENMASK(2, 1) +#define CSI2_CH_CTRL_VC_MASK GENMASK(6, 5) +#define CSI2_CH_CTRL_DT_MASK GENMASK(12, 7) +#define CSI2_CH_CTRL_LC_MASK GENMASK(27, 18) + +/* CHx_COMPRESSION_CONTROL */ +#define CSI2_CH_COMP_CTRL_OFFSET_MASK GENMASK(15, 0) +#define CSI2_CH_COMP_CTRL_SHIFT_MASK GENMASK(19, 16) +#define CSI2_CH_COMP_CTRL_MODE_MASK GENMASK(25, 24) + +static inline u32 csi2_reg_read(struct csi2_device *csi2, u32 offset) +{ + return readl(csi2->base + offset); +} + +static inline void csi2_reg_write(struct csi2_device *csi2, u32 offset, u32 val) +{ + writel(val, csi2->base + offset); +} + +static inline void set_field(u32 *valp, u32 field, u32 mask) +{ + u32 val = *valp; + + val &= ~mask; + val |= (field << __ffs(mask)) & mask; + *valp = val; +} + +static int csi2_regs_show(struct seq_file *s, void *data) +{ + struct csi2_device *csi2 = s->private; + int ret; + + ret = pm_runtime_resume_and_get(csi2->v4l2_dev->dev); + if (ret) + return ret; + +#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", csi2_reg_read(csi2, reg)) +#define DUMP_CH(idx, reg) seq_printf(s, #reg "(%u) \t0x%08x\n", idx, \ + csi2_reg_read(csi2, reg(idx))) + + DUMP(CSI2_STATUS); + DUMP(CSI2_DISCARDS_OVERFLOW); + DUMP(CSI2_DISCARDS_INACTIVE); + DUMP(CSI2_DISCARDS_UNMATCHED); + DUMP(CSI2_DISCARDS_LEN_LIMIT); + DUMP(CSI2_LLEV_PANICS); + DUMP(CSI2_ULEV_PANICS); + DUMP(CSI2_IRQ_MASK); + DUMP(CSI2_CTRL); + + for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; ++i) { + DUMP_CH(i, CSI2_CH_CTRL); + DUMP_CH(i, CSI2_CH_ADDR0); + DUMP_CH(i, CSI2_CH_ADDR1); + DUMP_CH(i, CSI2_CH_STRIDE); + DUMP_CH(i, CSI2_CH_LENGTH); + DUMP_CH(i, CSI2_CH_DEBUG); + DUMP_CH(i, CSI2_CH_FRAME_SIZE); + DUMP_CH(i, CSI2_CH_COMP_CTRL); + DUMP_CH(i, CSI2_CH_FE_FRAME_ID); + } + +#undef DUMP +#undef DUMP_CH + + pm_runtime_put(csi2->v4l2_dev->dev); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(csi2_regs); + +static int csi2_errors_show(struct seq_file *s, void *data) +{ + struct csi2_device *csi2 = s->private; + unsigned long flags; + u32 discards_table[DISCARDS_TABLE_NUM_VCS][DISCARDS_TABLE_NUM_ENTRIES]; + u32 discards_dt_table[DISCARDS_TABLE_NUM_ENTRIES]; + u32 overflows; + + spin_lock_irqsave(&csi2->errors_lock, flags); + + memcpy(discards_table, csi2->discards_table, sizeof(discards_table)); + memcpy(discards_dt_table, csi2->discards_dt_table, + sizeof(discards_dt_table)); + overflows = csi2->overflows; + + csi2->overflows = 0; + memset(csi2->discards_table, 0, sizeof(discards_table)); + memset(csi2->discards_dt_table, 0, sizeof(discards_dt_table)); + + spin_unlock_irqrestore(&csi2->errors_lock, flags); + + seq_printf(s, "Overflows %u\n", overflows); + seq_puts(s, "Discards:\n"); + seq_puts(s, "VC OVLF LEN UNMATCHED INACTIVE\n"); + + for (unsigned int vc = 0; vc < DISCARDS_TABLE_NUM_VCS; ++vc) { + seq_printf(s, "%u %10u %10u %10u %10u\n", vc, + discards_table[vc][DISCARDS_TABLE_OVERFLOW], + discards_table[vc][DISCARDS_TABLE_LENGTH_LIMIT], + discards_table[vc][DISCARDS_TABLE_UNMATCHED], + discards_table[vc][DISCARDS_TABLE_INACTIVE]); + } + + seq_printf(s, "Last DT %10u %10u %10u %10u\n", + discards_dt_table[DISCARDS_TABLE_OVERFLOW], + discards_dt_table[DISCARDS_TABLE_LENGTH_LIMIT], + discards_dt_table[DISCARDS_TABLE_UNMATCHED], + discards_dt_table[DISCARDS_TABLE_INACTIVE]); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(csi2_errors); + +static void csi2_isr_handle_errors(struct csi2_device *csi2, u32 status) +{ + spin_lock(&csi2->errors_lock); + + if (status & CSI2_STATUS_IRQ_OVERFLOW) + csi2->overflows++; + + for (unsigned int i = 0; i < DISCARDS_TABLE_NUM_ENTRIES; ++i) { + static const u32 discard_bits[] = { + CSI2_STATUS_IRQ_DISCARD_OVERFLOW, + CSI2_STATUS_IRQ_DISCARD_LEN_LIMIT, + CSI2_STATUS_IRQ_DISCARD_UNMATCHED, + CSI2_STATUS_IRQ_DISCARD_INACTIVE, + }; + static const u8 discard_regs[] = { + CSI2_DISCARDS_OVERFLOW, + CSI2_DISCARDS_LEN_LIMIT, + CSI2_DISCARDS_UNMATCHED, + CSI2_DISCARDS_INACTIVE, + }; + u32 amount; + u8 dt, vc; + u32 v; + + if (!(status & discard_bits[i])) + continue; + + v = csi2_reg_read(csi2, discard_regs[i]); + csi2_reg_write(csi2, discard_regs[i], 0); + + amount = (v & CSI2_DISCARDS_AMOUNT_MASK) >> + CSI2_DISCARDS_AMOUNT_SHIFT; + dt = (v & CSI2_DISCARDS_DT_MASK) >> CSI2_DISCARDS_DT_SHIFT; + vc = (v & CSI2_DISCARDS_VC_MASK) >> CSI2_DISCARDS_VC_SHIFT; + + csi2->discards_table[vc][i] += amount; + csi2->discards_dt_table[i] = dt; + } + + spin_unlock(&csi2->errors_lock); +} + +void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof) +{ + u32 status; + + status = csi2_reg_read(csi2, CSI2_STATUS); + + /* Write value back to clear the interrupts */ + csi2_reg_write(csi2, CSI2_STATUS, status); + + for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; i++) { + u32 dbg; + + if ((status & CSI2_STATUS_IRQ_CH_MASK(i)) == 0) + continue; + + dbg = csi2_reg_read(csi2, CSI2_CH_DEBUG(i)); + + trace_csi2_irq(i, status, dbg); + + sof[i] = !!(status & CSI2_STATUS_IRQ_FS(i)); + eof[i] = !!(status & CSI2_STATUS_IRQ_FE_ACK(i)); + } + + if (csi2_track_errors) + csi2_isr_handle_errors(csi2, status); +} + +void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel, + dma_addr_t dmaaddr, unsigned int stride, unsigned int size) +{ + u64 addr = dmaaddr; + /* + * ADDRESS0 must be written last as it triggers the double buffering + * mechanism for all buffer registers within the hardware. + */ + addr >>= 4; + csi2_reg_write(csi2, CSI2_CH_LENGTH(channel), size >> 4); + csi2_reg_write(csi2, CSI2_CH_STRIDE(channel), stride >> 4); + csi2_reg_write(csi2, CSI2_CH_ADDR1(channel), addr >> 32); + csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), addr & 0xffffffff); +} + +void csi2_set_compression(struct csi2_device *csi2, unsigned int channel, + enum csi2_compression_mode mode, unsigned int shift, + unsigned int offset) +{ + u32 compression = 0; + + set_field(&compression, CSI2_CH_COMP_CTRL_OFFSET_MASK, offset); + set_field(&compression, CSI2_CH_COMP_CTRL_SHIFT_MASK, shift); + set_field(&compression, CSI2_CH_COMP_CTRL_MODE_MASK, mode); + csi2_reg_write(csi2, CSI2_CH_COMP_CTRL(channel), compression); +} + +void csi2_start_channel(struct csi2_device *csi2, unsigned int channel, + enum csi2_mode mode, bool auto_arm, bool pack_bytes, + unsigned int width, unsigned int height, + u8 vc, u8 dt) +{ + u32 ctrl; + + csi2_dbg(csi2, "%s [%u]\n", __func__, channel); + + csi2_reg_write(csi2, CSI2_CH_CTRL(channel), 0); + csi2_reg_write(csi2, CSI2_CH_DEBUG(channel), 0); + csi2_reg_write(csi2, CSI2_STATUS, CSI2_STATUS_IRQ_CH_MASK(channel)); + + /* Enable channel and FS/FE interrupts. */ + ctrl = CSI2_CH_CTRL_DMA_EN | CSI2_CH_CTRL_IRQ_EN_FS | + CSI2_CH_CTRL_IRQ_EN_FE_ACK | CSI2_CH_CTRL_PACK_LINE; + /* PACK_BYTES ensures no striding for embedded data. */ + if (pack_bytes) + ctrl |= CSI2_CH_CTRL_PACK_BYTES; + + if (auto_arm) + ctrl |= CSI2_CH_CTRL_AUTO_ARM; + + if (width && height) { + set_field(&ctrl, mode, CSI2_CH_CTRL_CH_MODE_MASK); + csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), + (height << 16) | width); + } else { + set_field(&ctrl, 0x0, CSI2_CH_CTRL_CH_MODE_MASK); + csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), 0); + } + + set_field(&ctrl, vc, CSI2_CH_CTRL_VC_MASK); + set_field(&ctrl, dt, CSI2_CH_CTRL_DT_MASK); + csi2_reg_write(csi2, CSI2_CH_CTRL(channel), ctrl); + csi2->num_lines[channel] = height; +} + +void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel) +{ + csi2_dbg(csi2, "%s [%u]\n", __func__, channel); + + /* Channel disable. Use FORCE to allow stopping mid-frame. */ + csi2_reg_write(csi2, CSI2_CH_CTRL(channel), CSI2_CH_CTRL_FORCE); + /* Latch the above change by writing to the ADDR0 register. */ + csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), 0); + /* Write this again, the HW needs it! */ + csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), 0); +} + +void csi2_open_rx(struct csi2_device *csi2) +{ + csi2_reg_write(csi2, CSI2_IRQ_MASK, + csi2_track_errors ? CSI2_IRQ_MASK_IRQ_ALL : 0); + + dphy_start(&csi2->dphy); + + csi2_reg_write(csi2, CSI2_CTRL, CSI2_CTRL_EOP_IS_EOL); +} + +void csi2_close_rx(struct csi2_device *csi2) +{ + dphy_stop(&csi2->dphy); + + csi2_reg_write(csi2, CSI2_IRQ_MASK, 0); +} + +static int csi2_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] = { { + .sink_pad = CSI2_PAD_SINK, + .sink_stream = 0, + .source_pad = CSI2_PAD_FIRST_SOURCE, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + } }; + + struct v4l2_subdev_krouting routing = { + .num_routes = ARRAY_SIZE(routes), + .routes = routes, + }; + + int ret; + + ret = v4l2_subdev_set_routing_with_fmt(sd, state, &routing, + &cfe_default_format); + if (ret) + return ret; + + return 0; +} + +static int csi2_pad_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + if (format->pad == CSI2_PAD_SINK) { + /* Store the sink format and propagate it to the source. */ + + const struct cfe_fmt *cfe_fmt; + + cfe_fmt = find_format_by_code(format->format.code); + if (!cfe_fmt) { + cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB10_1X10); + format->format.code = cfe_fmt->code; + } + + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_state_get_format(state, format->pad, + format->stream); + if (!fmt) + return -EINVAL; + + *fmt = format->format; + + fmt = v4l2_subdev_state_get_opposite_stream_format(state, + format->pad, + format->stream); + if (!fmt) + return -EINVAL; + + format->format.field = V4L2_FIELD_NONE; + + *fmt = format->format; + } else { + /* Only allow changing the source pad mbus code. */ + + struct v4l2_mbus_framefmt *sink_fmt, *source_fmt; + u32 sink_code; + u32 code; + + sink_fmt = v4l2_subdev_state_get_opposite_stream_format(state, + format->pad, + format->stream); + if (!sink_fmt) + return -EINVAL; + + source_fmt = v4l2_subdev_state_get_format(state, format->pad, + format->stream); + if (!source_fmt) + return -EINVAL; + + sink_code = sink_fmt->code; + code = format->format.code; + + /* + * Only allow changing the mbus code to: + * - The sink's mbus code + * - The 16-bit version of the sink's mbus code + * - The compressed version of the sink's mbus code + */ + if (code == sink_code || + code == cfe_find_16bit_code(sink_code) || + code == cfe_find_compressed_code(sink_code)) + source_fmt->code = code; + + format->format.code = source_fmt->code; + } + + return 0; +} + +static int csi2_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + int ret; + + ret = v4l2_subdev_routing_validate(sd, routing, + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 | + V4L2_SUBDEV_ROUTING_NO_SOURCE_MULTIPLEXING); + if (ret) + return ret; + + /* Only stream ID 0 allowed on source pads */ + for (unsigned int i = 0; i < routing->num_routes; ++i) { + const struct v4l2_subdev_route *route = &routing->routes[i]; + + if (route->source_stream != 0) + return -EINVAL; + } + + ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, + &cfe_default_format); + if (ret) + return ret; + + return 0; +} + +static const struct v4l2_subdev_pad_ops csi2_subdev_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = csi2_pad_set_fmt, + .set_routing = csi2_set_routing, + .link_validate = v4l2_subdev_link_validate_default, +}; + +static const struct media_entity_operations csi2_entity_ops = { + .link_validate = v4l2_subdev_link_validate, + .has_pad_interdep = v4l2_subdev_has_pad_interdep, +}; + +static const struct v4l2_subdev_ops csi2_subdev_ops = { + .pad = &csi2_subdev_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops csi2_internal_ops = { + .init_state = csi2_init_state, +}; + +int csi2_init(struct csi2_device *csi2, struct dentry *debugfs) +{ + unsigned int ret; + + spin_lock_init(&csi2->errors_lock); + + csi2->dphy.dev = csi2->v4l2_dev->dev; + dphy_probe(&csi2->dphy); + + debugfs_create_file("csi2_regs", 0440, debugfs, csi2, &csi2_regs_fops); + + if (csi2_track_errors) + debugfs_create_file("csi2_errors", 0440, debugfs, csi2, + &csi2_errors_fops); + + csi2->pad[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + + for (unsigned int i = CSI2_PAD_FIRST_SOURCE; + i < CSI2_PAD_FIRST_SOURCE + CSI2_PAD_NUM_SOURCES; i++) + csi2->pad[i].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&csi2->sd.entity, ARRAY_SIZE(csi2->pad), + csi2->pad); + if (ret) + return ret; + + /* Initialize subdev */ + v4l2_subdev_init(&csi2->sd, &csi2_subdev_ops); + csi2->sd.internal_ops = &csi2_internal_ops; + csi2->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + csi2->sd.entity.ops = &csi2_entity_ops; + csi2->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS; + csi2->sd.owner = THIS_MODULE; + snprintf(csi2->sd.name, sizeof(csi2->sd.name), "csi2"); + + ret = v4l2_subdev_init_finalize(&csi2->sd); + if (ret) + goto err_entity_cleanup; + + ret = v4l2_device_register_subdev(csi2->v4l2_dev, &csi2->sd); + if (ret) { + csi2_err(csi2, "Failed register csi2 subdev (%d)\n", ret); + goto err_subdev_cleanup; + } + + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(&csi2->sd); +err_entity_cleanup: + media_entity_cleanup(&csi2->sd.entity); + + return ret; +} + +void csi2_uninit(struct csi2_device *csi2) +{ + v4l2_device_unregister_subdev(&csi2->sd); + v4l2_subdev_cleanup(&csi2->sd); + media_entity_cleanup(&csi2->sd.entity); +} diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/csi2.h b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.h new file mode 100644 index 000000000000..a8ee5de565fb --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * RP1 CSI-2 Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ + +#ifndef _RP1_CSI2_ +#define _RP1_CSI2_ + +#include <linux/debugfs.h> +#include <linux/io.h> +#include <linux/types.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> + +#include "dphy.h" + +#define CSI2_NUM_CHANNELS 4 + +#define CSI2_PAD_SINK 0 +#define CSI2_PAD_FIRST_SOURCE 1 +#define CSI2_PAD_NUM_SOURCES 4 +#define CSI2_NUM_PADS 5 + +#define DISCARDS_TABLE_NUM_VCS 4 + +enum csi2_mode { + CSI2_MODE_NORMAL = 0, + CSI2_MODE_REMAP = 1, + CSI2_MODE_COMPRESSED = 2, + CSI2_MODE_FE_STREAMING = 3, +}; + +enum csi2_compression_mode { + CSI2_COMPRESSION_DELTA = 1, + CSI2_COMPRESSION_SIMPLE = 2, + CSI2_COMPRESSION_COMBINED = 3, +}; + +enum discards_table_index { + DISCARDS_TABLE_OVERFLOW = 0, + DISCARDS_TABLE_LENGTH_LIMIT, + DISCARDS_TABLE_UNMATCHED, + DISCARDS_TABLE_INACTIVE, + DISCARDS_TABLE_NUM_ENTRIES, +}; + +struct csi2_device { + /* Parent V4l2 device */ + struct v4l2_device *v4l2_dev; + + void __iomem *base; + + struct dphy_data dphy; + + enum v4l2_mbus_type bus_type; + unsigned int bus_flags; + unsigned int num_lines[CSI2_NUM_CHANNELS]; + + struct media_pad pad[CSI2_NUM_PADS]; + struct v4l2_subdev sd; + + /* lock for csi2 errors counters */ + spinlock_t errors_lock; + u32 overflows; + u32 discards_table[DISCARDS_TABLE_NUM_VCS][DISCARDS_TABLE_NUM_ENTRIES]; + u32 discards_dt_table[DISCARDS_TABLE_NUM_ENTRIES]; +}; + +void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof); +void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel, + dma_addr_t dmaaddr, unsigned int stride, + unsigned int size); +void csi2_set_compression(struct csi2_device *csi2, unsigned int channel, + enum csi2_compression_mode mode, unsigned int shift, + unsigned int offset); +void csi2_start_channel(struct csi2_device *csi2, unsigned int channel, + enum csi2_mode mode, bool auto_arm, + bool pack_bytes, unsigned int width, + unsigned int height, u8 vc, u8 dt); +void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel); +void csi2_open_rx(struct csi2_device *csi2); +void csi2_close_rx(struct csi2_device *csi2); +int csi2_init(struct csi2_device *csi2, struct dentry *debugfs); +void csi2_uninit(struct csi2_device *csi2); + +#endif diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c new file mode 100644 index 000000000000..b443f0f56ddc --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RP1 CSI-2 Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ + +#include <linux/delay.h> +#include <linux/pm_runtime.h> + +#include "dphy.h" + +#define dphy_dbg(dphy, fmt, arg...) dev_dbg((dphy)->dev, fmt, ##arg) +#define dphy_err(dphy, fmt, arg...) dev_err((dphy)->dev, fmt, ##arg) + +/* DW dphy Host registers */ +#define DPHY_VERSION 0x000 +#define DPHY_N_LANES 0x004 +#define DPHY_RESETN 0x008 +#define DPHY_PHY_SHUTDOWNZ 0x040 +#define DPHY_PHY_RSTZ 0x044 +#define DPHY_PHY_RX 0x048 +#define DPHY_PHY_STOPSTATE 0x04c +#define DPHY_PHY_TST_CTRL0 0x050 +#define DPHY_PHY_TST_CTRL1 0x054 +#define DPHY_PHY2_TST_CTRL0 0x058 +#define DPHY_PHY2_TST_CTRL1 0x05c + +/* DW dphy Host Transactions */ +#define DPHY_HS_RX_CTRL_LANE0_OFFSET 0x44 +#define DPHY_PLL_INPUT_DIV_OFFSET 0x17 +#define DPHY_PLL_LOOP_DIV_OFFSET 0x18 +#define DPHY_PLL_DIV_CTRL_OFFSET 0x19 + +static u32 dw_csi2_host_read(struct dphy_data *dphy, u32 offset) +{ + return readl(dphy->base + offset); +} + +static void dw_csi2_host_write(struct dphy_data *dphy, u32 offset, u32 data) +{ + writel(data, dphy->base + offset); +} + +static void set_tstclr(struct dphy_data *dphy, u32 val) +{ + u32 ctrl0 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL0); + + dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL0, (ctrl0 & ~1) | val); +} + +static void set_tstclk(struct dphy_data *dphy, u32 val) +{ + u32 ctrl0 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL0); + + dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL0, (ctrl0 & ~2) | (val << 1)); +} + +static uint8_t get_tstdout(struct dphy_data *dphy) +{ + u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1); + + return ((ctrl1 >> 8) & 0xff); +} + +static void set_testen(struct dphy_data *dphy, u32 val) +{ + u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1); + + dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL1, + (ctrl1 & ~(1 << 16)) | (val << 16)); +} + +static void set_testdin(struct dphy_data *dphy, u32 val) +{ + u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1); + + dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL1, (ctrl1 & ~0xff) | val); +} + +static uint8_t dphy_transaction(struct dphy_data *dphy, u8 test_code, + uint8_t test_data) +{ + /* See page 101 of the MIPI DPHY databook. */ + set_tstclk(dphy, 1); + set_testen(dphy, 0); + set_testdin(dphy, test_code); + set_testen(dphy, 1); + set_tstclk(dphy, 0); + set_testen(dphy, 0); + set_testdin(dphy, test_data); + set_tstclk(dphy, 1); + return get_tstdout(dphy); +} + +static void dphy_set_hsfreqrange(struct dphy_data *dphy, uint32_t mbps) +{ + /* See Table 5-1 on page 65 of dphy databook */ + static const u16 hsfreqrange_table[][2] = { + { 89, 0b000000 }, { 99, 0b010000 }, { 109, 0b100000 }, + { 129, 0b000001 }, { 139, 0b010001 }, { 149, 0b100001 }, + { 169, 0b000010 }, { 179, 0b010010 }, { 199, 0b100010 }, + { 219, 0b000011 }, { 239, 0b010011 }, { 249, 0b100011 }, + { 269, 0b000100 }, { 299, 0b010100 }, { 329, 0b000101 }, + { 359, 0b010101 }, { 399, 0b100101 }, { 449, 0b000110 }, + { 499, 0b010110 }, { 549, 0b000111 }, { 599, 0b010111 }, + { 649, 0b001000 }, { 699, 0b011000 }, { 749, 0b001001 }, + { 799, 0b011001 }, { 849, 0b101001 }, { 899, 0b111001 }, + { 949, 0b001010 }, { 999, 0b011010 }, { 1049, 0b101010 }, + { 1099, 0b111010 }, { 1149, 0b001011 }, { 1199, 0b011011 }, + { 1249, 0b101011 }, { 1299, 0b111011 }, { 1349, 0b001100 }, + { 1399, 0b011100 }, { 1449, 0b101100 }, { 1500, 0b111100 }, + }; + unsigned int i; + + if (mbps < 80 || mbps > 1500) + dphy_err(dphy, "DPHY: Datarate %u Mbps out of range\n", mbps); + + for (i = 0; i < ARRAY_SIZE(hsfreqrange_table) - 1; i++) { + if (mbps <= hsfreqrange_table[i][0]) + break; + } + + dphy_transaction(dphy, DPHY_HS_RX_CTRL_LANE0_OFFSET, + hsfreqrange_table[i][1] << 1); +} + +static void dphy_init(struct dphy_data *dphy) +{ + dw_csi2_host_write(dphy, DPHY_PHY_RSTZ, 0); + dw_csi2_host_write(dphy, DPHY_PHY_SHUTDOWNZ, 0); + set_tstclk(dphy, 1); + set_testen(dphy, 0); + set_tstclr(dphy, 1); + usleep_range(15, 20); + set_tstclr(dphy, 0); + usleep_range(15, 20); + + dphy_set_hsfreqrange(dphy, dphy->dphy_rate); + + usleep_range(5, 10); + dw_csi2_host_write(dphy, DPHY_PHY_SHUTDOWNZ, 1); + usleep_range(5, 10); + dw_csi2_host_write(dphy, DPHY_PHY_RSTZ, 1); +} + +void dphy_start(struct dphy_data *dphy) +{ + dphy_dbg(dphy, "%s: Link rate %u Mbps, %u data lanes\n", __func__, + dphy->dphy_rate, dphy->active_lanes); + + dw_csi2_host_write(dphy, DPHY_N_LANES, (dphy->active_lanes - 1)); + dphy_init(dphy); + dw_csi2_host_write(dphy, DPHY_RESETN, 0xffffffff); + usleep_range(10, 50); +} + +void dphy_stop(struct dphy_data *dphy) +{ + dphy_dbg(dphy, "%s\n", __func__); + + /* Set only one lane (lane 0) as active (ON) */ + dw_csi2_host_write(dphy, DPHY_N_LANES, 0); + dw_csi2_host_write(dphy, DPHY_RESETN, 0); +} + +void dphy_probe(struct dphy_data *dphy) +{ + u32 host_ver; + u8 host_ver_major, host_ver_minor; + + host_ver = dw_csi2_host_read(dphy, DPHY_VERSION); + host_ver_major = (u8)((host_ver >> 24) - '0'); + host_ver_minor = (u8)((host_ver >> 16) - '0'); + host_ver_minor = host_ver_minor * 10; + host_ver_minor += (u8)((host_ver >> 8) - '0'); + + dphy_dbg(dphy, "DW dphy Host HW v%u.%u\n", host_ver_major, + host_ver_minor); +} diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/dphy.h b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.h new file mode 100644 index 000000000000..84fa370957cc --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ + +#ifndef _RP1_DPHY_ +#define _RP1_DPHY_ + +#include <linux/io.h> +#include <linux/types.h> + +struct dphy_data { + struct device *dev; + + void __iomem *base; + + u32 dphy_rate; + u32 max_lanes; + u32 active_lanes; +}; + +void dphy_probe(struct dphy_data *dphy); +void dphy_start(struct dphy_data *dphy); +void dphy_stop(struct dphy_data *dphy); + +#endif diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.c b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.c new file mode 100644 index 000000000000..05762b1be2bc --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.c @@ -0,0 +1,605 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PiSP Front End Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + */ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/moduleparam.h> +#include <linux/pm_runtime.h> +#include <linux/seq_file.h> + +#include <media/videobuf2-dma-contig.h> + +#include "cfe.h" +#include "pisp-fe.h" + +#include "cfe-trace.h" + +#define FE_VERSION 0x000 +#define FE_CONTROL 0x004 +#define FE_STATUS 0x008 +#define FE_FRAME_STATUS 0x00c +#define FE_ERROR_STATUS 0x010 +#define FE_OUTPUT_STATUS 0x014 +#define FE_INT_EN 0x018 +#define FE_INT_STATUS 0x01c + +/* CONTROL */ +#define FE_CONTROL_QUEUE BIT(0) +#define FE_CONTROL_ABORT BIT(1) +#define FE_CONTROL_RESET BIT(2) +#define FE_CONTROL_LATCH_REGS BIT(3) + +/* INT_EN / INT_STATUS */ +#define FE_INT_EOF BIT(0) +#define FE_INT_SOF BIT(1) +#define FE_INT_LINES0 BIT(8) +#define FE_INT_LINES1 BIT(9) +#define FE_INT_STATS BIT(16) +#define FE_INT_QREADY BIT(24) + +/* STATUS */ +#define FE_STATUS_QUEUED BIT(0) +#define FE_STATUS_WAITING BIT(1) +#define FE_STATUS_ACTIVE BIT(2) + +#define PISP_FE_CONFIG_BASE_OFFSET 0x0040 + +#define PISP_FE_ENABLE_STATS_CLUSTER \ + (PISP_FE_ENABLE_STATS_CROP | PISP_FE_ENABLE_DECIMATE | \ + PISP_FE_ENABLE_BLC | PISP_FE_ENABLE_CDAF_STATS | \ + PISP_FE_ENABLE_AWB_STATS | PISP_FE_ENABLE_RGBY | \ + PISP_FE_ENABLE_LSC | PISP_FE_ENABLE_AGC_STATS) + +#define PISP_FE_ENABLE_OUTPUT_CLUSTER(i) \ + ((PISP_FE_ENABLE_CROP0 | PISP_FE_ENABLE_DOWNSCALE0 | \ + PISP_FE_ENABLE_COMPRESS0 | PISP_FE_ENABLE_OUTPUT0) << (4 * (i))) + +struct pisp_fe_config_param { + u32 dirty_flags; + u32 dirty_flags_extra; + size_t offset; + size_t size; +}; + +static const struct pisp_fe_config_param pisp_fe_config_map[] = { + /* *_dirty_flag_extra types */ + { 0, PISP_FE_DIRTY_GLOBAL, + offsetof(struct pisp_fe_config, global), + sizeof(struct pisp_fe_global_config) }, + { 0, PISP_FE_DIRTY_FLOATING, + offsetof(struct pisp_fe_config, floating_stats), + sizeof(struct pisp_fe_floating_stats_config) }, + { 0, PISP_FE_DIRTY_OUTPUT_AXI, + offsetof(struct pisp_fe_config, output_axi), + sizeof(struct pisp_fe_output_axi_config) }, + /* *_dirty_flag types */ + { PISP_FE_ENABLE_INPUT, 0, + offsetof(struct pisp_fe_config, input), + sizeof(struct pisp_fe_input_config) }, + { PISP_FE_ENABLE_DECOMPRESS, 0, + offsetof(struct pisp_fe_config, decompress), + sizeof(struct pisp_decompress_config) }, + { PISP_FE_ENABLE_DECOMPAND, 0, + offsetof(struct pisp_fe_config, decompand), + sizeof(struct pisp_fe_decompand_config) }, + { PISP_FE_ENABLE_BLA, 0, + offsetof(struct pisp_fe_config, bla), + sizeof(struct pisp_bla_config) }, + { PISP_FE_ENABLE_DPC, 0, + offsetof(struct pisp_fe_config, dpc), + sizeof(struct pisp_fe_dpc_config) }, + { PISP_FE_ENABLE_STATS_CROP, 0, + offsetof(struct pisp_fe_config, stats_crop), + sizeof(struct pisp_fe_crop_config) }, + { PISP_FE_ENABLE_BLC, 0, + offsetof(struct pisp_fe_config, blc), + sizeof(struct pisp_bla_config) }, + { PISP_FE_ENABLE_CDAF_STATS, 0, + offsetof(struct pisp_fe_config, cdaf_stats), + sizeof(struct pisp_fe_cdaf_stats_config) }, + { PISP_FE_ENABLE_AWB_STATS, 0, + offsetof(struct pisp_fe_config, awb_stats), + sizeof(struct pisp_fe_awb_stats_config) }, + { PISP_FE_ENABLE_RGBY, 0, + offsetof(struct pisp_fe_config, rgby), + sizeof(struct pisp_fe_rgby_config) }, + { PISP_FE_ENABLE_LSC, 0, + offsetof(struct pisp_fe_config, lsc), + sizeof(struct pisp_fe_lsc_config) }, + { PISP_FE_ENABLE_AGC_STATS, 0, + offsetof(struct pisp_fe_config, agc_stats), + sizeof(struct pisp_agc_statistics) }, + { PISP_FE_ENABLE_CROP0, 0, + offsetof(struct pisp_fe_config, ch[0].crop), + sizeof(struct pisp_fe_crop_config) }, + { PISP_FE_ENABLE_DOWNSCALE0, 0, + offsetof(struct pisp_fe_config, ch[0].downscale), + sizeof(struct pisp_fe_downscale_config) }, + { PISP_FE_ENABLE_COMPRESS0, 0, + offsetof(struct pisp_fe_config, ch[0].compress), + sizeof(struct pisp_compress_config) }, + { PISP_FE_ENABLE_OUTPUT0, 0, + offsetof(struct pisp_fe_config, ch[0].output), + sizeof(struct pisp_fe_output_config) }, + { PISP_FE_ENABLE_CROP1, 0, + offsetof(struct pisp_fe_config, ch[1].crop), + sizeof(struct pisp_fe_crop_config) }, + { PISP_FE_ENABLE_DOWNSCALE1, 0, + offsetof(struct pisp_fe_config, ch[1].downscale), + sizeof(struct pisp_fe_downscale_config) }, + { PISP_FE_ENABLE_COMPRESS1, 0, + offsetof(struct pisp_fe_config, ch[1].compress), + sizeof(struct pisp_compress_config) }, + { PISP_FE_ENABLE_OUTPUT1, 0, + offsetof(struct pisp_fe_config, ch[1].output), + sizeof(struct pisp_fe_output_config) }, +}; + +#define pisp_fe_dbg(fe, fmt, arg...) dev_dbg((fe)->v4l2_dev->dev, fmt, ##arg) +#define pisp_fe_info(fe, fmt, arg...) dev_info((fe)->v4l2_dev->dev, fmt, ##arg) +#define pisp_fe_err(fe, fmt, arg...) dev_err((fe)->v4l2_dev->dev, fmt, ##arg) + +static inline u32 pisp_fe_reg_read(struct pisp_fe_device *fe, u32 offset) +{ + return readl(fe->base + offset); +} + +static inline void pisp_fe_reg_write(struct pisp_fe_device *fe, u32 offset, + u32 val) +{ + writel(val, fe->base + offset); +} + +static inline void pisp_fe_reg_write_relaxed(struct pisp_fe_device *fe, + u32 offset, u32 val) +{ + writel_relaxed(val, fe->base + offset); +} + +static int pisp_fe_regs_show(struct seq_file *s, void *data) +{ + struct pisp_fe_device *fe = s->private; + int ret; + + ret = pm_runtime_resume_and_get(fe->v4l2_dev->dev); + if (ret) + return ret; + + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS); + +#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", pisp_fe_reg_read(fe, reg)) + DUMP(FE_VERSION); + DUMP(FE_CONTROL); + DUMP(FE_STATUS); + DUMP(FE_FRAME_STATUS); + DUMP(FE_ERROR_STATUS); + DUMP(FE_OUTPUT_STATUS); + DUMP(FE_INT_EN); + DUMP(FE_INT_STATUS); +#undef DUMP + + pm_runtime_put(fe->v4l2_dev->dev); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(pisp_fe_regs); + +static void pisp_fe_config_write(struct pisp_fe_device *fe, + struct pisp_fe_config *config, + unsigned int start_offset, unsigned int size) +{ + const unsigned int max_offset = + offsetof(struct pisp_fe_config, ch[PISP_FE_NUM_OUTPUTS]); + unsigned int end_offset; + u32 *cfg = (u32 *)config; + + start_offset = min(start_offset, max_offset); + end_offset = min(start_offset + size, max_offset); + + cfg += start_offset >> 2; + for (unsigned int i = start_offset; i < end_offset; i += 4, cfg++) + pisp_fe_reg_write_relaxed(fe, PISP_FE_CONFIG_BASE_OFFSET + i, + *cfg); +} + +void pisp_fe_isr(struct pisp_fe_device *fe, bool *sof, bool *eof) +{ + u32 status, int_status, out_status, frame_status, error_status; + + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS); + status = pisp_fe_reg_read(fe, FE_STATUS); + out_status = pisp_fe_reg_read(fe, FE_OUTPUT_STATUS); + frame_status = pisp_fe_reg_read(fe, FE_FRAME_STATUS); + error_status = pisp_fe_reg_read(fe, FE_ERROR_STATUS); + + int_status = pisp_fe_reg_read(fe, FE_INT_STATUS); + pisp_fe_reg_write(fe, FE_INT_STATUS, int_status); + + trace_fe_irq(status, out_status, frame_status, error_status, + int_status); + + /* We do not report interrupts for the input/stream pad. */ + for (unsigned int i = 0; i < FE_NUM_PADS - 1; i++) { + sof[i] = !!(int_status & FE_INT_SOF); + eof[i] = !!(int_status & FE_INT_EOF); + } +} + +static bool pisp_fe_validate_output(struct pisp_fe_config const *cfg, + unsigned int c, struct v4l2_format const *f) +{ + unsigned int wbytes; + + wbytes = cfg->ch[c].output.format.width; + if (cfg->ch[c].output.format.format & PISP_IMAGE_FORMAT_BPS_MASK) + wbytes *= 2; + + /* Check output image dimensions are nonzero and not too big */ + if (cfg->ch[c].output.format.width < 2 || + cfg->ch[c].output.format.height < 2 || + cfg->ch[c].output.format.height > f->fmt.pix.height || + cfg->ch[c].output.format.stride > f->fmt.pix.bytesperline || + wbytes > f->fmt.pix.bytesperline) + return false; + + /* Check for zero-sized crops, which could cause lockup */ + if ((cfg->global.enables & PISP_FE_ENABLE_CROP(c)) && + ((cfg->ch[c].crop.offset_x >= (cfg->input.format.width & ~1) || + cfg->ch[c].crop.offset_y >= cfg->input.format.height || + cfg->ch[c].crop.width < 2 || cfg->ch[c].crop.height < 2))) + return false; + + if ((cfg->global.enables & PISP_FE_ENABLE_DOWNSCALE(c)) && + (cfg->ch[c].downscale.output_width < 2 || + cfg->ch[c].downscale.output_height < 2)) + return false; + + return true; +} + +static bool pisp_fe_validate_stats(struct pisp_fe_config const *cfg) +{ + /* Check for zero-sized crop, which could cause lockup */ + return (!(cfg->global.enables & PISP_FE_ENABLE_STATS_CROP) || + (cfg->stats_crop.offset_x < (cfg->input.format.width & ~1) && + cfg->stats_crop.offset_y < cfg->input.format.height && + cfg->stats_crop.width >= 2 && cfg->stats_crop.height >= 2)); +} + +int pisp_fe_validate_config(struct pisp_fe_device *fe, + struct pisp_fe_config *cfg, + struct v4l2_format const *f0, + struct v4l2_format const *f1) +{ + /* + * Check the input is enabled, streaming and has nonzero size; + * to avoid cases where the hardware might lock up or try to + * read inputs from memory (which this driver doesn't support). + */ + if (!(cfg->global.enables & PISP_FE_ENABLE_INPUT) || + cfg->input.streaming != 1 || cfg->input.format.width < 2 || + cfg->input.format.height < 2) { + pisp_fe_err(fe, "%s: Input config not valid", __func__); + return -EINVAL; + } + + for (unsigned int i = 0; i < PISP_FE_NUM_OUTPUTS; i++) { + if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i))) { + if (cfg->global.enables & + PISP_FE_ENABLE_OUTPUT_CLUSTER(i)) { + pisp_fe_err(fe, "%s: Output %u not valid", + __func__, i); + return -EINVAL; + } + continue; + } + + if (!pisp_fe_validate_output(cfg, i, i ? f1 : f0)) + return -EINVAL; + } + + if ((cfg->global.enables & PISP_FE_ENABLE_STATS_CLUSTER) && + !pisp_fe_validate_stats(cfg)) { + pisp_fe_err(fe, "%s: Stats config not valid", __func__); + return -EINVAL; + } + + return 0; +} + +void pisp_fe_submit_job(struct pisp_fe_device *fe, struct vb2_buffer **vb2_bufs, + struct pisp_fe_config *cfg) +{ + u64 addr; + u32 status; + + /* + * Check output buffers exist and outputs are correctly configured. + * If valid, set the buffer's DMA address; otherwise disable. + */ + for (unsigned int i = 0; i < PISP_FE_NUM_OUTPUTS; i++) { + struct vb2_buffer *buf = vb2_bufs[FE_OUTPUT0_PAD + i]; + + if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i))) + continue; + + addr = vb2_dma_contig_plane_dma_addr(buf, 0); + cfg->output_buffer[i].addr_lo = addr & 0xffffffff; + cfg->output_buffer[i].addr_hi = addr >> 32; + } + + if (vb2_bufs[FE_STATS_PAD]) { + addr = vb2_dma_contig_plane_dma_addr(vb2_bufs[FE_STATS_PAD], 0); + cfg->stats_buffer.addr_lo = addr & 0xffffffff; + cfg->stats_buffer.addr_hi = addr >> 32; + } + + /* Set up ILINES interrupts 3/4 of the way down each output */ + cfg->ch[0].output.ilines = + max(0x80u, (3u * cfg->ch[0].output.format.height) >> 2); + cfg->ch[1].output.ilines = + max(0x80u, (3u * cfg->ch[1].output.format.height) >> 2); + + /* + * The hardware must have consumed the previous config by now. + * This read of status also serves as a memory barrier before the + * sequence of relaxed writes which follow. + */ + status = pisp_fe_reg_read(fe, FE_STATUS); + if (WARN_ON(status & FE_STATUS_QUEUED)) + return; + + /* + * Unconditionally write buffers, global and input parameters. + * Write cropping and output parameters whenever they are enabled. + * Selectively write other parameters that have been marked as + * changed through the dirty flags. + */ + pisp_fe_config_write(fe, cfg, 0, + offsetof(struct pisp_fe_config, decompress)); + cfg->dirty_flags_extra &= ~PISP_FE_DIRTY_GLOBAL; + cfg->dirty_flags &= ~PISP_FE_ENABLE_INPUT; + cfg->dirty_flags |= (cfg->global.enables & + (PISP_FE_ENABLE_STATS_CROP | + PISP_FE_ENABLE_OUTPUT_CLUSTER(0) | + PISP_FE_ENABLE_OUTPUT_CLUSTER(1))); + for (unsigned int i = 0; i < ARRAY_SIZE(pisp_fe_config_map); i++) { + const struct pisp_fe_config_param *p = &pisp_fe_config_map[i]; + + if (cfg->dirty_flags & p->dirty_flags || + cfg->dirty_flags_extra & p->dirty_flags_extra) + pisp_fe_config_write(fe, cfg, p->offset, p->size); + } + + /* This final non-relaxed write serves as a memory barrier */ + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_QUEUE); +} + +void pisp_fe_start(struct pisp_fe_device *fe) +{ + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_RESET); + pisp_fe_reg_write(fe, FE_INT_STATUS, ~0); + pisp_fe_reg_write(fe, FE_INT_EN, FE_INT_EOF | FE_INT_SOF | + FE_INT_LINES0 | FE_INT_LINES1); + fe->inframe_count = 0; +} + +void pisp_fe_stop(struct pisp_fe_device *fe) +{ + pisp_fe_reg_write(fe, FE_INT_EN, 0); + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_ABORT); + usleep_range(1000, 2000); + WARN_ON(pisp_fe_reg_read(fe, FE_STATUS)); + pisp_fe_reg_write(fe, FE_INT_STATUS, ~0); +} + +static int pisp_fe_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD); + *fmt = cfe_default_format; + fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; + + fmt = v4l2_subdev_state_get_format(state, FE_CONFIG_PAD); + fmt->code = MEDIA_BUS_FMT_FIXED; + fmt->width = sizeof(struct pisp_fe_config); + fmt->height = 1; + + fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT0_PAD); + *fmt = cfe_default_format; + fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; + + fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT1_PAD); + *fmt = cfe_default_format; + fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; + + fmt = v4l2_subdev_state_get_format(state, FE_STATS_PAD); + fmt->code = MEDIA_BUS_FMT_FIXED; + fmt->width = sizeof(struct pisp_statistics); + fmt->height = 1; + + return 0; +} + +static int pisp_fe_pad_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt; + const struct cfe_fmt *cfe_fmt; + + /* TODO: format propagation to source pads */ + /* TODO: format validation */ + + switch (format->pad) { + case FE_STREAM_PAD: + cfe_fmt = find_format_by_code(format->format.code); + if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT)) + cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB16_1X16); + + format->format.code = cfe_fmt->code; + format->format.field = V4L2_FIELD_NONE; + + fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD); + *fmt = format->format; + + fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT0_PAD); + *fmt = format->format; + + fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT1_PAD); + *fmt = format->format; + + return 0; + + case FE_OUTPUT0_PAD: + case FE_OUTPUT1_PAD: { + /* + * TODO: we should allow scaling and cropping by allowing the + * user to set the size here. + */ + struct v4l2_mbus_framefmt *sink_fmt, *source_fmt; + u32 sink_code; + u32 code; + + cfe_fmt = find_format_by_code(format->format.code); + if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT)) + cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB16_1X16); + + format->format.code = cfe_fmt->code; + + sink_fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD); + if (!sink_fmt) + return -EINVAL; + + source_fmt = v4l2_subdev_state_get_format(state, format->pad); + if (!source_fmt) + return -EINVAL; + + sink_code = sink_fmt->code; + code = format->format.code; + + /* + * If the source code from the user does not match the code in + * the sink pad, check that the source code matches the + * compressed version of the sink code. + */ + + if (code != sink_code && + code == cfe_find_compressed_code(sink_code)) + source_fmt->code = code; + + return 0; + } + + case FE_CONFIG_PAD: + case FE_STATS_PAD: + default: + return v4l2_subdev_get_fmt(sd, state, format); + } +} + +static const struct v4l2_subdev_pad_ops pisp_fe_subdev_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = pisp_fe_pad_set_fmt, + .link_validate = v4l2_subdev_link_validate_default, +}; + +static int pisp_fe_link_validate(struct media_link *link) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(link->sink->entity); + struct pisp_fe_device *fe = container_of(sd, struct pisp_fe_device, sd); + + pisp_fe_dbg(fe, "%s: link \"%s\":%u -> \"%s\":%u\n", __func__, + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index); + + if (link->sink->index == FE_STREAM_PAD) + return v4l2_subdev_link_validate(link); + + if (link->sink->index == FE_CONFIG_PAD) + return 0; + + return -EINVAL; +} + +static const struct media_entity_operations pisp_fe_entity_ops = { + .link_validate = pisp_fe_link_validate, +}; + +static const struct v4l2_subdev_ops pisp_fe_subdev_ops = { + .pad = &pisp_fe_subdev_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops pisp_fe_internal_ops = { + .init_state = pisp_fe_init_state, +}; + +int pisp_fe_init(struct pisp_fe_device *fe, struct dentry *debugfs) +{ + int ret; + + debugfs_create_file("fe_regs", 0440, debugfs, fe, &pisp_fe_regs_fops); + + fe->hw_revision = pisp_fe_reg_read(fe, FE_VERSION); + pisp_fe_info(fe, "PiSP FE HW v%u.%u\n", + (fe->hw_revision >> 24) & 0xff, + (fe->hw_revision >> 20) & 0x0f); + + fe->pad[FE_STREAM_PAD].flags = + MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; + fe->pad[FE_CONFIG_PAD].flags = MEDIA_PAD_FL_SINK; + fe->pad[FE_OUTPUT0_PAD].flags = MEDIA_PAD_FL_SOURCE; + fe->pad[FE_OUTPUT1_PAD].flags = MEDIA_PAD_FL_SOURCE; + fe->pad[FE_STATS_PAD].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&fe->sd.entity, ARRAY_SIZE(fe->pad), + fe->pad); + if (ret) + return ret; + + /* Initialize subdev */ + v4l2_subdev_init(&fe->sd, &pisp_fe_subdev_ops); + fe->sd.internal_ops = &pisp_fe_internal_ops; + fe->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; + fe->sd.entity.ops = &pisp_fe_entity_ops; + fe->sd.entity.name = "pisp-fe"; + fe->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + fe->sd.owner = THIS_MODULE; + snprintf(fe->sd.name, sizeof(fe->sd.name), "pisp-fe"); + + ret = v4l2_subdev_init_finalize(&fe->sd); + if (ret) + goto err_entity_cleanup; + + ret = v4l2_device_register_subdev(fe->v4l2_dev, &fe->sd); + if (ret) { + pisp_fe_err(fe, "Failed register pisp fe subdev (%d)\n", ret); + goto err_subdev_cleanup; + } + + /* Must be in IDLE state (STATUS == 0) here. */ + WARN_ON(pisp_fe_reg_read(fe, FE_STATUS)); + + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(&fe->sd); +err_entity_cleanup: + media_entity_cleanup(&fe->sd.entity); + + return ret; +} + +void pisp_fe_uninit(struct pisp_fe_device *fe) +{ + v4l2_device_unregister_subdev(&fe->sd); + v4l2_subdev_cleanup(&fe->sd); + media_entity_cleanup(&fe->sd.entity); +} diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.h b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.h new file mode 100644 index 000000000000..54d506e19cf2 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PiSP Front End Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + */ +#ifndef _PISP_FE_H_ +#define _PISP_FE_H_ + +#include <linux/debugfs.h> +#include <linux/io.h> +#include <linux/types.h> +#include <linux/videodev2.h> + +#include <media/media-device.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> + +#include <linux/media/raspberrypi/pisp_fe_config.h> + +enum pisp_fe_pads { + FE_STREAM_PAD, + FE_CONFIG_PAD, + FE_OUTPUT0_PAD, + FE_OUTPUT1_PAD, + FE_STATS_PAD, + FE_NUM_PADS +}; + +struct pisp_fe_device { + /* Parent V4l2 device */ + struct v4l2_device *v4l2_dev; + void __iomem *base; + u32 hw_revision; + + u16 inframe_count; + struct media_pad pad[FE_NUM_PADS]; + struct v4l2_subdev sd; +}; + +void pisp_fe_isr(struct pisp_fe_device *fe, bool *sof, bool *eof); +int pisp_fe_validate_config(struct pisp_fe_device *fe, + struct pisp_fe_config *cfg, + struct v4l2_format const *f0, + struct v4l2_format const *f1); +void pisp_fe_submit_job(struct pisp_fe_device *fe, struct vb2_buffer **vb2_bufs, + struct pisp_fe_config *cfg); +void pisp_fe_start(struct pisp_fe_device *fe); +void pisp_fe_stop(struct pisp_fe_device *fe); +int pisp_fe_init(struct pisp_fe_device *fe, struct dentry *debugfs); +void pisp_fe_uninit(struct pisp_fe_device *fe); + +#endif diff --git a/drivers/media/platform/renesas/rcar-csi2.c b/drivers/media/platform/renesas/rcar-csi2.c index c419ddb4c5a2..27ffdd28cbf7 100644 --- a/drivers/media/platform/renesas/rcar-csi2.c +++ b/drivers/media/platform/renesas/rcar-csi2.c @@ -135,13 +135,23 @@ struct rcar_csi2; /* V4H BASE registers */ #define V4H_N_LANES_REG 0x0004 #define V4H_CSI2_RESETN_REG 0x0008 + #define V4H_PHY_MODE_REG 0x001c +#define V4H_PHY_MODE_DPHY 0 +#define V4H_PHY_MODE_CPHY 1 + #define V4H_PHY_SHUTDOWNZ_REG 0x0040 #define V4H_DPHY_RSTZ_REG 0x0044 #define V4H_FLDC_REG 0x0804 #define V4H_FLDD_REG 0x0808 #define V4H_IDIC_REG 0x0810 + #define V4H_PHY_EN_REG 0x2000 +#define V4H_PHY_EN_ENABLE_3 BIT(7) +#define V4H_PHY_EN_ENABLE_2 BIT(6) +#define V4H_PHY_EN_ENABLE_1 BIT(5) +#define V4H_PHY_EN_ENABLE_0 BIT(4) +#define V4H_PHY_EN_ENABLE_CLK BIT(0) #define V4H_ST_PHYST_REG 0x2814 #define V4H_ST_PHYST_ST_PHY_READY BIT(31) @@ -237,17 +247,37 @@ static const struct rcsi2_cphy_setting cphy_setting_table_r8a779g0[] = { { /* sentinel */ }, }; +/* V4M registers */ +#define V4M_OVR1_REG 0x0848 +#define V4M_OVR1_FORCERXMODE_3 BIT(12) +#define V4M_OVR1_FORCERXMODE_2 BIT(11) +#define V4M_OVR1_FORCERXMODE_1 BIT(10) +#define V4M_OVR1_FORCERXMODE_0 BIT(9) + +#define V4M_FRXM_REG 0x2004 +#define V4M_FRXM_FORCERXMODE_3 BIT(3) +#define V4M_FRXM_FORCERXMODE_2 BIT(2) +#define V4M_FRXM_FORCERXMODE_1 BIT(1) +#define V4M_FRXM_FORCERXMODE_0 BIT(0) + +#define V4M_PHYPLL_REG 0x02050 +#define V4M_CSI0CLKFCPR_REG 0x02054 +#define V4M_PHTW_REG 0x02060 +#define V4M_PHTR_REG 0x02064 +#define V4M_PHTC_REG 0x02068 + struct phtw_value { - u16 data; - u16 code; + u8 data; + u8 code; }; -struct rcsi2_mbps_reg { +struct rcsi2_mbps_info { u16 mbps; - u16 reg; + u8 reg; + u16 osc_freq; /* V4M */ }; -static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = { +static const struct rcsi2_mbps_info phtw_mbps_v3u[] = { { .mbps = 1500, .reg = 0xcc }, { .mbps = 1550, .reg = 0x1d }, { .mbps = 1600, .reg = 0x27 }, @@ -272,7 +302,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = { { /* sentinel */ }, }; -static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { +static const struct rcsi2_mbps_info phtw_mbps_h3_v3h_m3n[] = { { .mbps = 80, .reg = 0x86 }, { .mbps = 90, .reg = 0x86 }, { .mbps = 100, .reg = 0x87 }, @@ -292,7 +322,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { { /* sentinel */ }, }; -static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { +static const struct rcsi2_mbps_info phtw_mbps_v3m_e3[] = { { .mbps = 80, .reg = 0x00 }, { .mbps = 90, .reg = 0x20 }, { .mbps = 100, .reg = 0x40 }, @@ -336,7 +366,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { #define PHYPLL_REG 0x68 #define PHYPLL_HSFREQRANGE(n) ((n) << 16) -static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = { +static const struct rcsi2_mbps_info hsfreqrange_v3u[] = { { .mbps = 80, .reg = 0x00 }, { .mbps = 90, .reg = 0x10 }, { .mbps = 100, .reg = 0x20 }, @@ -402,7 +432,7 @@ static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = { { /* sentinel */ }, }; -static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = { +static const struct rcsi2_mbps_info hsfreqrange_h3_v3h_m3n[] = { { .mbps = 80, .reg = 0x00 }, { .mbps = 90, .reg = 0x10 }, { .mbps = 100, .reg = 0x20 }, @@ -449,7 +479,7 @@ static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = { { /* sentinel */ }, }; -static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = { +static const struct rcsi2_mbps_info hsfreqrange_m3w[] = { { .mbps = 80, .reg = 0x00 }, { .mbps = 90, .reg = 0x10 }, { .mbps = 100, .reg = 0x20 }, @@ -496,6 +526,73 @@ static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = { { /* sentinel */ }, }; +static const struct rcsi2_mbps_info hsfreqrange_v4m[] = { + { .mbps = 80, .reg = 0x00, .osc_freq = 0x01a9 }, + { .mbps = 90, .reg = 0x10, .osc_freq = 0x01a9 }, + { .mbps = 100, .reg = 0x20, .osc_freq = 0x01a9 }, + { .mbps = 110, .reg = 0x30, .osc_freq = 0x01a9 }, + { .mbps = 120, .reg = 0x01, .osc_freq = 0x01a9 }, + { .mbps = 130, .reg = 0x11, .osc_freq = 0x01a9 }, + { .mbps = 140, .reg = 0x21, .osc_freq = 0x01a9 }, + { .mbps = 150, .reg = 0x31, .osc_freq = 0x01a9 }, + { .mbps = 160, .reg = 0x02, .osc_freq = 0x01a9 }, + { .mbps = 170, .reg = 0x12, .osc_freq = 0x01a9 }, + { .mbps = 180, .reg = 0x22, .osc_freq = 0x01a9 }, + { .mbps = 190, .reg = 0x32, .osc_freq = 0x01a9 }, + { .mbps = 205, .reg = 0x03, .osc_freq = 0x01a9 }, + { .mbps = 220, .reg = 0x13, .osc_freq = 0x01a9 }, + { .mbps = 235, .reg = 0x23, .osc_freq = 0x01a9 }, + { .mbps = 250, .reg = 0x33, .osc_freq = 0x01a9 }, + { .mbps = 275, .reg = 0x04, .osc_freq = 0x01a9 }, + { .mbps = 300, .reg = 0x14, .osc_freq = 0x01a9 }, + { .mbps = 325, .reg = 0x25, .osc_freq = 0x01a9 }, + { .mbps = 350, .reg = 0x35, .osc_freq = 0x01a9 }, + { .mbps = 400, .reg = 0x05, .osc_freq = 0x01a9 }, + { .mbps = 450, .reg = 0x16, .osc_freq = 0x01a9 }, + { .mbps = 500, .reg = 0x26, .osc_freq = 0x01a9 }, + { .mbps = 550, .reg = 0x37, .osc_freq = 0x01a9 }, + { .mbps = 600, .reg = 0x07, .osc_freq = 0x01a9 }, + { .mbps = 650, .reg = 0x18, .osc_freq = 0x01a9 }, + { .mbps = 700, .reg = 0x28, .osc_freq = 0x01a9 }, + { .mbps = 750, .reg = 0x39, .osc_freq = 0x01a9 }, + { .mbps = 800, .reg = 0x09, .osc_freq = 0x01a9 }, + { .mbps = 850, .reg = 0x19, .osc_freq = 0x01a9 }, + { .mbps = 900, .reg = 0x29, .osc_freq = 0x01a9 }, + { .mbps = 950, .reg = 0x3a, .osc_freq = 0x01a9 }, + { .mbps = 1000, .reg = 0x0a, .osc_freq = 0x01a9 }, + { .mbps = 1050, .reg = 0x1a, .osc_freq = 0x01a9 }, + { .mbps = 1100, .reg = 0x2a, .osc_freq = 0x01a9 }, + { .mbps = 1150, .reg = 0x3b, .osc_freq = 0x01a9 }, + { .mbps = 1200, .reg = 0x0b, .osc_freq = 0x01a9 }, + { .mbps = 1250, .reg = 0x1b, .osc_freq = 0x01a9 }, + { .mbps = 1300, .reg = 0x2b, .osc_freq = 0x01a9 }, + { .mbps = 1350, .reg = 0x3c, .osc_freq = 0x01a9 }, + { .mbps = 1400, .reg = 0x0c, .osc_freq = 0x01a9 }, + { .mbps = 1450, .reg = 0x1c, .osc_freq = 0x01a9 }, + { .mbps = 1500, .reg = 0x2c, .osc_freq = 0x01a9 }, + { .mbps = 1550, .reg = 0x3d, .osc_freq = 0x0108 }, + { .mbps = 1600, .reg = 0x0d, .osc_freq = 0x0110 }, + { .mbps = 1650, .reg = 0x1d, .osc_freq = 0x0119 }, + { .mbps = 1700, .reg = 0x2e, .osc_freq = 0x0121 }, + { .mbps = 1750, .reg = 0x3e, .osc_freq = 0x012a }, + { .mbps = 1800, .reg = 0x0e, .osc_freq = 0x0132 }, + { .mbps = 1850, .reg = 0x1e, .osc_freq = 0x013b }, + { .mbps = 1900, .reg = 0x2f, .osc_freq = 0x0143 }, + { .mbps = 1950, .reg = 0x3f, .osc_freq = 0x014c }, + { .mbps = 2000, .reg = 0x0f, .osc_freq = 0x0154 }, + { .mbps = 2050, .reg = 0x40, .osc_freq = 0x015d }, + { .mbps = 2100, .reg = 0x41, .osc_freq = 0x0165 }, + { .mbps = 2150, .reg = 0x42, .osc_freq = 0x016e }, + { .mbps = 2200, .reg = 0x43, .osc_freq = 0x0176 }, + { .mbps = 2250, .reg = 0x44, .osc_freq = 0x017f }, + { .mbps = 2300, .reg = 0x45, .osc_freq = 0x0187 }, + { .mbps = 2350, .reg = 0x46, .osc_freq = 0x0190 }, + { .mbps = 2400, .reg = 0x47, .osc_freq = 0x0198 }, + { .mbps = 2450, .reg = 0x48, .osc_freq = 0x01a1 }, + { .mbps = 2500, .reg = 0x49, .osc_freq = 0x01a9 }, + { /* sentinel */ }, +}; + /* PHY ESC Error Monitor */ #define PHEERM_REG 0x74 @@ -584,13 +681,19 @@ enum rcar_csi2_pads { NR_OF_RCAR_CSI2_PAD, }; +struct rcsi2_register_layout { + unsigned int phtw; + unsigned int phypll; +}; + struct rcar_csi2_info { + const struct rcsi2_register_layout *regs; int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps); int (*phy_post_init)(struct rcar_csi2 *priv); int (*start_receiver)(struct rcar_csi2 *priv, struct v4l2_subdev_state *state); void (*enter_standby)(struct rcar_csi2 *priv); - const struct rcsi2_mbps_reg *hsfreqrange; + const struct rcsi2_mbps_info *hsfreqrange; unsigned int csi0clkfreqrange; unsigned int num_channels; bool clear_ulps; @@ -656,6 +759,70 @@ static void rcsi2_write16(struct rcar_csi2 *priv, unsigned int reg, u16 data) iowrite16(data, priv->base + reg); } +static int rcsi2_phtw_write(struct rcar_csi2 *priv, u8 data, u8 code) +{ + unsigned int timeout; + + rcsi2_write(priv, priv->info->regs->phtw, + PHTW_DWEN | PHTW_TESTDIN_DATA(data) | + PHTW_CWEN | PHTW_TESTDIN_CODE(code)); + + /* Wait for DWEN and CWEN to be cleared by hardware. */ + for (timeout = 0; timeout <= 20; timeout++) { + if (!(rcsi2_read(priv, priv->info->regs->phtw) & (PHTW_DWEN | PHTW_CWEN))) + return 0; + + usleep_range(1000, 2000); + } + + dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n"); + + return -ETIMEDOUT; +} + +static int rcsi2_phtw_write_array(struct rcar_csi2 *priv, + const struct phtw_value *values, + unsigned int size) +{ + int ret; + + for (unsigned int i = 0; i < size; i++) { + ret = rcsi2_phtw_write(priv, values[i].data, values[i].code); + if (ret) + return ret; + } + + return 0; +} + +static const struct rcsi2_mbps_info * +rcsi2_mbps_to_info(struct rcar_csi2 *priv, + const struct rcsi2_mbps_info *infotable, unsigned int mbps) +{ + const struct rcsi2_mbps_info *info; + const struct rcsi2_mbps_info *prev = NULL; + + if (mbps < infotable->mbps) + dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps", + mbps, infotable->mbps); + + for (info = infotable; info->mbps != 0; info++) { + if (info->mbps >= mbps) + break; + prev = info; + } + + if (!info->mbps) { + dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); + return NULL; + } + + if (prev && ((mbps - prev->mbps) <= (info->mbps - mbps))) + info = prev; + + return info; +} + static void rcsi2_enter_standby_gen3(struct rcar_csi2 *priv) { rcsi2_write(priv, PHYCNT_REG, 0); @@ -708,29 +875,13 @@ static int rcsi2_wait_phy_start(struct rcar_csi2 *priv, static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) { - const struct rcsi2_mbps_reg *hsfreq; - const struct rcsi2_mbps_reg *hsfreq_prev = NULL; - - if (mbps < priv->info->hsfreqrange->mbps) - dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps", - mbps, priv->info->hsfreqrange->mbps); - - for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) { - if (hsfreq->mbps >= mbps) - break; - hsfreq_prev = hsfreq; - } + const struct rcsi2_mbps_info *info; - if (!hsfreq->mbps) { - dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); + info = rcsi2_mbps_to_info(priv, priv->info->hsfreqrange, mbps); + if (!info) return -ERANGE; - } - if (hsfreq_prev && - ((mbps - hsfreq_prev->mbps) <= (hsfreq->mbps - mbps))) - hsfreq = hsfreq_prev; - - rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg)); + rcsi2_write(priv, priv->info->regs->phypll, PHYPLL_HSFREQRANGE(info->reg)); return 0; } @@ -1092,11 +1243,11 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv, rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0); /* PHY static setting */ - rcsi2_write(priv, V4H_PHY_EN_REG, BIT(0)); + rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK); rcsi2_write(priv, V4H_FLDC_REG, 0); rcsi2_write(priv, V4H_FLDD_REG, 0); rcsi2_write(priv, V4H_IDIC_REG, 0); - rcsi2_write(priv, V4H_PHY_MODE_REG, BIT(0)); + rcsi2_write(priv, V4H_PHY_MODE_REG, V4H_PHY_MODE_CPHY); rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1); /* Reset CSI2 */ @@ -1131,6 +1282,195 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv, return 0; } +static int rcsi2_d_phy_setting_v4m(struct rcar_csi2 *priv, int data_rate) +{ + unsigned int timeout; + int ret; + + static const struct phtw_value step1[] = { + { .data = 0x00, .code = 0x00 }, + { .data = 0x00, .code = 0x1e }, + }; + + /* Shutdown and reset PHY. */ + rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0)); + rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0)); + + /* Start internal calibration (POR). */ + ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1)); + if (ret) + return ret; + + /* Wait for POR to complete. */ + for (timeout = 10; timeout > 0; timeout--) { + if ((rcsi2_read(priv, V4M_PHTR_REG) & 0xf0000) == 0x70000) + break; + usleep_range(1000, 2000); + } + + if (!timeout) { + dev_err(priv->dev, "D-PHY calibration failed\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int rcsi2_set_osc_freq(struct rcar_csi2 *priv, unsigned int mbps) +{ + const struct rcsi2_mbps_info *info; + struct phtw_value steps[] = { + { .data = 0x00, .code = 0x00 }, + { .code = 0xe2 }, /* Data filled in below. */ + { .code = 0xe3 }, /* Data filled in below. */ + { .data = 0x01, .code = 0xe4 }, + }; + + info = rcsi2_mbps_to_info(priv, priv->info->hsfreqrange, mbps); + if (!info) + return -ERANGE; + + /* Fill in data for command. */ + steps[1].data = (info->osc_freq & 0x00ff) >> 0; + steps[2].data = (info->osc_freq & 0x0f00) >> 8; + + return rcsi2_phtw_write_array(priv, steps, ARRAY_SIZE(steps)); +} + +static int rcsi2_init_common_v4m(struct rcar_csi2 *priv, unsigned int mbps) +{ + int ret; + + static const struct phtw_value step1[] = { + { .data = 0x00, .code = 0x00 }, + { .data = 0x3c, .code = 0x08 }, + }; + + static const struct phtw_value step2[] = { + { .data = 0x00, .code = 0x00 }, + { .data = 0x80, .code = 0xe0 }, + { .data = 0x01, .code = 0xe1 }, + { .data = 0x06, .code = 0x00 }, + { .data = 0x0f, .code = 0x11 }, + { .data = 0x08, .code = 0x00 }, + { .data = 0x0f, .code = 0x11 }, + { .data = 0x0a, .code = 0x00 }, + { .data = 0x0f, .code = 0x11 }, + { .data = 0x0c, .code = 0x00 }, + { .data = 0x0f, .code = 0x11 }, + { .data = 0x01, .code = 0x00 }, + { .data = 0x31, .code = 0xaa }, + { .data = 0x05, .code = 0x00 }, + { .data = 0x05, .code = 0x09 }, + { .data = 0x07, .code = 0x00 }, + { .data = 0x05, .code = 0x09 }, + { .data = 0x09, .code = 0x00 }, + { .data = 0x05, .code = 0x09 }, + { .data = 0x0b, .code = 0x00 }, + { .data = 0x05, .code = 0x09 }, + }; + + if (priv->info->hsfreqrange) { + ret = rcsi2_set_phypll(priv, mbps); + if (ret) + return ret; + + ret = rcsi2_set_osc_freq(priv, mbps); + if (ret) + return ret; + } + + if (mbps <= 1500) { + ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1)); + if (ret) + return ret; + } + + if (priv->info->csi0clkfreqrange) + rcsi2_write(priv, V4M_CSI0CLKFCPR_REG, + CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange)); + + rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK | + V4H_PHY_EN_ENABLE_0 | V4H_PHY_EN_ENABLE_1 | + V4H_PHY_EN_ENABLE_2 | V4H_PHY_EN_ENABLE_3); + + if (mbps > 1500) { + ret = rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2)); + if (ret) + return ret; + } + + return ret; +} + +static int rcsi2_start_receiver_v4m(struct rcar_csi2 *priv, + struct v4l2_subdev_state *state) +{ + const struct rcar_csi2_format *format; + const struct v4l2_mbus_framefmt *fmt; + unsigned int lanes; + int mbps; + int ret; + + /* Calculate parameters */ + fmt = v4l2_subdev_state_get_format(state, RCAR_CSI2_SINK); + format = rcsi2_code_to_fmt(fmt->code); + if (!format) + return -EINVAL; + + ret = rcsi2_get_active_lanes(priv, &lanes); + if (ret) + return ret; + + mbps = rcsi2_calc_mbps(priv, format->bpp, lanes); + if (mbps < 0) + return mbps; + + /* Reset LINK and PHY */ + rcsi2_write(priv, V4H_CSI2_RESETN_REG, 0); + rcsi2_write(priv, V4H_DPHY_RSTZ_REG, 0); + rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0); + rcsi2_write(priv, V4M_PHTC_REG, PHTC_TESTCLR); + + /* PHY static setting */ + rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK); + rcsi2_write(priv, V4H_FLDC_REG, 0); + rcsi2_write(priv, V4H_FLDD_REG, 0); + rcsi2_write(priv, V4H_IDIC_REG, 0); + rcsi2_write(priv, V4H_PHY_MODE_REG, V4H_PHY_MODE_DPHY); + rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1); + + rcsi2_write(priv, V4M_FRXM_REG, + V4M_FRXM_FORCERXMODE_0 | V4M_FRXM_FORCERXMODE_1 | + V4M_FRXM_FORCERXMODE_2 | V4M_FRXM_FORCERXMODE_3); + rcsi2_write(priv, V4M_OVR1_REG, + V4M_OVR1_FORCERXMODE_0 | V4M_OVR1_FORCERXMODE_1 | + V4M_OVR1_FORCERXMODE_2 | V4M_OVR1_FORCERXMODE_3); + + /* Reset CSI2 */ + rcsi2_write(priv, V4M_PHTC_REG, 0); + rcsi2_write(priv, V4H_CSI2_RESETN_REG, BIT(0)); + + /* Common settings */ + ret = rcsi2_init_common_v4m(priv, mbps); + if (ret) + return ret; + + /* D-PHY settings */ + ret = rcsi2_d_phy_setting_v4m(priv, mbps); + if (ret) + return ret; + + rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_STOPSTATE_0 | + V4H_ST_PHYST_ST_STOPSTATE_1 | + V4H_ST_PHYST_ST_STOPSTATE_2 | + V4H_ST_PHYST_ST_STOPSTATE_3); + + rcsi2_write(priv, V4M_FRXM_REG, 0); + + return 0; +} + static int rcsi2_start(struct rcar_csi2 *priv, struct v4l2_subdev_state *state) { int ret; @@ -1451,64 +1791,16 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv) * NOTE: Magic values are from the datasheet and lack documentation. */ -static int rcsi2_phtw_write(struct rcar_csi2 *priv, u16 data, u16 code) -{ - unsigned int timeout; - - rcsi2_write(priv, PHTW_REG, - PHTW_DWEN | PHTW_TESTDIN_DATA(data) | - PHTW_CWEN | PHTW_TESTDIN_CODE(code)); - - /* Wait for DWEN and CWEN to be cleared by hardware. */ - for (timeout = 0; timeout <= 20; timeout++) { - if (!(rcsi2_read(priv, PHTW_REG) & (PHTW_DWEN | PHTW_CWEN))) - return 0; - - usleep_range(1000, 2000); - } - - dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n"); - - return -ETIMEDOUT; -} - -static int rcsi2_phtw_write_array(struct rcar_csi2 *priv, - const struct phtw_value *values) -{ - const struct phtw_value *value; - int ret; - - for (value = values; value->data || value->code; value++) { - ret = rcsi2_phtw_write(priv, value->data, value->code); - if (ret) - return ret; - } - - return 0; -} - static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps, - const struct rcsi2_mbps_reg *values, u16 code) + const struct rcsi2_mbps_info *values, u8 code) { - const struct rcsi2_mbps_reg *value; - const struct rcsi2_mbps_reg *prev_value = NULL; - - for (value = values; value->mbps; value++) { - if (value->mbps >= mbps) - break; - prev_value = value; - } + const struct rcsi2_mbps_info *info; - if (prev_value && - ((mbps - prev_value->mbps) <= (value->mbps - mbps))) - value = prev_value; - - if (!value->mbps) { - dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); + info = rcsi2_mbps_to_info(priv, values, mbps); + if (!info) return -ERANGE; - } - return rcsi2_phtw_write(priv, value->reg, code); + return rcsi2_phtw_write(priv, info->reg, code); } static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, @@ -1520,7 +1812,6 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, { .data = 0x11, .code = 0xe4 }, { .data = 0x01, .code = 0xe5 }, { .data = 0x10, .code = 0x04 }, - { /* sentinel */ }, }; static const struct phtw_value step2[] = { @@ -1529,12 +1820,11 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, { .data = 0x4b, .code = 0xac }, { .data = 0x03, .code = 0x00 }, { .data = 0x80, .code = 0x07 }, - { /* sentinel */ }, }; int ret; - ret = rcsi2_phtw_write_array(priv, step1); + ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1)); if (ret) return ret; @@ -1549,7 +1839,7 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, return ret; } - return rcsi2_phtw_write_array(priv, step2); + return rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2)); } static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) @@ -1575,10 +1865,9 @@ static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv) { .data = 0xee, .code = 0x54 }, { .data = 0xee, .code = 0x84 }, { .data = 0xee, .code = 0x94 }, - { /* sentinel */ }, }; - return rcsi2_phtw_write_array(priv, step1); + return rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1)); } static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, @@ -1587,20 +1876,17 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, /* In case of 1500Mbps or less */ static const struct phtw_value step1[] = { { .data = 0xcc, .code = 0xe2 }, - { /* sentinel */ }, }; static const struct phtw_value step2[] = { { .data = 0x01, .code = 0xe3 }, { .data = 0x11, .code = 0xe4 }, { .data = 0x01, .code = 0xe5 }, - { /* sentinel */ }, }; /* In case of 1500Mbps or less */ static const struct phtw_value step3[] = { { .data = 0x38, .code = 0x08 }, - { /* sentinel */ }, }; static const struct phtw_value step4[] = { @@ -1608,29 +1894,28 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, { .data = 0x4b, .code = 0xac }, { .data = 0x03, .code = 0x00 }, { .data = 0x80, .code = 0x07 }, - { /* sentinel */ }, }; int ret; if (mbps != 0 && mbps <= 1500) - ret = rcsi2_phtw_write_array(priv, step1); + ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1)); else ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3u, 0xe2); if (ret) return ret; - ret = rcsi2_phtw_write_array(priv, step2); + ret = rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2)); if (ret) return ret; if (mbps != 0 && mbps <= 1500) { - ret = rcsi2_phtw_write_array(priv, step3); + ret = rcsi2_phtw_write_array(priv, step3, ARRAY_SIZE(step3)); if (ret) return ret; } - ret = rcsi2_phtw_write_array(priv, step4); + ret = rcsi2_phtw_write_array(priv, step4, ARRAY_SIZE(step4)); if (ret) return ret; @@ -1714,7 +1999,13 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv, return PTR_ERR_OR_ZERO(priv->rstc); } +static const struct rcsi2_register_layout rcsi2_registers_gen3 = { + .phtw = PHTW_REG, + .phypll = PHYPLL_REG, +}; + static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, @@ -1726,6 +2017,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_h3es2, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, @@ -1737,6 +2029,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { + .regs = &rcsi2_registers_gen3, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, .hsfreqrange = hsfreqrange_m3w, @@ -1745,6 +2038,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = { + .regs = &rcsi2_registers_gen3, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, .hsfreqrange = hsfreqrange_m3w, @@ -1753,6 +2047,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, @@ -1764,6 +2059,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_v3m_e3, .phy_post_init = rcsi2_phy_post_init_v3m_e3, .start_receiver = rcsi2_start_receiver_gen3, @@ -1773,6 +2069,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, @@ -1783,6 +2080,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_v3m_e3, .phy_post_init = rcsi2_phy_post_init_v3m_e3, .start_receiver = rcsi2_start_receiver_gen3, @@ -1792,6 +2090,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_v3u, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, @@ -1803,11 +2102,26 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a779g0 = { + .regs = &rcsi2_registers_gen3, .start_receiver = rcsi2_start_receiver_v4h, .use_isp = true, .support_cphy = true, }; +static const struct rcsi2_register_layout rcsi2_registers_v4m = { + .phtw = V4M_PHTW_REG, + .phypll = V4M_PHYPLL_REG, +}; + +static const struct rcar_csi2_info rcar_csi2_info_r8a779h0 = { + .regs = &rcsi2_registers_v4m, + .start_receiver = rcsi2_start_receiver_v4m, + .hsfreqrange = hsfreqrange_v4m, + .csi0clkfreqrange = 0x0c, + .use_isp = true, + .support_dphy = true, +}; + static const struct of_device_id rcar_csi2_of_table[] = { { .compatible = "renesas,r8a774a1-csi2", @@ -1861,6 +2175,10 @@ static const struct of_device_id rcar_csi2_of_table[] = { .compatible = "renesas,r8a779g0-csi2", .data = &rcar_csi2_info_r8a779g0, }, + { + .compatible = "renesas,r8a779h0-csi2", + .data = &rcar_csi2_info_r8a779h0, + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, rcar_csi2_of_table); @@ -1974,7 +2292,7 @@ static void rcsi2_remove(struct platform_device *pdev) } static struct platform_driver rcar_csi2_pdrv = { - .remove_new = rcsi2_remove, + .remove = rcsi2_remove, .probe = rcsi2_probe, .driver = { .name = "rcar-csi2", diff --git a/drivers/media/platform/renesas/rcar-fcp.c b/drivers/media/platform/renesas/rcar-fcp.c index bcef7b87da7c..cee9bbce4e3a 100644 --- a/drivers/media/platform/renesas/rcar-fcp.c +++ b/drivers/media/platform/renesas/rcar-fcp.c @@ -164,7 +164,7 @@ MODULE_DEVICE_TABLE(of, rcar_fcp_of_match); static struct platform_driver rcar_fcp_platform_driver = { .probe = rcar_fcp_probe, - .remove_new = rcar_fcp_remove, + .remove = rcar_fcp_remove, .driver = { .name = "rcar-fcp", .of_match_table = rcar_fcp_of_match, diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c index 4512ac338ca5..c515278e3be5 100644 --- a/drivers/media/platform/renesas/rcar-isp.c +++ b/drivers/media/platform/renesas/rcar-isp.c @@ -431,7 +431,9 @@ static int risp_probe_resources(struct rcar_isp *isp, static const struct of_device_id risp_of_id_table[] = { { .compatible = "renesas,r8a779a0-isp" }, { .compatible = "renesas,r8a779g0-isp" }, - { /* sentinel */ }, + /* Keep above for compatibility with old DTB files. */ + { .compatible = "renesas,rcar-gen4-isp" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, risp_of_id_table); @@ -522,7 +524,7 @@ static struct platform_driver rcar_isp_driver = { .of_match_table = risp_of_id_table, }, .probe = risp_probe, - .remove_new = risp_remove, + .remove = risp_remove, }; module_platform_driver(rcar_isp_driver); diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c index 695d884a22d1..ddfb18e6e7a4 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c @@ -1279,6 +1279,7 @@ static const struct rvin_info rcar_info_gen4 = { .use_mc = true, .use_isp = true, .nv12 = true, + .raw10 = true, .max_width = 4096, .max_height = 4096, }; @@ -1443,7 +1444,7 @@ static struct platform_driver rcar_vin_driver = { .of_match_table = rvin_of_id_table, }, .probe = rcar_vin_probe, - .remove_new = rcar_vin_remove, + .remove = rcar_vin_remove, }; module_platform_driver(rcar_vin_driver); diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index 21d5b2815e86..8773998101ff 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -123,7 +123,9 @@ /* Video n Data Mode Register bits */ #define VNDMR_A8BIT(n) (((n) & 0xff) << 24) #define VNDMR_A8BIT_MASK (0xff << 24) +#define VNDMR_RMODE_RAW10 (2 << 19) #define VNDMR_YMODE_Y8 (1 << 12) +#define VNDMR_YC_THR (1 << 11) #define VNDMR_EXRGB (1 << 8) #define VNDMR_BPSM (1 << 4) #define VNDMR_ABIT (1 << 2) @@ -790,6 +792,12 @@ static int rvin_setup(struct rvin_dev *vin) case MEDIA_BUS_FMT_Y8_1X8: vnmc |= VNMC_INF_RAW8; break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + vnmc |= VNMC_INF_RGB666; + break; default: break; } @@ -898,6 +906,12 @@ static int rvin_setup(struct rvin_dev *vin) dmr = 0; } break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + dmr = VNDMR_RMODE_RAW10 | VNDMR_YC_THR; + break; default: vin_err(vin, "Invalid pixelformat (0x%x)\n", vin->format.pixelformat); @@ -1280,6 +1294,22 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd, if (vin->format.pixelformat != V4L2_PIX_FMT_GREY) return -EPIPE; break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR10) + return -EPIPE; + break; + case MEDIA_BUS_FMT_SGBRG10_1X10: + if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG10) + return -EPIPE; + break; + case MEDIA_BUS_FMT_SGRBG10_1X10: + if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG10) + return -EPIPE; + break; + case MEDIA_BUS_FMT_SRGGB10_1X10: + if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB10) + return -EPIPE; + break; default: return -EPIPE; } @@ -1529,8 +1559,6 @@ static const struct vb2_ops rvin_qops = { .buf_queue = rvin_buffer_queue, .start_streaming = rvin_start_streaming_vq, .stop_streaming = rvin_stop_streaming_vq, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; void rvin_dma_unregister(struct rvin_dev *vin) diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c index bb4b07bed28d..756fdfdbce61 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c @@ -86,6 +86,22 @@ static const struct rvin_video_format rvin_formats[] = { .fourcc = V4L2_PIX_FMT_GREY, .bpp = 1, }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .bpp = 4, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .bpp = 4, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .bpp = 4, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .bpp = 4, + }, }; const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, @@ -106,6 +122,13 @@ const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, if (!vin->info->nv12 || !(BIT(vin->id) & 0x3333)) return NULL; break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + if (!vin->info->raw10) + return NULL; + break; default: break; } @@ -407,6 +430,26 @@ static int rvin_enum_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; f->pixelformat = V4L2_PIX_FMT_SRGGB8; return 0; + case MEDIA_BUS_FMT_SBGGR10_1X10: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_SBGGR10; + return 0; + case MEDIA_BUS_FMT_SGBRG10_1X10: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_SGBRG10; + return 0; + case MEDIA_BUS_FMT_SGRBG10_1X10: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_SGRBG10; + return 0; + case MEDIA_BUS_FMT_SRGGB10_1X10: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_SRGGB10; + return 0; default: return -EINVAL; } diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h index 997a66318a29..f87d4bc9e53e 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h @@ -151,7 +151,8 @@ struct rvin_group_route { * @model: VIN model * @use_mc: use media controller instead of controlling subdevice * @use_isp: the VIN is connected to the ISP and not to the CSI-2 - * @nv12: support outputing NV12 pixel format + * @nv12: support outputting NV12 pixel format + * @raw10: support outputting RAW10 pixel format * @max_width: max input width the VIN supports * @max_height: max input height the VIN supports * @routes: list of possible routes from the CSI-2 recivers to @@ -163,6 +164,7 @@ struct rvin_info { bool use_mc; bool use_isp; bool nv12; + bool raw10; unsigned int max_width; unsigned int max_height; diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c index f21d05054341..fc8b6bbef793 100644 --- a/drivers/media/platform/renesas/rcar_drif.c +++ b/drivers/media/platform/renesas/rcar_drif.c @@ -861,8 +861,6 @@ static const struct vb2_ops rcar_drif_vb2_ops = { .buf_queue = rcar_drif_buf_queue, .start_streaming = rcar_drif_start_streaming, .stop_streaming = rcar_drif_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int rcar_drif_querycap(struct file *file, void *fh, @@ -1071,7 +1069,6 @@ static int rcar_drif_sdr_register(struct rcar_drif_sdr *sdr) sdr->vdev->release = video_device_release; sdr->vdev->lock = &sdr->v4l2_mutex; sdr->vdev->queue = &sdr->vb_queue; - sdr->vdev->queue->lock = &sdr->vb_queue_mutex; sdr->vdev->ctrl_handler = &sdr->ctrl_hdl; sdr->vdev->v4l2_dev = &sdr->v4l2_dev; sdr->vdev->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER | @@ -1316,6 +1313,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr) sdr->vb_queue.ops = &rcar_drif_vb2_ops; sdr->vb_queue.mem_ops = &vb2_vmalloc_memops; sdr->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + sdr->vb_queue.lock = &sdr->vb_queue_mutex; /* Init videobuf2 queue */ ret = vb2_queue_init(&sdr->vb_queue); @@ -1475,7 +1473,7 @@ static struct platform_driver rcar_drif_driver = { .pm = &rcar_drif_pm_ops, }, .probe = rcar_drif_probe, - .remove_new = rcar_drif_remove, + .remove = rcar_drif_remove, }; module_platform_driver(rcar_drif_driver); diff --git a/drivers/media/platform/renesas/rcar_fdp1.c b/drivers/media/platform/renesas/rcar_fdp1.c index a2565b269f3b..5d453a7a8988 100644 --- a/drivers/media/platform/renesas/rcar_fdp1.c +++ b/drivers/media/platform/renesas/rcar_fdp1.c @@ -2032,8 +2032,6 @@ static const struct vb2_ops fdp1_qops = { .buf_queue = fdp1_buf_queue, .start_streaming = fdp1_start_streaming, .stop_streaming = fdp1_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -2444,7 +2442,7 @@ MODULE_DEVICE_TABLE(of, fdp1_dt_ids); static struct platform_driver fdp1_pdrv = { .probe = fdp1_probe, - .remove_new = fdp1_remove, + .remove = fdp1_remove, .driver = { .name = DRIVER_NAME, .of_match_table = fdp1_dt_ids, diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c index e50fe7525a73..81038df71bb5 100644 --- a/drivers/media/platform/renesas/rcar_jpu.c +++ b/drivers/media/platform/renesas/rcar_jpu.c @@ -1171,8 +1171,6 @@ static const struct vb2_ops jpu_qops = { .buf_finish = jpu_buf_finish, .start_streaming = jpu_start_streaming, .stop_streaming = jpu_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int jpu_queue_init(void *priv, struct vb2_queue *src_vq, @@ -1736,7 +1734,7 @@ static const struct dev_pm_ops jpu_pm_ops = { static struct platform_driver jpu_driver = { .probe = jpu_probe, - .remove_new = jpu_remove, + .remove = jpu_remove, .driver = { .of_match_table = jpu_dt_ids, .name = DRV_NAME, diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c index 167760276796..8cceafe491b1 100644 --- a/drivers/media/platform/renesas/renesas-ceu.c +++ b/drivers/media/platform/renesas/renesas-ceu.c @@ -761,8 +761,6 @@ static const struct vb2_ops ceu_vb2_ops = { .queue_setup = ceu_vb2_setup, .buf_queue = ceu_vb2_queue, .buf_prepare = ceu_vb2_prepare, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = ceu_start_streaming, .stop_streaming = ceu_stop_streaming, }; @@ -1723,7 +1721,7 @@ static struct platform_driver ceu_driver = { .of_match_table = of_match_ptr(ceu_of_match), }, .probe = ceu_probe, - .remove_new = ceu_remove, + .remove = ceu_remove, }; module_platform_driver(ceu_driver); diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c index 280efd2a8185..89be584a4988 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c @@ -72,7 +72,6 @@ static int rzg2l_cru_group_notify_complete(struct v4l2_async_notifier *notifier) source->name, sink->name); return ret; } - cru->csi.channel = 0; cru->ip.remote = cru->csi.subdev; /* Create media device link between CRU IP <-> CRU OUTPUT */ @@ -209,7 +208,7 @@ static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru) const struct of_device_id *match; int ret; - cru->pad.flags = MEDIA_PAD_FL_SINK; + cru->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; ret = media_entity_pads_init(&cru->vdev.entity, 1, &cru->pad); if (ret) return ret; @@ -242,7 +241,7 @@ static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru) static int rzg2l_cru_probe(struct platform_device *pdev) { struct rzg2l_cru_dev *cru; - int ret; + int irq, ret; cru = devm_kzalloc(&pdev->dev, sizeof(*cru), GFP_KERNEL); if (!cru) @@ -270,9 +269,14 @@ static int rzg2l_cru_probe(struct platform_device *pdev) cru->dev = &pdev->dev; cru->info = of_device_get_match_data(&pdev->dev); - cru->image_conv_irq = platform_get_irq(pdev, 0); - if (cru->image_conv_irq < 0) - return cru->image_conv_irq; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(&pdev->dev, irq, rzg2l_cru_irq, 0, + KBUILD_MODNAME, cru); + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to request irq\n"); platform_set_drvdata(pdev, cru); @@ -325,7 +329,7 @@ static struct platform_driver rzg2l_cru_driver = { .of_match_table = rzg2l_cru_of_id_table, }, .probe = rzg2l_cru_probe, - .remove_new = rzg2l_cru_remove, + .remove = rzg2l_cru_remove, }; module_platform_driver(rzg2l_cru_driver); diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h new file mode 100644 index 000000000000..1c9f22118a5d --- /dev/null +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * rzg2l-cru-regs.h--RZ/G2L (and alike SoCs) CRU Registers Definitions + * + * Copyright (C) 2024 Renesas Electronics Corp. + */ + +#ifndef __RZG2L_CRU_REGS_H__ +#define __RZG2L_CRU_REGS_H__ + +/* HW CRU Registers Definition */ + +/* CRU Control Register */ +#define CRUnCTRL 0x0 +#define CRUnCTRL_VINSEL(x) ((x) << 0) + +/* CRU Interrupt Enable Register */ +#define CRUnIE 0x4 +#define CRUnIE_EFE BIT(17) + +/* CRU Interrupt Status Register */ +#define CRUnINTS 0x8 +#define CRUnINTS_SFS BIT(16) + +/* CRU Reset Register */ +#define CRUnRST 0xc +#define CRUnRST_VRESETN BIT(0) + +/* Memory Bank Base Address (Lower) Register for CRU Image Data */ +#define AMnMBxADDRL(x) (0x100 + ((x) * 8)) + +/* Memory Bank Base Address (Higher) Register for CRU Image Data */ +#define AMnMBxADDRH(x) (0x104 + ((x) * 8)) + +/* Memory Bank Enable Register for CRU Image Data */ +#define AMnMBVALID 0x148 +#define AMnMBVALID_MBVALID(x) GENMASK(x, 0) + +/* Memory Bank Status Register for CRU Image Data */ +#define AMnMBS 0x14c +#define AMnMBS_MBSTS 0x7 + +/* AXI Master Transfer Setting Register for CRU Image Data */ +#define AMnAXIATTR 0x158 +#define AMnAXIATTR_AXILEN_MASK GENMASK(3, 0) +#define AMnAXIATTR_AXILEN (0xf) + +/* AXI Master FIFO Pointer Register for CRU Image Data */ +#define AMnFIFOPNTR 0x168 +#define AMnFIFOPNTR_FIFOWPNTR GENMASK(7, 0) +#define AMnFIFOPNTR_FIFORPNTR_Y GENMASK(23, 16) + +/* AXI Master Transfer Stop Register for CRU Image Data */ +#define AMnAXISTP 0x174 +#define AMnAXISTP_AXI_STOP BIT(0) + +/* AXI Master Transfer Stop Status Register for CRU Image Data */ +#define AMnAXISTPACK 0x178 +#define AMnAXISTPACK_AXI_STOP_ACK BIT(0) + +/* CRU Image Processing Enable Register */ +#define ICnEN 0x200 +#define ICnEN_ICEN BIT(0) + +/* CRU Image Processing Main Control Register */ +#define ICnMC 0x208 +#define ICnMC_CSCTHR BIT(5) +#define ICnMC_INF(x) ((x) << 16) +#define ICnMC_VCSEL(x) ((x) << 22) +#define ICnMC_INF_MASK GENMASK(21, 16) + +/* CRU Module Status Register */ +#define ICnMS 0x254 +#define ICnMS_IA BIT(2) + +/* CRU Data Output Mode Register */ +#define ICnDMR 0x26c +#define ICnDMR_YCMODE_UYVY (1 << 4) + +#endif /* __RZG2L_CRU_REGS_H__ */ diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h index a5a99b004322..8b898ce05b84 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h @@ -8,6 +8,7 @@ #ifndef __RZG2L_CRU__ #define __RZG2L_CRU__ +#include <linux/irqreturn.h> #include <linux/reset.h> #include <media/v4l2-async.h> @@ -30,6 +31,11 @@ #define RZG2L_CRU_MIN_INPUT_HEIGHT 240 #define RZG2L_CRU_MAX_INPUT_HEIGHT 4095 +enum rzg2l_csi2_pads { + RZG2L_CRU_IP_SINK = 0, + RZG2L_CRU_IP_SOURCE, +}; + /** * enum rzg2l_cru_dma_state - DMA states * @RZG2L_CRU_DMA_STOPPED: No operation in progress @@ -47,7 +53,6 @@ enum rzg2l_cru_dma_state { struct rzg2l_cru_csi { struct v4l2_async_connection *asd; struct v4l2_subdev *subdev; - u32 channel; }; struct rzg2l_cru_ip { @@ -58,6 +63,24 @@ struct rzg2l_cru_ip { }; /** + * struct rzg2l_cru_ip_format - CRU IP format + * @code: Media bus code + * @datatype: MIPI CSI2 data type + * @format: 4CC format identifier (V4L2_PIX_FMT_*) + * @icndmr: ICnDMR register value + * @bpp: bytes per pixel + * @yuv: Flag to indicate whether the format is YUV-based. + */ +struct rzg2l_cru_ip_format { + u32 code; + u32 datatype; + u32 format; + u32 icndmr; + u8 bpp; + bool yuv; +}; + +/** * struct rzg2l_cru_dev - Renesas CRU device structure * @dev: (OF) device * @base: device I/O register space remapped to virtual memory @@ -68,8 +91,6 @@ struct rzg2l_cru_ip { * * @vclk: CRU Main clock * - * @image_conv_irq: Holds image conversion interrupt number - * * @vdev: V4L2 video device associated with CRU * @v4l2_dev: V4L2 device * @num_buf: Holds the current number of buffers enabled @@ -105,8 +126,6 @@ struct rzg2l_cru_dev { struct clk *vclk; - int image_conv_irq; - struct video_device vdev; struct v4l2_device v4l2_dev; u8 num_buf; @@ -141,6 +160,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru); int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru); void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru); +irqreturn_t rzg2l_cru_irq(int irq, void *data); const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format); @@ -148,4 +168,8 @@ int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru); void rzg2l_cru_ip_subdev_unregister(struct rzg2l_cru_dev *cru); struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru); +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code); +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format); +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index); + #endif diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c index c7fdee347ac8..881e910dce02 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c @@ -183,12 +183,15 @@ static const struct rzg2l_csi2_timings rzg2l_csi2_global_timings[] = { struct rzg2l_csi2_format { u32 code; - unsigned int datatype; unsigned int bpp; }; static const struct rzg2l_csi2_format rzg2l_csi2_formats[] = { - { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 }, + { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16 }, + { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, }, }; static inline struct rzg2l_csi2 *sd_to_csi2(struct v4l2_subdev *sd) @@ -574,6 +577,9 @@ static int rzg2l_csi2_enum_frame_size(struct v4l2_subdev *sd, if (fse->index != 0) return -EINVAL; + if (!rzg2l_csi2_code_to_fmt(fse->code)) + return -EINVAL; + fse->min_width = RZG2L_CSI2_MIN_WIDTH; fse->min_height = RZG2L_CSI2_MIN_HEIGHT; fse->max_width = RZG2L_CSI2_MAX_WIDTH; @@ -582,6 +588,25 @@ static int rzg2l_csi2_enum_frame_size(struct v4l2_subdev *sd, return 0; } +static int rzg2l_csi2_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct rzg2l_csi2 *csi2 = sd_to_csi2(sd); + struct media_pad *remote_pad; + + if (!csi2->remote_source) + return -ENODEV; + + remote_pad = media_pad_remote_pad_unique(&csi2->pads[RZG2L_CSI2_SINK]); + if (IS_ERR(remote_pad)) { + dev_err(csi2->dev, "can't get source pad of %s (%ld)\n", + csi2->remote_source->name, PTR_ERR(remote_pad)); + return PTR_ERR(remote_pad); + } + return v4l2_subdev_call(csi2->remote_source, pad, get_frame_desc, + remote_pad->index, fd); +} + static const struct v4l2_subdev_video_ops rzg2l_csi2_video_ops = { .s_stream = rzg2l_csi2_s_stream, .pre_streamon = rzg2l_csi2_pre_streamon, @@ -593,6 +618,7 @@ static const struct v4l2_subdev_pad_ops rzg2l_csi2_pad_ops = { .enum_frame_size = rzg2l_csi2_enum_frame_size, .set_fmt = rzg2l_csi2_set_format, .get_fmt = v4l2_subdev_get_fmt, + .get_frame_desc = rzg2l_csi2_get_frame_desc, }; static const struct v4l2_subdev_ops rzg2l_csi2_subdev_ops = { @@ -795,14 +821,17 @@ static int rzg2l_csi2_probe(struct platform_device *pdev) csi2->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; csi2->subdev.entity.ops = &rzg2l_csi2_entity_ops; - csi2->pads[RZG2L_CSI2_SINK].flags = MEDIA_PAD_FL_SINK; + csi2->pads[RZG2L_CSI2_SINK].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; /* * TODO: RZ/G2L CSI2 supports 4 virtual channels, as virtual * channels should be implemented by streams API which is under * development lets hardcode to VC0 for now. */ - csi2->pads[RZG2L_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&csi2->subdev.entity, 2, csi2->pads); + csi2->pads[RZG2L_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE | + MEDIA_PAD_FL_MUST_CONNECT; + ret = media_entity_pads_init(&csi2->subdev.entity, ARRAY_SIZE(csi2->pads), + csi2->pads); if (ret) goto error_pm; @@ -868,7 +897,7 @@ static const struct of_device_id rzg2l_csi2_of_table[] = { MODULE_DEVICE_TABLE(of, rzg2l_csi2_of_table); static struct platform_driver rzg2l_csi2_pdrv = { - .remove_new = rzg2l_csi2_remove, + .remove = rzg2l_csi2_remove, .probe = rzg2l_csi2_probe, .driver = { .name = "rzg2l-csi2", diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c index ac8ebae4ed07..76a2b451f1da 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c @@ -6,24 +6,55 @@ */ #include <linux/delay.h> -#include "rzg2l-cru.h" +#include <media/mipi-csi2.h> -struct rzg2l_cru_ip_format { - u32 code; - unsigned int datatype; - unsigned int bpp; -}; +#include "rzg2l-cru.h" +#include "rzg2l-cru-regs.h" static const struct rzg2l_cru_ip_format rzg2l_cru_ip_formats[] = { - { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 }, -}; - -enum rzg2l_csi2_pads { - RZG2L_CRU_IP_SINK = 0, - RZG2L_CRU_IP_SOURCE, + { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .datatype = MIPI_CSI2_DT_YUV422_8B, + .format = V4L2_PIX_FMT_UYVY, + .bpp = 2, + .icndmr = ICnDMR_YCMODE_UYVY, + .yuv = true, + }, + { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .format = V4L2_PIX_FMT_SBGGR8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 1, + .icndmr = 0, + .yuv = false, + }, + { + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .format = V4L2_PIX_FMT_SGBRG8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 1, + .icndmr = 0, + .yuv = false, + }, + { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .format = V4L2_PIX_FMT_SGRBG8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 1, + .icndmr = 0, + .yuv = false, + }, + { + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .format = V4L2_PIX_FMT_SRGGB8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 1, + .icndmr = 0, + .yuv = false, + }, }; -static const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code) +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code) { unsigned int i; @@ -34,6 +65,26 @@ static const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int c return NULL; } +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) { + if (rzg2l_cru_ip_formats[i].format == format) + return &rzg2l_cru_ip_formats[i]; + } + + return NULL; +} + +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index) +{ + if (index >= ARRAY_SIZE(rzg2l_cru_ip_formats)) + return NULL; + + return &rzg2l_cru_ip_formats[index]; +} + struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru) { struct v4l2_subdev_state *state; @@ -149,7 +200,7 @@ static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd, if (fse->index != 0) return -EINVAL; - if (fse->code != MEDIA_BUS_FMT_UYVY8_1X16) + if (!rzg2l_cru_ip_code_to_fmt(fse->code)) return -EINVAL; fse->min_width = RZG2L_CRU_MIN_INPUT_WIDTH; @@ -217,8 +268,10 @@ int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru) ip->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; ip->subdev.entity.ops = &rzg2l_cru_ip_entity_ops; - ip->pads[0].flags = MEDIA_PAD_FL_SINK; - ip->pads[1].flags = MEDIA_PAD_FL_SOURCE; + ip->pads[RZG2L_CRU_IP_SINK].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; + ip->pads[RZG2L_CRU_IP_SOURCE].flags = MEDIA_PAD_FL_SOURCE | + MEDIA_PAD_FL_MUST_CONNECT; ret = media_entity_pads_init(&ip->subdev.entity, 2, ip->pads); if (ret) diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c index b16b8af6e8f8..17a1af507a27 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c @@ -15,75 +15,12 @@ #include <linux/delay.h> #include <linux/pm_runtime.h> +#include <media/mipi-csi2.h> #include <media/v4l2-ioctl.h> #include <media/videobuf2-dma-contig.h> #include "rzg2l-cru.h" - -/* HW CRU Registers Definition */ - -/* CRU Control Register */ -#define CRUnCTRL 0x0 -#define CRUnCTRL_VINSEL(x) ((x) << 0) - -/* CRU Interrupt Enable Register */ -#define CRUnIE 0x4 -#define CRUnIE_EFE BIT(17) - -/* CRU Interrupt Status Register */ -#define CRUnINTS 0x8 -#define CRUnINTS_SFS BIT(16) - -/* CRU Reset Register */ -#define CRUnRST 0xc -#define CRUnRST_VRESETN BIT(0) - -/* Memory Bank Base Address (Lower) Register for CRU Image Data */ -#define AMnMBxADDRL(x) (0x100 + ((x) * 8)) - -/* Memory Bank Base Address (Higher) Register for CRU Image Data */ -#define AMnMBxADDRH(x) (0x104 + ((x) * 8)) - -/* Memory Bank Enable Register for CRU Image Data */ -#define AMnMBVALID 0x148 -#define AMnMBVALID_MBVALID(x) GENMASK(x, 0) - -/* Memory Bank Status Register for CRU Image Data */ -#define AMnMBS 0x14c -#define AMnMBS_MBSTS 0x7 - -/* AXI Master FIFO Pointer Register for CRU Image Data */ -#define AMnFIFOPNTR 0x168 -#define AMnFIFOPNTR_FIFOWPNTR GENMASK(7, 0) -#define AMnFIFOPNTR_FIFORPNTR_Y GENMASK(23, 16) - -/* AXI Master Transfer Stop Register for CRU Image Data */ -#define AMnAXISTP 0x174 -#define AMnAXISTP_AXI_STOP BIT(0) - -/* AXI Master Transfer Stop Status Register for CRU Image Data */ -#define AMnAXISTPACK 0x178 -#define AMnAXISTPACK_AXI_STOP_ACK BIT(0) - -/* CRU Image Processing Enable Register */ -#define ICnEN 0x200 -#define ICnEN_ICEN BIT(0) - -/* CRU Image Processing Main Control Register */ -#define ICnMC 0x208 -#define ICnMC_CSCTHR BIT(5) -#define ICnMC_INF_YUV8_422 (0x1e << 16) -#define ICnMC_INF_USER (0x30 << 16) -#define ICnMC_VCSEL(x) ((x) << 22) -#define ICnMC_INF_MASK GENMASK(21, 16) - -/* CRU Module Status Register */ -#define ICnMS 0x254 -#define ICnMS_IA BIT(2) - -/* CRU Data Output Mode Register */ -#define ICnDMR 0x26c -#define ICnDMR_YCMODE_UYVY (1 << 4) +#include "rzg2l-cru-regs.h" #define RZG2L_TIMEOUT_MS 100 #define RZG2L_RETRIES 10 @@ -184,46 +121,6 @@ static void rzg2l_cru_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&cru->qlock, flags); } -static int rzg2l_cru_mc_validate_format(struct rzg2l_cru_dev *cru, - struct v4l2_subdev *sd, - struct media_pad *pad) -{ - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - - fmt.pad = pad->index; - if (v4l2_subdev_call_state_active(sd, pad, get_fmt, &fmt)) - return -EPIPE; - - switch (fmt.format.code) { - case MEDIA_BUS_FMT_UYVY8_1X16: - break; - default: - return -EPIPE; - } - - switch (fmt.format.field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_NONE: - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_INTERLACED_BT: - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_SEQ_TB: - case V4L2_FIELD_SEQ_BT: - break; - default: - return -EPIPE; - } - - if (fmt.format.width != cru->format.width || - fmt.format.height != cru->format.height) - return -EPIPE; - - return 0; -} - static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru, int slot, dma_addr_t addr) { @@ -278,6 +175,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot) static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru) { unsigned int slot; + u32 amnaxiattr; /* * Set image data memory banks. @@ -287,55 +185,47 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru) for (slot = 0; slot < cru->num_buf; slot++) rzg2l_cru_fill_hw_slot(cru, slot); + + /* Set AXI burst max length to recommended setting */ + amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK; + amnaxiattr |= AMnAXIATTR_AXILEN; + rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr); } -static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, bool *input_is_yuv, - struct v4l2_mbus_framefmt *ip_sd_fmt) +static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, + const struct rzg2l_cru_ip_format *ip_fmt, + u8 csi_vc) { - u32 icnmc; - - switch (ip_sd_fmt->code) { - case MEDIA_BUS_FMT_UYVY8_1X16: - icnmc = ICnMC_INF_YUV8_422; - *input_is_yuv = true; - break; - default: - *input_is_yuv = false; - icnmc = ICnMC_INF_USER; - break; - } + u32 icnmc = ICnMC_INF(ip_fmt->datatype); icnmc |= (rzg2l_cru_read(cru, ICnMC) & ~ICnMC_INF_MASK); /* Set virtual channel CSI2 */ - icnmc |= ICnMC_VCSEL(cru->csi.channel); + icnmc |= ICnMC_VCSEL(csi_vc); rzg2l_cru_write(cru, ICnMC, icnmc); } static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru, - struct v4l2_mbus_framefmt *ip_sd_fmt) + struct v4l2_mbus_framefmt *ip_sd_fmt, + u8 csi_vc) { - bool output_is_yuv = false; - bool input_is_yuv = false; - u32 icndmr; + const struct rzg2l_cru_ip_format *cru_video_fmt; + const struct rzg2l_cru_ip_format *cru_ip_fmt; - rzg2l_cru_csi2_setup(cru, &input_is_yuv, ip_sd_fmt); + cru_ip_fmt = rzg2l_cru_ip_code_to_fmt(ip_sd_fmt->code); + rzg2l_cru_csi2_setup(cru, cru_ip_fmt, csi_vc); /* Output format */ - switch (cru->format.pixelformat) { - case V4L2_PIX_FMT_UYVY: - icndmr = ICnDMR_YCMODE_UYVY; - output_is_yuv = true; - break; - default: + cru_video_fmt = rzg2l_cru_ip_format_to_fmt(cru->format.pixelformat); + if (!cru_video_fmt) { dev_err(cru->dev, "Invalid pixelformat (0x%x)\n", cru->format.pixelformat); return -EINVAL; } /* If input and output use same colorspace, do bypass mode */ - if (output_is_yuv == input_is_yuv) + if (cru_ip_fmt->yuv == cru_video_fmt->yuv) rzg2l_cru_write(cru, ICnMC, rzg2l_cru_read(cru, ICnMC) | ICnMC_CSCTHR); else @@ -343,7 +233,7 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru, rzg2l_cru_read(cru, ICnMC) & (~ICnMC_CSCTHR)); /* Set output data format */ - rzg2l_cru_write(cru, ICnDMR, icndmr); + rzg2l_cru_write(cru, ICnDMR, cru_video_fmt->icndmr); return 0; } @@ -422,12 +312,47 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru) spin_unlock_irqrestore(&cru->qlock, flags); } +static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru) +{ + struct v4l2_mbus_frame_desc fd = { }; + struct media_pad *remote_pad; + int ret; + + remote_pad = media_pad_remote_pad_unique(&cru->ip.pads[RZG2L_CRU_IP_SINK]); + ret = v4l2_subdev_call(cru->ip.remote, pad, get_frame_desc, remote_pad->index, &fd); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_err(cru->dev, "get_frame_desc failed on IP remote subdev\n"); + return ret; + } + /* If remote subdev does not implement .get_frame_desc default to VC0. */ + if (ret == -ENOIOCTLCMD) + return 0; + + if (fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { + dev_err(cru->dev, "get_frame_desc returned invalid bus type %d\n", fd.type); + return -EINVAL; + } + + if (!fd.num_entries) { + dev_err(cru->dev, "get_frame_desc returned zero entries\n"); + return -EINVAL; + } + + return fd.entry[0].bus.csi2.vc; +} + int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru) { struct v4l2_mbus_framefmt *fmt = rzg2l_cru_ip_get_src_fmt(cru); unsigned long flags; + u8 csi_vc; int ret; + ret = rzg2l_cru_get_virtual_channel(cru); + if (ret < 0) + return ret; + csi_vc = ret; + spin_lock_irqsave(&cru->qlock, flags); /* Select a video input */ @@ -444,7 +369,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru) rzg2l_cru_initialize_axi(cru); /* Initialize image convert */ - ret = rzg2l_cru_initialize_image_conv(cru, fmt); + ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc); if (ret) { spin_unlock_irqrestore(&cru->qlock, flags); return ret; @@ -492,10 +417,6 @@ static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on) return stream_off_ret; } - ret = rzg2l_cru_mc_validate_format(cru, sd, pad); - if (ret) - return ret; - pipe = media_entity_pipeline(&sd->entity) ? : &cru->vdev.pipe; ret = video_device_pipeline_start(&cru->vdev, pipe); if (ret) @@ -527,7 +448,7 @@ static void rzg2l_cru_stop_streaming(struct rzg2l_cru_dev *cru) rzg2l_cru_set_stream(cru, 0); } -static irqreturn_t rzg2l_cru_irq(int irq, void *data) +irqreturn_t rzg2l_cru_irq(int irq, void *data) { struct rzg2l_cru_dev *cru = data; unsigned int handled = 0; @@ -637,13 +558,6 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count goto assert_aresetn; } - ret = request_irq(cru->image_conv_irq, rzg2l_cru_irq, - IRQF_SHARED, KBUILD_MODNAME, cru); - if (ret) { - dev_err(cru->dev, "failed to request irq\n"); - goto assert_presetn; - } - /* Allocate scratch buffer. */ cru->scratch = dma_alloc_coherent(cru->dev, cru->format.sizeimage, &cru->scratch_phys, GFP_KERNEL); @@ -651,7 +565,7 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count return_unused_buffers(cru, VB2_BUF_STATE_QUEUED); dev_err(cru->dev, "Failed to allocate scratch buffer\n"); ret = -ENOMEM; - goto free_image_conv_irq; + goto assert_presetn; } cru->sequence = 0; @@ -670,9 +584,6 @@ out: if (ret) dma_free_coherent(cru->dev, cru->format.sizeimage, cru->scratch, cru->scratch_phys); -free_image_conv_irq: - free_irq(cru->image_conv_irq, cru); - assert_presetn: reset_control_assert(cru->presetn); @@ -698,7 +609,6 @@ static void rzg2l_cru_stop_streaming_vq(struct vb2_queue *vq) dma_free_coherent(cru->dev, cru->format.sizeimage, cru->scratch, cru->scratch_phys); - free_irq(cru->image_conv_irq, cru); return_unused_buffers(cru, VB2_BUF_STATE_ERROR); reset_control_assert(cru->presetn); @@ -712,8 +622,6 @@ static const struct vb2_ops rzg2l_cru_qops = { .buf_queue = rzg2l_cru_buffer_queue, .start_streaming = rzg2l_cru_start_streaming_vq, .stop_streaming = rzg2l_cru_stop_streaming_vq, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru) @@ -775,46 +683,16 @@ error: * V4L2 stuff */ -static const struct v4l2_format_info rzg2l_cru_formats[] = { - { - .format = V4L2_PIX_FMT_UYVY, - .bpp[0] = 2, - }, -}; - -const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rzg2l_cru_formats); i++) - if (rzg2l_cru_formats[i].format == format) - return rzg2l_cru_formats + i; - - return NULL; -} - -static u32 rzg2l_cru_format_bytesperline(struct v4l2_pix_format *pix) -{ - const struct v4l2_format_info *fmt; - - fmt = rzg2l_cru_format_from_pixel(pix->pixelformat); - - if (WARN_ON(!fmt)) - return -EINVAL; - - return pix->width * fmt->bpp[0]; -} - -static u32 rzg2l_cru_format_sizeimage(struct v4l2_pix_format *pix) -{ - return pix->bytesperline * pix->height; -} - static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru, struct v4l2_pix_format *pix) { - if (!rzg2l_cru_format_from_pixel(pix->pixelformat)) + const struct rzg2l_cru_ip_format *fmt; + + fmt = rzg2l_cru_ip_format_to_fmt(pix->pixelformat); + if (!fmt) { pix->pixelformat = RZG2L_CRU_DEFAULT_FORMAT; + fmt = rzg2l_cru_ip_format_to_fmt(pix->pixelformat); + } switch (pix->field) { case V4L2_FIELD_TOP: @@ -833,8 +711,8 @@ static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru, v4l_bound_align_image(&pix->width, 320, RZG2L_CRU_MAX_INPUT_WIDTH, 1, &pix->height, 240, RZG2L_CRU_MAX_INPUT_HEIGHT, 2, 0); - pix->bytesperline = rzg2l_cru_format_bytesperline(pix); - pix->sizeimage = rzg2l_cru_format_sizeimage(pix); + pix->bytesperline = pix->width * fmt->bpp; + pix->sizeimage = pix->bytesperline * pix->height; dev_dbg(cru->dev, "Format %ux%u bpl: %u size: %u\n", pix->width, pix->height, pix->bytesperline, pix->sizeimage); @@ -905,10 +783,13 @@ static int rzg2l_cru_g_fmt_vid_cap(struct file *file, void *priv, static int rzg2l_cru_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - if (f->index >= ARRAY_SIZE(rzg2l_cru_formats)) + const struct rzg2l_cru_ip_format *fmt; + + fmt = rzg2l_cru_ip_index_to_fmt(f->index); + if (!fmt) return -EINVAL; - f->pixelformat = rzg2l_cru_formats[f->index].format; + f->pixelformat = fmt->format; return 0; } @@ -984,6 +865,43 @@ static const struct v4l2_file_operations rzg2l_cru_fops = { .read = vb2_fop_read, }; +/* ----------------------------------------------------------------------------- + * Media entity operations + */ + +static int rzg2l_cru_video_link_validate(struct media_link *link) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + const struct rzg2l_cru_ip_format *video_fmt; + struct v4l2_subdev *subdev; + struct rzg2l_cru_dev *cru; + int ret; + + subdev = media_entity_to_v4l2_subdev(link->source->entity); + fmt.pad = link->source->index; + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); + if (ret < 0) + return ret == -ENOIOCTLCMD ? -EINVAL : ret; + + cru = container_of(media_entity_to_video_device(link->sink->entity), + struct rzg2l_cru_dev, vdev); + video_fmt = rzg2l_cru_ip_format_to_fmt(cru->format.pixelformat); + + if (fmt.format.width != cru->format.width || + fmt.format.height != cru->format.height || + fmt.format.field != cru->format.field || + video_fmt->code != fmt.format.code) + return -EPIPE; + + return 0; +} + +static const struct media_entity_operations rzg2l_cru_video_media_ops = { + .link_validate = rzg2l_cru_video_link_validate, +}; + static void rzg2l_cru_v4l2_init(struct rzg2l_cru_dev *cru) { struct video_device *vdev = &cru->vdev; @@ -995,6 +913,7 @@ static void rzg2l_cru_v4l2_init(struct rzg2l_cru_dev *cru) vdev->lock = &cru->lock; vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; vdev->device_caps |= V4L2_CAP_IO_MC; + vdev->entity.ops = &rzg2l_cru_video_media_ops; vdev->fops = &rzg2l_cru_fops; vdev->ioctl_ops = &rzg2l_cru_ioctl_ops; diff --git a/drivers/media/platform/renesas/sh_vou.c b/drivers/media/platform/renesas/sh_vou.c index 1e74dd601c2b..4ad7ae188d5b 100644 --- a/drivers/media/platform/renesas/sh_vou.c +++ b/drivers/media/platform/renesas/sh_vou.c @@ -360,8 +360,6 @@ static const struct vb2_ops sh_vou_qops = { .buf_queue = sh_vou_buf_queue, .start_streaming = sh_vou_start_streaming, .stop_streaming = sh_vou_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* Video IOCTLs */ @@ -1359,7 +1357,7 @@ static void sh_vou_remove(struct platform_device *pdev) } static struct platform_driver sh_vou = { - .remove_new = sh_vou_remove, + .remove = sh_vou_remove, .driver = { .name = "sh-vou", }, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c index 1aac44d68731..9fc6bf624a52 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c @@ -1005,7 +1005,7 @@ MODULE_DEVICE_TABLE(of, vsp1_of_match); static struct platform_driver vsp1_platform_driver = { .probe = vsp1_probe, - .remove_new = vsp1_remove, + .remove = vsp1_remove, .driver = { .name = "vsp1", .pm = &vsp1_pm_ops, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c index 9c2d4c91bfad..c762202877ba 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c @@ -155,8 +155,6 @@ static const struct vb2_ops histo_video_queue_qops = { .queue_setup = histo_queue_setup, .buf_prepare = histo_buffer_prepare, .buf_queue = histo_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = histo_start_streaming, .stop_streaming = histo_stop_streaming, }; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index e728f9f5160e..03f4efd6b82b 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -873,8 +873,6 @@ static const struct vb2_ops vsp1_video_queue_qops = { .queue_setup = vsp1_video_queue_setup, .buf_prepare = vsp1_video_buffer_prepare, .buf_queue = vsp1_video_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = vsp1_video_start_streaming, .stop_streaming = vsp1_video_stop_streaming, }; diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c index 70808049d2e8..8a48e9d91f96 100644 --- a/drivers/media/platform/rockchip/rga/rga-buf.c +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -218,8 +218,6 @@ const struct vb2_ops rga_qops = { .buf_prepare = rga_buf_prepare, .buf_queue = rga_buf_queue, .buf_cleanup = rga_buf_cleanup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = rga_buf_start_streaming, .stop_streaming = rga_buf_stop_streaming, }; diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 0e768f3e9eda..1739ac0c8e92 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -102,7 +102,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) src_vq->drv_priv = ctx; src_vq->ops = &rga_qops; src_vq->mem_ops = &vb2_dma_sg_memops; - dst_vq->gfp_flags = __GFP_DMA32; + src_vq->gfp_flags = __GFP_DMA32; src_vq->buf_struct_size = sizeof(struct rga_vb_buffer); src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->rga->mutex; @@ -972,7 +972,7 @@ MODULE_DEVICE_TABLE(of, rockchip_rga_match); static struct platform_driver rga_pdrv = { .probe = rga_probe, - .remove_new = rga_remove, + .remove = rga_remove, .driver = { .name = RGA_NAME, .pm = &rga_pm, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index 2bddb4fa8a5c..02339cd94486 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -1203,8 +1203,6 @@ static const struct vb2_ops rkisp1_vb2_ops = { .buf_init = rkisp1_vb2_buf_init, .buf_queue = rkisp1_vb2_buf_queue, .buf_prepare = rkisp1_vb2_buf_prepare, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = rkisp1_vb2_stop_streaming, .start_streaming = rkisp1_vb2_start_streaming, }; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index dd114ab77800..0100b9c3edbe 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -752,7 +752,7 @@ static struct platform_driver rkisp1_drv = { .pm = &rkisp1_pm_ops, }, .probe = rkisp1_probe, - .remove_new = rkisp1_remove, + .remove = rkisp1_remove, }; module_platform_driver(rkisp1_drv); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 320581a9f866..b28f4140c8a3 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -2704,8 +2704,6 @@ static const struct vb2_ops rkisp1_params_vb2_ops = { .queue_setup = rkisp1_params_vb2_queue_setup, .buf_init = rkisp1_params_vb2_buf_init, .buf_cleanup = rkisp1_params_vb2_buf_cleanup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_queue = rkisp1_params_vb2_buf_queue, .buf_prepare = rkisp1_params_vb2_buf_prepare, .stop_streaming = rkisp1_params_vb2_stop_streaming, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c index a502719e916a..d5fdb8f82dc7 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c @@ -150,8 +150,6 @@ static const struct vb2_ops rkisp1_stats_vb2_ops = { .queue_setup = rkisp1_stats_vb2_queue_setup, .buf_queue = rkisp1_stats_vb2_buf_queue, .buf_prepare = rkisp1_stats_vb2_buf_prepare, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = rkisp1_stats_vb2_stop_streaming, }; diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c index f45f5c8612a6..a06d7cace92f 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c @@ -1309,7 +1309,7 @@ static const struct dev_pm_ops gsc_pm_ops = { static struct platform_driver gsc_driver = { .probe = gsc_probe, - .remove_new = gsc_remove, + .remove = gsc_remove, .driver = { .name = GSC_MODULE_NAME, .pm = &gsc_pm_ops, diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c index b7854ce5fb8e..4bda1c369c44 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c @@ -276,8 +276,6 @@ static const struct vb2_ops gsc_m2m_qops = { .queue_setup = gsc_m2m_queue_setup, .buf_prepare = gsc_m2m_buf_prepare, .buf_queue = gsc_m2m_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = gsc_m2m_stop_streaming, .start_streaming = gsc_m2m_start_streaming, }; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c index ffa4ea21387d..c3c2e474a18a 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c @@ -455,8 +455,6 @@ static const struct vb2_ops fimc_capture_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.c b/drivers/media/platform/samsung/exynos4-is/fimc-core.c index adfc2d73d04b..2c9edd0a559b 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-core.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.c @@ -1157,7 +1157,7 @@ static const struct dev_pm_ops fimc_pm_ops = { static struct platform_driver fimc_driver = { .probe = fimc_probe, - .remove_new = fimc_remove, + .remove = fimc_remove, .driver = { .of_match_table = fimc_of_match, .name = FIMC_DRIVER_NAME, diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c index 44363c4241d5..b243cbb1d010 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c @@ -137,7 +137,7 @@ static const struct of_device_id fimc_is_i2c_of_match[] = { static struct platform_driver fimc_is_i2c_driver = { .probe = fimc_is_i2c_probe, - .remove_new = fimc_is_i2c_remove, + .remove = fimc_is_i2c_remove, .driver = { .of_match_table = fimc_is_i2c_of_match, .name = "fimc-isp-i2c", diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c index 0a4b58daf924..2e8fe9e49735 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c @@ -963,7 +963,7 @@ static const struct dev_pm_ops fimc_is_pm_ops = { static struct platform_driver fimc_is_driver = { .probe = fimc_is_probe, - .remove_new = fimc_is_remove, + .remove = fimc_is_remove, .driver = { .of_match_table = fimc_is_of_match, .name = FIMC_IS_DRV_NAME, diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c index 06c4352562b3..ad219ac1b951 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c @@ -255,8 +255,6 @@ static const struct vb2_ops isp_video_capture_qops = { .queue_setup = isp_video_capture_queue_setup, .buf_prepare = isp_video_capture_buffer_prepare, .buf_queue = isp_video_capture_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = isp_video_capture_start_streaming, .stop_streaming = isp_video_capture_stop_streaming, }; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 1a4d75443215..f23e51e3da2f 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -441,8 +441,6 @@ static const struct vb2_ops fimc_lite_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; @@ -1654,7 +1652,7 @@ MODULE_DEVICE_TABLE(of, flite_of_match); static struct platform_driver fimc_lite_driver = { .probe = fimc_lite_probe, - .remove_new = fimc_lite_remove, + .remove = fimc_lite_remove, .driver = { .of_match_table = flite_of_match, .name = FIMC_LITE_DRV_NAME, diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c index 199997eec1cc..951433c8e92a 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c @@ -216,8 +216,6 @@ static const struct vb2_ops fimc_qops = { .queue_setup = fimc_queue_setup, .buf_prepare = fimc_buf_prepare, .buf_queue = fimc_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = stop_streaming, .start_streaming = start_streaming, }; diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c index 5f10bb4eb4f7..b5ee3c547789 100644 --- a/drivers/media/platform/samsung/exynos4-is/media-dev.c +++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c @@ -1564,7 +1564,7 @@ MODULE_DEVICE_TABLE(of, fimc_md_of_match); static struct platform_driver fimc_md_driver = { .probe = fimc_md_probe, - .remove_new = fimc_md_remove, + .remove = fimc_md_remove, .driver = { .of_match_table = of_match_ptr(fimc_md_of_match), .name = "s5p-fimc-md", diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.h b/drivers/media/platform/samsung/exynos4-is/media-dev.h index 786264cf79dc..a50e58ab7ef7 100644 --- a/drivers/media/platform/samsung/exynos4-is/media-dev.h +++ b/drivers/media/platform/samsung/exynos4-is/media-dev.h @@ -178,8 +178,9 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on); #ifdef CONFIG_OF static inline bool fimc_md_is_isp_available(struct device_node *node) { - node = of_get_child_by_name(node, FIMC_IS_OF_NODE_NAME); - return node ? of_device_is_available(node) : false; + struct device_node *child __free(device_node) = + of_get_child_by_name(node, FIMC_IS_OF_NODE_NAME); + return child ? of_device_is_available(child) : false; } #else #define fimc_md_is_isp_available(node) (false) diff --git a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c index 4b9b20ba3504..63f3eecdd7e6 100644 --- a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c @@ -1020,7 +1020,7 @@ MODULE_DEVICE_TABLE(of, s5pcsis_of_match); static struct platform_driver s5pcsis_driver = { .probe = s5pcsis_probe, - .remove_new = s5pcsis_remove, + .remove = s5pcsis_remove, .driver = { .of_match_table = s5pcsis_of_match, .name = CSIS_DRIVER_NAME, diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c index be58260ea67e..bd1149e8abc2 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c @@ -525,8 +525,6 @@ static const struct vb2_ops s3c_camif_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/platform/samsung/s3c-camif/camif-core.c b/drivers/media/platform/samsung/s3c-camif/camif-core.c index e4529f666e20..de6e8f151849 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-core.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-core.c @@ -622,7 +622,7 @@ static const struct dev_pm_ops s3c_camif_pm_ops = { static struct platform_driver s3c_camif_driver = { .probe = s3c_camif_probe, - .remove_new = s3c_camif_remove, + .remove = s3c_camif_remove, .id_table = s3c_camif_driver_ids, .driver = { .name = S3C_CAMIF_DRIVER_NAME, diff --git a/drivers/media/platform/samsung/s5p-g2d/g2d.c b/drivers/media/platform/samsung/s5p-g2d/g2d.c index 89aeba47ed07..ffed16a34493 100644 --- a/drivers/media/platform/samsung/s5p-g2d/g2d.c +++ b/drivers/media/platform/samsung/s5p-g2d/g2d.c @@ -133,8 +133,6 @@ static const struct vb2_ops g2d_qops = { .queue_setup = g2d_queue_setup, .buf_prepare = g2d_buf_prepare, .buf_queue = g2d_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -777,7 +775,7 @@ MODULE_DEVICE_TABLE(of, exynos_g2d_match); static struct platform_driver g2d_pdrv = { .probe = g2d_probe, - .remove_new = g2d_remove, + .remove = g2d_remove, .driver = { .name = G2D_NAME, .of_match_table = exynos_g2d_match, diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c index d2c4a0178b3c..ac4cf269456a 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c @@ -775,11 +775,14 @@ static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx) (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sos + 2; jpeg_buffer.curr = 0; - word = 0; - if (get_word_be(&jpeg_buffer, &word)) return; - jpeg_buffer.size = (long)word - 2; + + if (word < 2) + jpeg_buffer.size = 0; + else + jpeg_buffer.size = (long)word - 2; + jpeg_buffer.data += 2; jpeg_buffer.curr = 0; @@ -1058,6 +1061,7 @@ static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word) if (byte == -1) return -1; *word = (unsigned int)byte | temp; + return 0; } @@ -1145,7 +1149,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, if (get_word_be(&jpeg_buffer, &word)) break; length = (long)word - 2; - if (!length) + if (length <= 0) return false; sof = jpeg_buffer.curr; /* after 0xffc0 */ sof_len = length; @@ -1176,7 +1180,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, if (get_word_be(&jpeg_buffer, &word)) break; length = (long)word - 2; - if (!length) + if (length <= 0) return false; if (n_dqt >= S5P_JPEG_MAX_MARKER) return false; @@ -1189,7 +1193,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, if (get_word_be(&jpeg_buffer, &word)) break; length = (long)word - 2; - if (!length) + if (length <= 0) return false; if (n_dht >= S5P_JPEG_MAX_MARKER) return false; @@ -1214,6 +1218,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, if (get_word_be(&jpeg_buffer, &word)) break; length = (long)word - 2; + /* No need to check underflows as skip() does it */ skip(&jpeg_buffer, length); break; } @@ -2590,8 +2595,6 @@ static const struct vb2_ops s5p_jpeg_qops = { .queue_setup = s5p_jpeg_queue_setup, .buf_prepare = s5p_jpeg_buf_prepare, .buf_queue = s5p_jpeg_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = s5p_jpeg_start_streaming, .stop_streaming = s5p_jpeg_stop_streaming, }; @@ -3160,7 +3163,7 @@ static void *jpeg_get_drv_data(struct device *dev) static struct platform_driver s5p_jpeg_driver = { .probe = s5p_jpeg_probe, - .remove_new = s5p_jpeg_remove, + .remove = s5p_jpeg_remove, .driver = { .of_match_table = samsung_jpeg_match, .name = S5P_JPEG_M2M_NAME, diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c index 637a5104d948..6657d294c10a 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c @@ -427,11 +427,6 @@ void exynos3250_jpeg_clear_int_status(void __iomem *regs, writel(value, regs + EXYNOS3250_JPGINTST); } -unsigned int exynos3250_jpeg_operating(void __iomem *regs) -{ - return readl(regs + S5P_JPGOPR) & EXYNOS3250_JPGOPR_MASK; -} - unsigned int exynos3250_jpeg_compressed_size(void __iomem *regs) { return readl(regs + EXYNOS3250_JPGCNT) & EXYNOS3250_JPGCNT_MASK; diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h index 15af928fad76..709c61ae322c 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h @@ -45,7 +45,6 @@ void exynos3250_jpeg_rstart(void __iomem *regs); unsigned int exynos3250_jpeg_get_int_status(void __iomem *regs); void exynos3250_jpeg_clear_int_status(void __iomem *regs, unsigned int value); -unsigned int exynos3250_jpeg_operating(void __iomem *regs); unsigned int exynos3250_jpeg_compressed_size(void __iomem *regs); void exynos3250_jpeg_dec_stream_size(void __iomem *regs, unsigned int size); void exynos3250_jpeg_dec_scaling_ratio(void __iomem *regs, unsigned int sratio); diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c index 0828cfa783fe..479288fc8c77 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c @@ -185,11 +185,6 @@ unsigned int exynos4_jpeg_get_int_status(void __iomem *base) return readl(base + EXYNOS4_INT_STATUS_REG); } -unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base) -{ - return readl(base + EXYNOS4_FIFO_STATUS_REG); -} - void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value) { unsigned int reg; @@ -300,22 +295,8 @@ void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size) writel(size, base + EXYNOS4_BITSTREAM_SIZE_REG); } -void exynos4_jpeg_get_frame_size(void __iomem *base, - unsigned int *width, unsigned int *height) -{ - *width = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) & - EXYNOS4_DECODED_SIZE_MASK); - *height = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) >> 16) & - EXYNOS4_DECODED_SIZE_MASK; -} - unsigned int exynos4_jpeg_get_frame_fmt(void __iomem *base) { return readl(base + EXYNOS4_DECODE_IMG_FMT_REG) & EXYNOS4_JPEG_DECODED_IMG_FMT_MASK; } - -void exynos4_jpeg_set_timer_count(void __iomem *base, unsigned int size) -{ - writel(size, base + EXYNOS4_INT_TIMER_COUNT_REG); -} diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h index 3e2887526960..b941cc89e4ba 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h @@ -35,10 +35,6 @@ void exynos4_jpeg_select_dec_h_tbl(void __iomem *base, char c, char x); void exynos4_jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt); void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size); unsigned int exynos4_jpeg_get_stream_size(void __iomem *base); -void exynos4_jpeg_get_frame_size(void __iomem *base, - unsigned int *width, unsigned int *height); unsigned int exynos4_jpeg_get_frame_fmt(void __iomem *base); -unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base); -void exynos4_jpeg_set_timer_count(void __iomem *base, unsigned int size); #endif /* JPEG_HW_EXYNOS4_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index 50451984d59f..2fe3c9228ac5 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -1721,7 +1721,7 @@ MODULE_DEVICE_TABLE(of, exynos_mfc_match); static struct platform_driver s5p_mfc_driver = { .probe = s5p_mfc_probe, - .remove_new = s5p_mfc_remove, + .remove = s5p_mfc_remove, .driver = { .name = S5P_MFC_NAME, .pm = &s5p_mfc_pm_ops, diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c index 91e102d4ec4e..3efbc3367906 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c @@ -1161,8 +1161,6 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) static const struct vb2_ops s5p_mfc_dec_qops = { .queue_setup = s5p_mfc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_init = s5p_mfc_buf_init, .start_streaming = s5p_mfc_start_streaming, .stop_streaming = s5p_mfc_stop_streaming, diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c index 81cbb36fb382..6c603dcd5664 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -2652,8 +2652,6 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) static const struct vb2_ops s5p_mfc_enc_qops = { .queue_setup = s5p_mfc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_init = s5p_mfc_buf_init, .buf_prepare = s5p_mfc_buf_prepare, .start_streaming = s5p_mfc_start_streaming, diff --git a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c index c7ee6e1a4451..73ad66ed20f2 100644 --- a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c @@ -531,8 +531,6 @@ static const struct vb2_ops bdisp_qops = { .queue_setup = bdisp_queue_setup, .buf_prepare = bdisp_buf_prepare, .buf_queue = bdisp_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = bdisp_stop_streaming, .start_streaming = bdisp_start_streaming, }; @@ -1411,7 +1409,7 @@ MODULE_DEVICE_TABLE(of, bdisp_match_types); static struct platform_driver bdisp_driver = { .probe = bdisp_probe, - .remove_new = bdisp_remove, + .remove = bdisp_remove, .driver = { .name = BDISP_NAME, .of_match_table = bdisp_match_types, diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c index 67d3d6e50d2e..7b3a37957e3a 100644 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c @@ -1158,7 +1158,7 @@ static struct platform_driver c8sectpfe_driver = { .of_match_table = c8sectpfe_match, }, .probe = c8sectpfe_probe, - .remove_new = c8sectpfe_remove, + .remove = c8sectpfe_remove, }; module_platform_driver(c8sectpfe_driver); diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c index da402d1e9171..196e6a40335d 100644 --- a/drivers/media/platform/st/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c @@ -1559,8 +1559,6 @@ static const struct vb2_ops delta_vb2_au_ops = { .queue_setup = delta_vb2_au_queue_setup, .buf_prepare = delta_vb2_au_prepare, .buf_queue = delta_vb2_au_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = delta_vb2_au_start_streaming, .stop_streaming = delta_vb2_au_stop_streaming, }; @@ -1570,8 +1568,6 @@ static const struct vb2_ops delta_vb2_frame_ops = { .buf_prepare = delta_vb2_frame_prepare, .buf_finish = delta_vb2_frame_finish, .buf_queue = delta_vb2_frame_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = delta_vb2_frame_stop_streaming, }; @@ -1954,7 +1950,7 @@ MODULE_DEVICE_TABLE(of, delta_match_types); static struct platform_driver delta_driver = { .probe = delta_probe, - .remove_new = delta_remove, + .remove = delta_remove, .driver = { .name = DELTA_NAME, .of_match_table = delta_match_types, diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c index 161a5c0fbc4e..5366c0f92549 100644 --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c @@ -1114,8 +1114,6 @@ static const struct vb2_ops hva_qops = { .buf_queue = hva_buf_queue, .start_streaming = hva_start_streaming, .stop_streaming = hva_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* @@ -1456,7 +1454,7 @@ MODULE_DEVICE_TABLE(of, hva_match_types); static struct platform_driver hva_driver = { .probe = hva_probe, - .remove_new = hva_remove, + .remove = hva_remove, .driver = { .name = HVA_NAME, .of_match_table = hva_match_types, diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.c b/drivers/media/platform/st/stm32/dma2d/dma2d.c index 92f1edee58f8..b6c8400fb92d 100644 --- a/drivers/media/platform/st/stm32/dma2d/dma2d.c +++ b/drivers/media/platform/st/stm32/dma2d/dma2d.c @@ -186,8 +186,6 @@ static const struct vb2_ops dma2d_qops = { .buf_queue = dma2d_buf_queue, .start_streaming = dma2d_start_streaming, .stop_streaming = dma2d_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -717,7 +715,7 @@ MODULE_DEVICE_TABLE(of, stm32_dma2d_match); static struct platform_driver dma2d_pdrv = { .probe = dma2d_probe, - .remove_new = dma2d_remove, + .remove = dma2d_remove, .driver = { .name = DMA2D_NAME, .of_match_table = stm32_dma2d_match, diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index ff3331af9406..9b699ee2b1e0 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -898,8 +898,6 @@ static const struct vb2_ops dcmi_video_qops = { .buf_queue = dcmi_buf_queue, .start_streaming = dcmi_start_streaming, .stop_streaming = dcmi_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int dcmi_g_fmt_vid_cap(struct file *file, void *priv, @@ -2149,7 +2147,7 @@ static const struct dev_pm_ops dcmi_pm_ops = { static struct platform_driver stm32_dcmi_driver = { .probe = dcmi_probe, - .remove_new = dcmi_remove, + .remove = dcmi_remove, .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(stm32_dcmi_of_match), diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c index 9f768f011fa2..7edd49bfe7e5 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c @@ -625,12 +625,6 @@ static const struct vb2_ops dcmipp_bytecap_qops = { .buf_prepare = dcmipp_bytecap_buf_prepare, .buf_queue = dcmipp_bytecap_buf_queue, .queue_setup = dcmipp_bytecap_queue_setup, - /* - * Since q->lock is set we can use the standard - * vb2_ops_wait_prepare/finish helper functions. - */ - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static void dcmipp_bytecap_release(struct video_device *vdev) diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c index 7f771ea49b78..3806f7c6e2fe 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c @@ -583,7 +583,7 @@ static const struct dev_pm_ops dcmipp_pm_ops = { static struct platform_driver dcmipp_pdrv = { .probe = dcmipp_probe, - .remove_new = dcmipp_remove, + .remove = dcmipp_remove, .driver = { .name = DCMIPP_PDEV_NAME, .of_match_table = dcmipp_of_match, diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c index d07e980aba61..e53a07b770b7 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -340,7 +340,7 @@ static const struct dev_pm_ops sun4i_csi_pm_ops = { static struct platform_driver sun4i_csi_driver = { .probe = sun4i_csi_probe, - .remove_new = sun4i_csi_remove, + .remove = sun4i_csi_remove, .driver = { .name = "sun4i-csi", .of_match_table = sun4i_csi_of_match, diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c index d1371e130113..e911c7f7acc5 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c @@ -371,8 +371,6 @@ static const struct vb2_ops sun4i_csi_qops = { .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) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index c6ba385c0c86..af2a32c226a5 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -423,7 +423,7 @@ MODULE_DEVICE_TABLE(of, sun6i_csi_of_match); static struct platform_driver sun6i_csi_platform_driver = { .probe = sun6i_csi_probe, - .remove_new = sun6i_csi_remove, + .remove = sun6i_csi_remove, .driver = { .name = SUN6I_CSI_NAME, .of_match_table = sun6i_csi_of_match, diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 14c0dc827c52..76356bc7f10e 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -657,8 +657,6 @@ static const struct vb2_ops sun6i_csi_capture_queue_ops = { .buf_queue = sun6i_csi_capture_buffer_queue, .start_streaming = sun6i_csi_capture_start_streaming, .stop_streaming = sun6i_csi_capture_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* V4L2 Device */ diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c index f9d4dc45b490..b06cb73015cd 100644 --- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c @@ -757,7 +757,7 @@ MODULE_DEVICE_TABLE(of, sun6i_mipi_csi2_of_match); static struct platform_driver sun6i_mipi_csi2_platform_driver = { .probe = sun6i_mipi_csi2_probe, - .remove_new = sun6i_mipi_csi2_remove, + .remove = sun6i_mipi_csi2_remove, .driver = { .name = SUN6I_MIPI_CSI2_NAME, .of_match_table = sun6i_mipi_csi2_of_match, diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c index 4a5698eb12b7..dbc51daa4fe3 100644 --- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c @@ -824,7 +824,7 @@ MODULE_DEVICE_TABLE(of, sun8i_a83t_mipi_csi2_of_match); static struct platform_driver sun8i_a83t_mipi_csi2_platform_driver = { .probe = sun8i_a83t_mipi_csi2_probe, - .remove_new = sun8i_a83t_mipi_csi2_remove, + .remove = sun8i_a83t_mipi_csi2_remove, .driver = { .name = SUN8I_A83T_MIPI_CSI2_NAME, .of_match_table = sun8i_a83t_mipi_csi2_of_match, diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c index a1c35a2b68ed..3e7f2df70408 100644 --- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -659,8 +659,6 @@ static const struct vb2_ops deinterlace_qops = { .buf_queue = deinterlace_buf_queue, .start_streaming = deinterlace_start_streaming, .stop_streaming = deinterlace_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int deinterlace_queue_init(void *priv, struct vb2_queue *src_vq, @@ -1001,7 +999,7 @@ static const struct dev_pm_ops deinterlace_pm_ops = { static struct platform_driver deinterlace_driver = { .probe = deinterlace_probe, - .remove_new = deinterlace_remove, + .remove = deinterlace_remove, .driver = { .name = DEINTERLACE_NAME, .of_match_table = deinterlace_dt_match, diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c index a12323ca89fa..abd10b218aa1 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c +++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c @@ -522,8 +522,6 @@ static const struct vb2_ops rotate_qops = { .buf_queue = rotate_buf_queue, .start_streaming = rotate_start_streaming, .stop_streaming = rotate_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int rotate_queue_init(void *priv, struct vb2_queue *src_vq, @@ -905,7 +903,7 @@ static const struct dev_pm_ops rotate_pm_ops = { static struct platform_driver rotate_driver = { .probe = rotate_probe, - .remove_new = rotate_remove, + .remove = rotate_remove, .driver = { .name = ROTATE_NAME, .of_match_table = rotate_dt_match, diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c index 009ff68a2b43..44cdccb89377 100644 --- a/drivers/media/platform/ti/am437x/am437x-vpfe.c +++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c @@ -2079,8 +2079,6 @@ static long vpfe_ioctl_default(struct file *file, void *priv, } static const struct vb2_ops vpfe_video_qops = { - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .queue_setup = vpfe_queue_setup, .buf_prepare = vpfe_buffer_prepare, .buf_queue = vpfe_buffer_queue, @@ -2617,7 +2615,7 @@ MODULE_DEVICE_TABLE(of, vpfe_of_match); static struct platform_driver vpfe_driver = { .probe = vpfe_probe, - .remove_new = vpfe_remove, + .remove = vpfe_remove, .driver = { .name = VPFE_MODULE_NAME, .pm = &vpfe_pm_ops, diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index e1ba5dfc217e..e29743ae61e2 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -808,8 +808,6 @@ static const struct vb2_ops cal_video_qops = { .buf_queue = cal_buffer_queue, .start_streaming = cal_start_streaming, .stop_streaming = cal_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c index 5c2c04142aee..4bd2092e0255 100644 --- a/drivers/media/platform/ti/cal/cal.c +++ b/drivers/media/platform/ti/cal/cal.c @@ -1332,7 +1332,7 @@ static const struct dev_pm_ops cal_pm_ops = { static struct platform_driver cal_pdrv = { .probe = cal_probe, - .remove_new = cal_remove, + .remove = cal_remove, .driver = { .name = CAL_MODULE_NAME, .pm = &cal_pm_ops, diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c index f4e1fa76bf37..a81719702a22 100644 --- a/drivers/media/platform/ti/davinci/vpif.c +++ b/drivers/media/platform/ti/davinci/vpif.c @@ -589,7 +589,7 @@ static struct platform_driver vpif_driver = { .name = VPIF_DRIVER_NAME, .pm = vpif_pm_ops, }, - .remove_new = vpif_remove, + .remove = vpif_remove, .probe = vpif_probe, }; diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c index 16326437767f..d053972888d1 100644 --- a/drivers/media/platform/ti/davinci/vpif_capture.c +++ b/drivers/media/platform/ti/davinci/vpif_capture.c @@ -310,8 +310,6 @@ static const struct vb2_ops video_qops = { .start_streaming = vpif_start_streaming, .stop_streaming = vpif_stop_streaming, .buf_queue = vpif_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /** @@ -1815,7 +1813,7 @@ static __refdata struct platform_driver vpif_driver = { .pm = &vpif_pm_ops, }, .probe = vpif_probe, - .remove_new = vpif_remove, + .remove = vpif_remove, }; module_platform_driver(vpif_driver); diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c index 76d8fa8ad088..70c89549f4b6 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.c +++ b/drivers/media/platform/ti/davinci/vpif_display.c @@ -293,8 +293,6 @@ static void vpif_stop_streaming(struct vb2_queue *vq) static const struct vb2_ops video_qops = { .queue_setup = vpif_buffer_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = vpif_buffer_prepare, .start_streaming = vpif_start_streaming, .stop_streaming = vpif_stop_streaming, @@ -1398,7 +1396,7 @@ static __refdata struct platform_driver vpif_driver = { .pm = &vpif_pm_ops, }, .probe = vpif_probe, - .remove_new = vpif_remove, + .remove = vpif_remove, }; module_platform_driver(vpif_driver); diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 22442fce7607..6412a00be8ea 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -878,8 +878,6 @@ static const struct vb2_ops csi_vb2_qops = { .buf_queue = ti_csi2rx_buffer_queue, .start_streaming = ti_csi2rx_start_streaming, .stop_streaming = ti_csi2rx_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int ti_csi2rx_init_vb2q(struct ti_csi2rx_dev *csi) @@ -1014,9 +1012,9 @@ static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) pix_fmt->height = 480; pix_fmt->field = V4L2_FIELD_NONE; pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; - pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601, - pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE, - pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB, + pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; + pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; ti_csi2rx_fill_fmt(fmt, &csi->v_fmt); @@ -1163,7 +1161,7 @@ MODULE_DEVICE_TABLE(of, ti_csi2rx_of_match); static struct platform_driver ti_csi2rx_pdrv = { .probe = ti_csi2rx_probe, - .remove_new = ti_csi2rx_remove, + .remove = ti_csi2rx_remove, .driver = { .name = TI_CSI2RX_MODULE_NAME, .of_match_table = ti_csi2rx_of_match, diff --git a/drivers/media/platform/ti/omap/omap_vout.c b/drivers/media/platform/ti/omap/omap_vout.c index 1c56b6a87ced..a87d5030ac35 100644 --- a/drivers/media/platform/ti/omap/omap_vout.c +++ b/drivers/media/platform/ti/omap/omap_vout.c @@ -1300,8 +1300,6 @@ static const struct vb2_ops omap_vout_vb2_ops = { .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 */ @@ -1721,7 +1719,7 @@ static struct platform_driver omap_vout_driver = { .driver = { .name = VOUT_NAME, }, - .remove_new = omap_vout_remove, + .remove = omap_vout_remove, }; static int __init omap_vout_init(void) diff --git a/drivers/media/platform/ti/omap/omap_voutdef.h b/drivers/media/platform/ti/omap/omap_voutdef.h index b586193341d2..159e5e670d91 100644 --- a/drivers/media/platform/ti/omap/omap_voutdef.h +++ b/drivers/media/platform/ti/omap/omap_voutdef.h @@ -48,7 +48,7 @@ #define VRFB_TX_TIMEOUT 1000 #define VRFB_NUM_BUFS 4 -/* Max buffer size tobe allocated during init */ +/* Max buffer size to be allocated during init */ #define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4) enum dma_channel_state { diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c index 91101ba88ef0..405ca215179d 100644 --- a/drivers/media/platform/ti/omap3isp/isp.c +++ b/drivers/media/platform/ti/omap3isp/isp.c @@ -2472,7 +2472,7 @@ MODULE_DEVICE_TABLE(of, omap3isp_of_table); static struct platform_driver omap3isp_driver = { .probe = isp_probe, - .remove_new = isp_remove, + .remove = isp_remove, .id_table = omap3isp_id_table, .driver = { .name = "omap3isp", diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index daca689dc082..5c9aa80023fd 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -480,11 +480,29 @@ static int isp_video_start_streaming(struct vb2_queue *queue, return 0; } +static void omap3isp_wait_prepare(struct vb2_queue *vq) +{ + struct isp_video_fh *vfh = vb2_get_drv_priv(vq); + struct isp_video *video = vfh->video; + + mutex_unlock(&video->queue_lock); +} + +static void omap3isp_wait_finish(struct vb2_queue *vq) +{ + struct isp_video_fh *vfh = vb2_get_drv_priv(vq); + struct isp_video *video = vfh->video; + + mutex_lock(&video->queue_lock); +} + static const struct vb2_ops isp_video_queue_ops = { .queue_setup = isp_video_queue_setup, .buf_prepare = isp_video_buffer_prepare, .buf_queue = isp_video_buffer_queue, .start_streaming = isp_video_start_streaming, + .wait_prepare = omap3isp_wait_prepare, + .wait_finish = omap3isp_wait_finish, }; /* diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c index 6848cbc82f52..636d76ecebcd 100644 --- a/drivers/media/platform/ti/vpe/vpe.c +++ b/drivers/media/platform/ti/vpe/vpe.c @@ -2210,8 +2210,6 @@ static const struct vb2_ops vpe_qops = { .queue_setup = vpe_queue_setup, .buf_prepare = vpe_buf_prepare, .buf_queue = vpe_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = vpe_start_streaming, .stop_streaming = vpe_stop_streaming, }; @@ -2649,7 +2647,7 @@ MODULE_DEVICE_TABLE(of, vpe_of_match); static struct platform_driver vpe_pdrv = { .probe = vpe_probe, - .remove_new = vpe_remove, + .remove = vpe_remove, .driver = { .name = VPE_MODULE_NAME, .of_match_table = of_match_ptr(vpe_of_match), diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 05bbac853c4f..8542238e0fb1 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -1277,7 +1277,7 @@ static const struct dev_pm_ops hantro_pm_ops = { static struct platform_driver hantro_driver = { .probe = hantro_probe, - .remove_new = hantro_remove, + .remove = hantro_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_hantro_match, diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index 62d3962c18d9..2513adfbd825 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -201,7 +201,15 @@ static int vidioc_enum_fmt(struct file *file, void *priv, struct hantro_ctx *ctx = fh_to_ctx(priv); const struct hantro_fmt *fmt, *formats; unsigned int num_fmts, i, j = 0; - bool skip_mode_none; + bool skip_mode_none, enum_all_formats; + u32 index = f->index & ~V4L2_FMTDESC_FLAG_ENUM_ALL; + + /* + * If the V4L2_FMTDESC_FLAG_ENUM_ALL flag is set, we want to enumerate all + * hardware supported pixel formats + */ + enum_all_formats = !!(f->index & V4L2_FMTDESC_FLAG_ENUM_ALL); + f->index = index; /* * When dealing with an encoder: @@ -222,9 +230,9 @@ static int vidioc_enum_fmt(struct file *file, void *priv, if (skip_mode_none == mode_none) continue; - if (!hantro_check_depth_match(fmt, ctx->bit_depth)) + if (!hantro_check_depth_match(fmt, ctx->bit_depth) && !enum_all_formats) continue; - if (j == f->index) { + if (j == index) { f->pixelformat = fmt->fourcc; return 0; } @@ -242,9 +250,9 @@ static int vidioc_enum_fmt(struct file *file, void *priv, for (i = 0; i < num_fmts; i++) { fmt = &formats[i]; - if (!hantro_check_depth_match(fmt, ctx->bit_depth)) + if (!hantro_check_depth_match(fmt, ctx->bit_depth) && !enum_all_formats) continue; - if (j == f->index) { + if (j == index) { f->pixelformat = fmt->fourcc; return 0; } @@ -996,6 +1004,4 @@ const struct vb2_ops hantro_queue_ops = { .buf_request_complete = hantro_buf_request_complete, .start_streaming = hantro_start_streaming, .stop_streaming = hantro_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c index 65e8f2d07400..e54f5fac325b 100644 --- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c +++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c @@ -161,8 +161,7 @@ static int rockchip_vpu981_av1_dec_frame_ref(struct hantro_ctx *ctx, av1_dec->frame_refs[i].timestamp = timestamp; av1_dec->frame_refs[i].frame_type = frame->frame_type; av1_dec->frame_refs[i].order_hint = frame->order_hint; - if (!av1_dec->frame_refs[i].vb2_ref) - av1_dec->frame_refs[i].vb2_ref = hantro_get_dst_buf(ctx); + av1_dec->frame_refs[i].vb2_ref = hantro_get_dst_buf(ctx); for (j = 0; j < V4L2_AV1_TOTAL_REFS_PER_FRAME; j++) av1_dec->frame_refs[i].order_hints[j] = frame->order_hints[j]; diff --git a/drivers/media/platform/via/via-camera.c b/drivers/media/platform/via/via-camera.c index 4cb8f29e2f14..5702eff664d4 100644 --- a/drivers/media/platform/via/via-camera.c +++ b/drivers/media/platform/via/via-camera.c @@ -666,8 +666,6 @@ static const struct vb2_ops viacam_vb2_ops = { .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, }; /* --------------------------------------------------------------------------*/ @@ -1307,7 +1305,7 @@ static struct platform_driver viacam_driver = { .name = "viafb-camera", }, .probe = viacam_probe, - .remove_new = viacam_remove, + .remove = viacam_remove, }; module_platform_driver(viacam_driver); diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index 31e9e92e723e..cba34893258a 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -52,6 +52,7 @@ static int video_mux_link_setup(struct media_entity *entity, const struct media_pad *remote, u32 flags) { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct v4l2_subdev_state *sd_state; struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); u16 source_pad = entity->num_pads - 1; int ret = 0; @@ -67,10 +68,10 @@ static int video_mux_link_setup(struct media_entity *entity, remote->entity->name, remote->index, local->entity->name, local->index, flags & MEDIA_LNK_FL_ENABLED); + sd_state = v4l2_subdev_lock_and_get_active_state(sd); mutex_lock(&vmux->lock); if (flags & MEDIA_LNK_FL_ENABLED) { - struct v4l2_subdev_state *sd_state; struct v4l2_mbus_framefmt *source_mbusformat; if (vmux->active == local->index) @@ -88,12 +89,10 @@ static int video_mux_link_setup(struct media_entity *entity, vmux->active = local->index; /* Propagate the active format to the source */ - sd_state = v4l2_subdev_lock_and_get_active_state(sd); source_mbusformat = v4l2_subdev_state_get_format(sd_state, source_pad); *source_mbusformat = *v4l2_subdev_state_get_format(sd_state, vmux->active); - v4l2_subdev_unlock_state(sd_state); } else { if (vmux->active != local->index) goto out; @@ -105,6 +104,7 @@ static int video_mux_link_setup(struct media_entity *entity, out: mutex_unlock(&vmux->lock); + v4l2_subdev_unlock_state(sd_state); return ret; } @@ -486,7 +486,7 @@ MODULE_DEVICE_TABLE(of, video_mux_dt_ids); static struct platform_driver video_mux_driver = { .probe = video_mux_probe, - .remove_new = video_mux_remove, + .remove = video_mux_remove, .driver = { .of_match_table = video_mux_dt_ids, .name = "video-mux", diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c index f953d5474ae0..146131b8f37e 100644 --- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c +++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c @@ -1028,7 +1028,7 @@ static struct platform_driver xcsi2rxss_driver = { .of_match_table = xcsi2rxss_of_id_table, }, .probe = xcsi2rxss_probe, - .remove_new = xcsi2rxss_remove, + .remove = xcsi2rxss_remove, }; module_platform_driver(xcsi2rxss_driver); diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index a1687b868a44..18bfa6001909 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -458,8 +458,6 @@ static const struct vb2_ops xvip_dma_queue_qops = { .queue_setup = xvip_dma_queue_setup, .buf_prepare = xvip_dma_buffer_prepare, .buf_queue = xvip_dma_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = xvip_dma_start_streaming, .stop_streaming = xvip_dma_stop_streaming, }; diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c index e05e528ffc6f..cb93711ea3e3 100644 --- a/drivers/media/platform/xilinx/xilinx-tpg.c +++ b/drivers/media/platform/xilinx/xilinx-tpg.c @@ -13,6 +13,7 @@ #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_graph.h> #include <linux/platform_device.h> #include <linux/xilinx-v4l2-controls.h> @@ -711,22 +712,13 @@ static int xtpg_parse_of(struct xtpg_device *xtpg) { struct device *dev = xtpg->xvip.dev; struct device_node *node = xtpg->xvip.dev->of_node; - struct device_node *ports; - struct device_node *port; unsigned int nports = 0; bool has_endpoint = false; - ports = of_get_child_by_name(node, "ports"); - if (ports == NULL) - ports = node; - - for_each_child_of_node(ports, port) { + for_each_of_graph_port(node, port) { const struct xvip_video_format *format; struct device_node *endpoint; - if (!of_node_name_eq(port, "port")) - continue; - format = xvip_of_get_format(port); if (IS_ERR(format)) { dev_err(dev, "invalid format in DT"); @@ -744,7 +736,7 @@ static int xtpg_parse_of(struct xtpg_device *xtpg) } if (nports == 0) { - endpoint = of_get_next_child(port, NULL); + endpoint = of_graph_get_next_port_endpoint(port, NULL); if (endpoint) has_endpoint = true; of_node_put(endpoint); @@ -920,7 +912,7 @@ static struct platform_driver xtpg_driver = { .of_match_table = xtpg_of_id_table, }, .probe = xtpg_probe, - .remove_new = xtpg_remove, + .remove = xtpg_remove, }; module_platform_driver(xtpg_driver); diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index bfe48cc0ab52..024b439feec9 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -618,7 +618,7 @@ static struct platform_driver xvip_composite_driver = { .of_match_table = xvip_composite_of_id_table, }, .probe = xvip_composite_probe, - .remove_new = xvip_composite_remove, + .remove = xvip_composite_remove, }; module_platform_driver(xvip_composite_driver); diff --git a/drivers/media/platform/xilinx/xilinx-vtc.c b/drivers/media/platform/xilinx/xilinx-vtc.c index dda70719f004..92fec7bb47da 100644 --- a/drivers/media/platform/xilinx/xilinx-vtc.c +++ b/drivers/media/platform/xilinx/xilinx-vtc.c @@ -365,7 +365,7 @@ static struct platform_driver xvtc_driver = { .of_match_table = xvtc_of_id_table, }, .probe = xvtc_probe, - .remove_new = xvtc_remove, + .remove = xvtc_remove, }; module_platform_driver(xvtc_driver); diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 0e9a3787724c..3c8c17d64821 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -4,7 +4,7 @@ * * Copyright 1997 M. Kirkwood * - * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com> + * Converted to the radio-isa framework by Hans Verkuil <hansverk@cisco.com> * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org> * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index a532f63aa9d9..5ca6274c45bd 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -15,7 +15,7 @@ * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> * - * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com> + * Converted to the radio-isa framework by Hans Verkuil <hansverk@cisco.com> * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org> * * Note: this card seems to swap the left and right audio channels! diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index ad49151f5ff0..4f87c76a2a96 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -4,7 +4,7 @@ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers * to concentrate on the actual hardware operation. * - * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.com> + * Copyright (C) 2012 Hans Verkuil <hansverk@cisco.com> */ #include <linux/module.h> diff --git a/drivers/media/radio/radio-isa.h b/drivers/media/radio/radio-isa.h index c9159958203e..0f3db473da5e 100644 --- a/drivers/media/radio/radio-isa.h +++ b/drivers/media/radio/radio-isa.h @@ -4,7 +4,7 @@ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers * to concentrate on the actual hardware operation. * - * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.com> + * Copyright (C) 2012 Hans Verkuil <hansverk@cisco.com> */ #ifndef _RADIO_ISA_H_ diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 08be77b8f3b7..27f058c5e677 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -23,7 +23,7 @@ * This code has been reintroduced and converted to use * the new V4L2 RDS API by: * - * Hans Verkuil <hans.verkuil@cisco.com> + * Hans Verkuil <hansverk@cisco.com> */ #include <linux/module.h> diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index 73d2c187f122..16b13a63bfed 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -7,7 +7,7 @@ * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> * - * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com> + * Converted to the radio-isa framework by Hans Verkuil <hansverk@cisco.com> * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org> * * Fully tested with actual hardware and the v4l2-compliance tool. diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index b2c5809a8bc7..9980346cb5ea 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -1513,7 +1513,7 @@ static struct platform_driver si476x_radio_driver = { .name = DRIVER_NAME, }, .probe = si476x_radio_probe, - .remove_new = si476x_radio_remove, + .remove = si476x_radio_remove, }; module_platform_driver(si476x_radio_driver); diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 621bb8523271..720080634454 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -17,7 +17,7 @@ * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); * Volume Control is done digitally * - * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com> + * Converted to the radio-isa framework by Hans Verkuil <hansverk@cisco.com> * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org> */ diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index 04daa9c358c2..a6069b106fd3 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -164,7 +164,7 @@ static struct platform_driver timbradio_platform_driver = { .name = DRIVER_NAME, }, .probe = timbradio_probe, - .remove_new = timbradio_remove, + .remove = timbradio_remove, }; module_platform_driver(timbradio_platform_driver); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index f6b98c304b72..511a8ede05ec 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -2145,7 +2145,7 @@ pdata_err: static struct platform_driver wl1273_fm_radio_driver = { .probe = wl1273_fm_radio_probe, - .remove_new = wl1273_fm_radio_remove, + .remove = wl1273_fm_radio_remove, .driver = { .name = "wl1273_fm_radio", }, diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index f3dc57c75131..099b7af6a410 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -30,7 +30,7 @@ * 2006-07-24 - Converted to V4L2 API * by Mauro Carvalho Chehab <mchehab@kernel.org> * - * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com> + * Converted to the radio-isa framework by Hans Verkuil <hansverk@cisco.com> * * Note that this is the driver for the Zoltrix Radio Plus. * This driver does not work for the Zoltrix Radio Plus 108 or the diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c index 9fdaed68a962..67b4afadc95a 100644 --- a/drivers/media/radio/si4713/radio-platform-si4713.c +++ b/drivers/media/radio/si4713/radio-platform-si4713.c @@ -205,7 +205,7 @@ static struct platform_driver radio_si4713_pdriver = { .name = "radio-si4713", }, .probe = radio_si4713_pdriver_probe, - .remove_new = radio_si4713_pdriver_remove, + .remove = radio_si4713_pdriver_remove, }; module_platform_driver(radio_si4713_pdriver); diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 3d36f323a8f8..4d032436691c 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -466,11 +466,12 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); return -ETIMEDOUT; } + spin_lock_irqsave(&fmdev->resp_skb_lock, flags); if (!fmdev->resp_skb) { + spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); fmerr("Response SKB is missing\n"); return -EFAULT; } - spin_lock_irqsave(&fmdev->resp_skb_lock, flags); skb = fmdev->resp_skb; fmdev->resp_skb = NULL; spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 74d69ce22a33..0a8aeafdb7e0 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -184,6 +184,7 @@ config IR_GPIO_TX tristate "GPIO IR Bit Banging Transmitter" depends on LIRC depends on (OF && GPIOLIB) || COMPILE_TEST + depends on !PREEMPT_RT help Say Y if you want to a GPIO based IR transmitter. This is a bit banging driver. diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index d7721e60776e..a733914a2574 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -311,9 +311,9 @@ static void ati_remote_dump(struct device *dev, unsigned char *data, if (data[0] != (unsigned char)0xff && data[0] != 0x00) dev_warn(dev, "Weird byte 0x%02x\n", data[0]); } else if (len == 4) - dev_warn(dev, "Weird key %*ph\n", 4, data); + dev_warn(dev, "Weird key %4ph\n", data); else - dev_warn(dev, "Weird data, len=%d %*ph ...\n", len, 6, data); + dev_warn(dev, "Weird data, len=%d %6ph ...\n", len, data); } /* @@ -502,7 +502,7 @@ static void ati_remote_input_report(struct urb *urb) if (data[1] != ((data[2] + data[3] + 0xd5) & 0xff)) { dbginfo(&ati_remote->interface->dev, - "wrong checksum in input: %*ph\n", 4, data); + "wrong checksum in input: %4ph\n", data); return; } diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index b29a1a9f381d..bf6d8fa983bf 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -201,7 +201,7 @@ MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match); static struct platform_driver gpio_ir_recv_driver = { .probe = gpio_ir_recv_probe, - .remove_new = gpio_ir_recv_remove, + .remove = gpio_ir_recv_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = gpio_ir_recv_of_match, diff --git a/drivers/media/rc/gpio-ir-tx.c b/drivers/media/rc/gpio-ir-tx.c index 1a8fea357f14..e185ead40464 100644 --- a/drivers/media/rc/gpio-ir-tx.c +++ b/drivers/media/rc/gpio-ir-tx.c @@ -78,8 +78,6 @@ static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf, ktime_t edge; int i; - local_irq_disable(); - edge = ktime_get(); for (i = 0; i < count; i++) { @@ -110,8 +108,6 @@ static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf, space = DIV_ROUND_CLOSEST((100 - gpio_ir->duty_cycle) * (NSEC_PER_SEC / 100), gpio_ir->carrier); - local_irq_disable(); - edge = ktime_get(); for (i = 0; i < count; i++) { diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c index d87d8e14c556..067f4bc7fcc3 100644 --- a/drivers/media/rc/img-ir/img-ir-core.c +++ b/drivers/media/rc/img-ir/img-ir-core.c @@ -181,7 +181,7 @@ static struct platform_driver img_ir_driver = { .pm = &img_ir_pmops, }, .probe = img_ir_probe, - .remove_new = img_ir_remove, + .remove = img_ir_remove, }; module_platform_driver(img_ir_driver); diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index de5bb9a08ea4..afd80d2350c6 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -394,7 +394,7 @@ static struct platform_driver hix5hd2_ir_driver = { .pm = &hix5hd2_ir_pm_ops, }, .probe = hix5hd2_ir_probe, - .remove_new = hix5hd2_ir_remove, + .remove = hix5hd2_ir_remove, }; module_platform_driver(hix5hd2_ir_driver); diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index f042f3f14afa..a2257dc2f25d 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -815,28 +815,23 @@ void __exit lirc_dev_exit(void) struct rc_dev *rc_dev_get_from_fd(int fd, bool write) { - struct fd f = fdget(fd); + CLASS(fd, f)(fd); struct lirc_fh *fh; struct rc_dev *dev; - if (!fd_file(f)) + if (fd_empty(f)) return ERR_PTR(-EBADF); - if (fd_file(f)->f_op != &lirc_fops) { - fdput(f); + if (fd_file(f)->f_op != &lirc_fops) return ERR_PTR(-EINVAL); - } - if (write && !(fd_file(f)->f_mode & FMODE_WRITE)) { - fdput(f); + if (write && !(fd_file(f)->f_mode & FMODE_WRITE)) return ERR_PTR(-EPERM); - } fh = fd_file(f)->private_data; dev = fh->rc; get_device(&dev->dev); - fdput(f); return dev; } diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 9cdb45821ecc..272ebb0d97c8 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -628,7 +628,7 @@ MODULE_DEVICE_TABLE(of, meson_ir_match); static struct platform_driver meson_ir_driver = { .probe = meson_ir_probe, - .remove_new = meson_ir_remove, + .remove = meson_ir_remove, .shutdown = meson_ir_shutdown, .driver = { .name = DRIVER_NAME, diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c index b2f82b2d1c8d..85c9436b0a20 100644 --- a/drivers/media/rc/mtk-cir.c +++ b/drivers/media/rc/mtk-cir.c @@ -440,7 +440,7 @@ static void mtk_ir_remove(struct platform_device *pdev) static struct platform_driver mtk_ir_driver = { .probe = mtk_ir_probe, - .remove_new = mtk_ir_remove, + .remove = mtk_ir_remove, .driver = { .name = MTK_IR_DEV, .of_match_table = mtk_ir_match, diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 988b09191c4c..6539fa0a6e79 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -408,7 +408,7 @@ static struct platform_driver st_rc_driver = { .pm = &st_rc_pm_ops, }, .probe = st_rc_probe, - .remove_new = st_rc_remove, + .remove = st_rc_remove, }; module_platform_driver(st_rc_driver); diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index b49df8355e6b..92ef4e7c6f69 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -413,7 +413,7 @@ MODULE_DEVICE_TABLE(of, sunxi_ir_match); static struct platform_driver sunxi_ir_driver = { .probe = sunxi_ir_probe, - .remove_new = sunxi_ir_remove, + .remove = sunxi_ir_remove, .shutdown = sunxi_ir_shutdown, .driver = { .name = SUNXI_IR_DEV, diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index 846e90c06291..c45f5cf12ded 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -26,7 +26,7 @@ #include "codec-v4l2-fwht.h" MODULE_DESCRIPTION("Virtual codec device"); -MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>"); MODULE_LICENSE("GPL v2"); static bool multiplanar; @@ -43,6 +43,8 @@ MODULE_PARM_DESC(debug, " activates debug info"); #define MIN_WIDTH 640U #define MAX_HEIGHT 2160U #define MIN_HEIGHT 360U +/* Recommended number of buffers for the stateful codecs */ +#define VICODEC_REC_BUFS 2 #define dprintk(dev, fmt, arg...) \ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) @@ -1688,8 +1690,6 @@ static const struct vb2_ops vicodec_qops = { .buf_request_complete = vicodec_buf_request_complete, .start_streaming = vicodec_start_streaming, .stop_streaming = vicodec_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -1707,12 +1707,14 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &vicodec_qops; src_vq->mem_ops = &vb2_vmalloc_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - if (ctx->is_enc) + if (ctx->is_enc) { src_vq->lock = &ctx->dev->stateful_enc.mutex; - else if (ctx->is_stateless) + src_vq->min_reqbufs_allocation = VICODEC_REC_BUFS; + } else if (ctx->is_stateless) { src_vq->lock = &ctx->dev->stateless_dec.mutex; - else + } else { src_vq->lock = &ctx->dev->stateful_dec.mutex; + } src_vq->supports_requests = ctx->is_stateless; src_vq->requires_requests = ctx->is_stateless; ret = vb2_queue_init(src_vq); @@ -1730,6 +1732,8 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->mem_ops = &vb2_vmalloc_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = src_vq->lock; + if (!ctx->is_stateless && !ctx->is_enc) + dst_vq->min_reqbufs_allocation = VICODEC_REC_BUFS; return vb2_queue_init(dst_vq); } @@ -1854,11 +1858,16 @@ static int vicodec_open(struct file *file) 1, 31, 1, 20); v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP, 1, 31, 1, 20); - if (ctx->is_enc) - v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, - V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 1, 1, 1); + if (ctx->is_stateless) v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL); + else + v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, ctx->is_enc ? + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT : + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + VICODEC_REC_BUFS, VICODEC_REC_BUFS, 1, + VICODEC_REC_BUFS); + if (hdl->error) { rc = hdl->error; v4l2_ctrl_handler_free(hdl); @@ -2207,7 +2216,7 @@ static void vicodec_remove(struct platform_device *pdev) static struct platform_driver vicodec_pdrv = { .probe = vicodec_probe, - .remove_new = vicodec_remove, + .remove = vicodec_remove, .driver = { .name = VICODEC_NAME, }, diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c index 613949df897d..e1dd8adeba46 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c +++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c @@ -572,7 +572,7 @@ static struct platform_driver vidtv_bridge_driver = { .name = VIDTV_PDEV_NAME, }, .probe = vidtv_bridge_probe, - .remove_new = vidtv_bridge_remove, + .remove = vidtv_bridge_remove, }; static void __exit vidtv_bridge_exit(void) diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c index 3e3b424b4860..6c24dcf27eb0 100644 --- a/drivers/media/test-drivers/vim2m.c +++ b/drivers/media/test-drivers/vim2m.c @@ -1100,8 +1100,6 @@ static const struct vb2_ops vim2m_qops = { .buf_queue = vim2m_buf_queue, .start_streaming = vim2m_start_streaming, .stop_streaming = vim2m_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_request_complete = vim2m_buf_request_complete, }; @@ -1394,7 +1392,7 @@ static void vim2m_remove(struct platform_device *pdev) static struct platform_driver vim2m_pdrv = { .probe = vim2m_probe, - .remove_new = vim2m_remove, + .remove = vim2m_remove, .driver = { .name = MEM2MEM_NAME, }, diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c index 89506ae00901..10df039278e7 100644 --- a/drivers/media/test-drivers/vimc/vimc-capture.c +++ b/drivers/media/test-drivers/vimc/vimc-capture.c @@ -326,12 +326,6 @@ static const struct vb2_ops vimc_capture_qops = { .buf_queue = vimc_capture_buf_queue, .queue_setup = vimc_capture_queue_setup, .buf_prepare = vimc_capture_buffer_prepare, - /* - * Since q->lock is set we can use the standard - * vb2_ops_wait_prepare/finish helper functions. - */ - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static const struct media_entity_operations vimc_capture_mops = { diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c index 2083c60e34d6..c812fa9f0650 100644 --- a/drivers/media/test-drivers/vimc/vimc-core.c +++ b/drivers/media/test-drivers/vimc/vimc-core.c @@ -410,7 +410,7 @@ static struct platform_device vimc_pdev = { static struct platform_driver vimc_pdrv = { .probe = vimc_probe, - .remove_new = vimc_remove, + .remove = vimc_remove, .driver = { .name = VIMC_PDEV_NAME, }, diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c index c46464bcaf2e..01c964ea6f76 100644 --- a/drivers/media/test-drivers/visl/visl-core.c +++ b/drivers/media/test-drivers/visl/visl-core.c @@ -523,7 +523,7 @@ static void visl_remove(struct platform_device *pdev) static struct platform_driver visl_pdrv = { .probe = visl_probe, - .remove_new = visl_remove, + .remove = visl_remove, .driver = { .name = VISL_NAME, }, diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c index f8d970319764..8be505d8908c 100644 --- a/drivers/media/test-drivers/visl/visl-video.c +++ b/drivers/media/test-drivers/visl/visl-video.c @@ -136,6 +136,12 @@ static const u32 visl_decoded_fmts[] = { V4L2_PIX_FMT_YUV420, }; +static const u32 visl_extended_decoded_fmts[] = { + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_P010, +}; + const struct visl_coded_format_desc visl_coded_fmts[] = { { .pixelformat = V4L2_PIX_FMT_FWHT_STATELESS, @@ -341,11 +347,21 @@ static int visl_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct visl_ctx *ctx = visl_file_to_ctx(file); + u32 index = f->index & ~V4L2_FMTDESC_FLAG_ENUM_ALL; + int max_fmts = ctx->coded_format_desc->num_decoded_fmts; + const u32 *decoded_fmts = ctx->coded_format_desc->decoded_fmts; + + if (f->index & V4L2_FMTDESC_FLAG_ENUM_ALL) { + max_fmts = ARRAY_SIZE(visl_extended_decoded_fmts); + decoded_fmts = visl_extended_decoded_fmts; + } + + f->index = index; - if (f->index >= ctx->coded_format_desc->num_decoded_fmts) + if (index >= max_fmts) return -EINVAL; - f->pixelformat = ctx->coded_format_desc->decoded_fmts[f->index]; + f->pixelformat = decoded_fmts[index]; return 0; } @@ -716,8 +732,6 @@ static const struct vb2_ops visl_qops = { .buf_queue = visl_buf_queue, .start_streaming = visl_start_streaming, .stop_streaming = visl_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_request_complete = visl_buf_request_complete, }; diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index 00e0d08af357..7477ac8cb955 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -910,7 +910,7 @@ static int vivid_create_queue(struct vivid_dev *dev, * videobuf2-core.c to MAX_BUFFER_INDEX. */ if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - q->max_num_buffers = 64; + q->max_num_buffers = MAX_VID_CAP_BUFFERS; if (buf_type == V4L2_BUF_TYPE_SDR_CAPTURE) q->max_num_buffers = 1024; if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE) @@ -2239,7 +2239,7 @@ static struct platform_device vivid_pdev = { static struct platform_driver vivid_pdrv = { .probe = vivid_probe, - .remove_new = vivid_remove, + .remove = vivid_remove, .driver = { .name = "vivid", }, diff --git a/drivers/media/test-drivers/vivid/vivid-core.h b/drivers/media/test-drivers/vivid/vivid-core.h index cc18a3bc6dc0..d2d52763b119 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.h +++ b/drivers/media/test-drivers/vivid/vivid-core.h @@ -26,6 +26,8 @@ #define MAX_INPUTS 16 /* The maximum number of outputs */ #define MAX_OUTPUTS 16 +/* The maximum number of video capture buffers */ +#define MAX_VID_CAP_BUFFERS 64 /* The maximum up or down scaling factor is 4 */ #define MAX_ZOOM 4 /* The maximum image width/height are set to 4K DMT */ @@ -481,7 +483,7 @@ struct vivid_dev { /* video capture */ struct tpg_data tpg; unsigned ms_vid_cap; - bool must_blank[VIDEO_MAX_FRAME]; + bool must_blank[MAX_VID_CAP_BUFFERS]; const struct vivid_fmt *fmt_cap; struct v4l2_fract timeperframe_vid_cap; diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c index 8bb38bc7b8cc..2b5c8fbcd0a2 100644 --- a/drivers/media/test-drivers/vivid/vivid-ctrls.c +++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c @@ -553,7 +553,7 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) break; case VIVID_CID_PERCENTAGE_FILL: tpg_s_perc_fill(&dev->tpg, ctrl->val); - for (i = 0; i < VIDEO_MAX_FRAME; i++) + for (i = 0; i < MAX_VID_CAP_BUFFERS; i++) dev->must_blank[i] = ctrl->val < 100; break; case VIVID_CID_INSERT_SAV: diff --git a/drivers/media/test-drivers/vivid/vivid-meta-cap.c b/drivers/media/test-drivers/vivid/vivid-meta-cap.c index 0a718d037e59..c7aaecc0b5a2 100644 --- a/drivers/media/test-drivers/vivid/vivid-meta-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-meta-cap.c @@ -122,8 +122,6 @@ const struct vb2_ops vivid_meta_cap_qops = { .start_streaming = meta_cap_start_streaming, .stop_streaming = meta_cap_stop_streaming, .buf_request_complete = meta_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vidioc_enum_fmt_meta_cap(struct file *file, void *priv, diff --git a/drivers/media/test-drivers/vivid/vivid-meta-out.c b/drivers/media/test-drivers/vivid/vivid-meta-out.c index 82ab3b26914e..55e5e5dec2f2 100644 --- a/drivers/media/test-drivers/vivid/vivid-meta-out.c +++ b/drivers/media/test-drivers/vivid/vivid-meta-out.c @@ -122,8 +122,6 @@ const struct vb2_ops vivid_meta_out_qops = { .start_streaming = meta_out_start_streaming, .stop_streaming = meta_out_stop_streaming, .buf_request_complete = meta_out_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vidioc_enum_fmt_meta_out(struct file *file, void *priv, diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c index 38cda33dffb2..74a91d28c8be 100644 --- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c @@ -337,8 +337,6 @@ const struct vb2_ops vivid_sdr_cap_qops = { .start_streaming = sdr_cap_start_streaming, .stop_streaming = sdr_cap_stop_streaming, .buf_request_complete = sdr_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vivid_sdr_enum_freq_bands(struct file *file, void *fh, diff --git a/drivers/media/test-drivers/vivid/vivid-touch-cap.c b/drivers/media/test-drivers/vivid/vivid-touch-cap.c index 3600b084bca5..36a781fa17bc 100644 --- a/drivers/media/test-drivers/vivid/vivid-touch-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-touch-cap.c @@ -110,8 +110,6 @@ const struct vb2_ops vivid_touch_cap_qops = { .start_streaming = touch_cap_start_streaming, .stop_streaming = touch_cap_stop_streaming, .buf_request_complete = touch_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f) diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c index 99138f63585c..a09f62c66c33 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c @@ -230,8 +230,6 @@ const struct vb2_ops vivid_vbi_cap_qops = { .start_streaming = vbi_cap_start_streaming, .stop_streaming = vbi_cap_stop_streaming, .buf_request_complete = vbi_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-out.c b/drivers/media/test-drivers/vivid/vivid-vbi-out.c index 871a56d93425..b7a09d2f394e 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vbi-out.c @@ -128,8 +128,6 @@ const struct vb2_ops vivid_vbi_out_qops = { .start_streaming = vbi_out_start_streaming, .stop_streaming = vbi_out_stop_streaming, .buf_request_complete = vbi_out_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vidioc_g_fmt_vbi_out(struct file *file, void *priv, diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c index 69620e0a35a0..b166d90177c6 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c @@ -10,6 +10,7 @@ #include <linux/sched.h> #include <linux/vmalloc.h> #include <linux/videodev2.h> +#include <linux/prandom.h> #include <linux/v4l2-dv-timings.h> #include <media/v4l2-common.h> #include <media/v4l2-event.h> @@ -213,7 +214,7 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count) dev->vid_cap_seq_count = 0; dprintk(dev, 1, "%s\n", __func__); - for (i = 0; i < VIDEO_MAX_FRAME; i++) + for (i = 0; i < MAX_VID_CAP_BUFFERS; i++) dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100; if (dev->start_streaming_error) { dev->start_streaming_error = false; @@ -257,8 +258,6 @@ const struct vb2_ops vivid_vid_cap_qops = { .start_streaming = vid_cap_start_streaming, .stop_streaming = vid_cap_stop_streaming, .buf_request_complete = vid_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* @@ -1459,12 +1458,19 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) h_freq = (u32)bt->pixelclock / total_h_pixel; if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { + struct v4l2_dv_timings cvt = {}; + if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, bt->width, - bt->polarities, bt->interlaced, timings)) + bt->polarities, bt->interlaced, + &vivid_dv_timings_cap, &cvt) && + cvt.bt.width == bt->width && cvt.bt.height == bt->height) { + *timings = cvt; return true; + } } if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) { + struct v4l2_dv_timings gtf = {}; struct v4l2_fract aspect_ratio; find_aspect_ratio(bt->width, bt->height, @@ -1472,8 +1478,12 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) &aspect_ratio.denominator); if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync, bt->polarities, bt->interlaced, - aspect_ratio, timings)) + aspect_ratio, &vivid_dv_timings_cap, + >f) && + gtf.bt.width == bt->width && gtf.bt.height == bt->height) { + *timings = gtf; return true; + } } return false; } diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c index 60327f3612af..5ec84db934d6 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c @@ -201,8 +201,6 @@ const struct vb2_ops vivid_vid_out_qops = { .start_streaming = vid_out_start_streaming, .stop_streaming = vid_out_stop_streaming, .buf_request_complete = vid_out_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 4d5b1c878028..9186174a46fd 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -444,7 +444,7 @@ static struct platform_driver it913x_driver = { .suppress_bind_attrs = true, }, .probe = it913x_probe, - .remove_new = it913x_remove, + .remove = it913x_remove, .id_table = it913x_id_table, }; diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index 6afef11a49cb..2c8ce74ddca4 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -1476,7 +1476,7 @@ static u32 MT2063_CalcLO2Mult(u32 *Div, } /* - * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be + * FindClearTuneFilter() - Calculate the correct ClearTune filter to be * used for a given input frequency. * * @state: ptr to tuner data structure diff --git a/drivers/media/tuners/mxl301rf.c b/drivers/media/tuners/mxl301rf.c index 7c03d4132763..3b61c3afed18 100644 --- a/drivers/media/tuners/mxl301rf.c +++ b/drivers/media/tuners/mxl301rf.c @@ -64,7 +64,7 @@ static int reg_read(struct mxl301rf_state *state, u8 reg, u8 *val) /* tuner_ops */ -/* get RSSI and update propery cache, set to *out in % */ +/* get RSSI and update property cache, set to *out in % */ static int mxl301rf_get_rf_strength(struct dvb_frontend *fe, u16 *out) { struct mxl301rf_state *state; diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c index d9bfa257a005..0e811c5eae6c 100644 --- a/drivers/media/tuners/mxl5005s.c +++ b/drivers/media/tuners/mxl5005s.c @@ -2639,7 +2639,7 @@ static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq) E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ; status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A); - /* Euqation E5B CHCAL_EN_INIT_RF */ + /* Equation E5B CHCAL_EN_INIT_RF */ status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0)); /*if (E5 == 0) * status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1); diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c index a7e721baaa99..3a3309bc0151 100644 --- a/drivers/media/tuners/tda18271-fe.c +++ b/drivers/media/tuners/tda18271-fe.c @@ -279,7 +279,9 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, if (approx > 255) approx = 255; - tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); + ret = tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); + if (tda_fail(ret)) + goto fail; /* calculate temperature compensation */ rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000; diff --git a/drivers/media/tuners/tea5761.c b/drivers/media/tuners/tea5761.c index d78a2bdb3e36..425e9fd3f3d4 100644 --- a/drivers/media/tuners/tea5761.c +++ b/drivers/media/tuners/tea5761.c @@ -46,7 +46,7 @@ struct tea5761_priv { /* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */ /* First byte */ -#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */ +#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from bottom to up */ #define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */ /* Bits 0-5 for divider MSB */ @@ -132,7 +132,7 @@ static void tea5761_status_dump(unsigned char *buffer) frq / 1000, frq % 1000, div); } -/* Freq should be specifyed at 62.5 Hz */ +/* Freq should be specified at 62.5 Hz */ static int __set_radio_freq(struct dvb_frontend *fe, unsigned int freq, bool mono) diff --git a/drivers/media/tuners/tea5767.c b/drivers/media/tuners/tea5767.c index 016d0d5ec50b..ef4acb1f1bfa 100644 --- a/drivers/media/tuners/tea5767.c +++ b/drivers/media/tuners/tea5767.c @@ -44,7 +44,7 @@ struct tea5767_priv { /* Third register */ -/* Station search from botton to up */ +/* Station search from bottom to up */ #define TEA5767_SEARCH_UP 0x80 /* Searches with ADC output = 10 */ @@ -183,7 +183,7 @@ static void tea5767_status_dump(struct tea5767_priv *priv, (buffer[4] & TEA5767_RESERVED_MASK)); } -/* Freq should be specifyed at 62.5 Hz */ +/* Freq should be specified at 62.5 Hz */ static int set_radio_freq(struct dvb_frontend *fe, struct analog_parameters *params) { diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index e24e655fb1db..08f0920cf6ca 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -603,8 +603,6 @@ static const struct vb2_ops airspy_vb2_ops = { .buf_queue = airspy_buf_queue, .start_streaming = airspy_start_streaming, .stop_streaming = airspy_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int airspy_querycap(struct file *file, void *fh, @@ -1017,6 +1015,7 @@ static int airspy_probe(struct usb_interface *intf, s->vb_queue.ops = &airspy_vb2_ops; s->vb_queue.mem_ops = &vb2_vmalloc_memops; s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + s->vb_queue.lock = &s->vb_queue_lock; ret = vb2_queue_init(&s->vb_queue); if (ret) { dev_err(s->dev, "Could not initialize vb2 queue\n"); @@ -1026,7 +1025,6 @@ static int airspy_probe(struct usb_interface *intf, /* Init video_device structure */ s->vdev = airspy_template; s->vdev.queue = &s->vb_queue; - s->vdev.queue->lock = &s->vb_queue_lock; video_set_drvdata(&s->vdev, s); /* Register the v4l2_device structure */ diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c index b0333637b747..11203adf47ea 100644 --- a/drivers/media/usb/au0828/au0828-vbi.c +++ b/drivers/media/usb/au0828/au0828-vbi.c @@ -74,6 +74,4 @@ const struct vb2_ops au0828_vbi_qops = { .prepare_streaming = v4l_vb2q_enable_media_source, .start_streaming = au0828_start_analog_streaming, .stop_streaming = au0828_stop_vbi_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 2ec49ea479d5..e9cd2a335f7f 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -915,8 +915,6 @@ static const struct vb2_ops au0828_video_qops = { .prepare_streaming = v4l_vb2q_enable_media_source, .start_streaming = au0828_start_analog_streaming, .stop_streaming = au0828_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index abb967c8bd35..a4a9781328c5 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1458,8 +1458,6 @@ static const struct vb2_ops cx231xx_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 3d3c881c8e58..6139ef5d891d 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -623,7 +623,7 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input) } int cx231xx_set_decoder_video_input(struct cx231xx *dev, - u8 pin_type, u8 input) + u8 pin_type, u32 input) { int status = 0; u32 value = 0; @@ -1338,39 +1338,6 @@ void update_HH_register_after_set_DIF(struct cx231xx *dev) */ } -void cx231xx_dump_HH_reg(struct cx231xx *dev) -{ - u32 value = 0; - u16 i = 0; - - value = 0x45005390; - vid_blk_write_word(dev, 0x104, value); - - for (i = 0x100; i < 0x140; i++) { - vid_blk_read_word(dev, i, &value); - dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value); - i = i+3; - } - - for (i = 0x300; i < 0x400; i++) { - vid_blk_read_word(dev, i, &value); - dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value); - i = i+3; - } - - for (i = 0x400; i < 0x440; i++) { - vid_blk_read_word(dev, i, &value); - dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value); - i = i+3; - } - - vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); - dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value); - vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390); - vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); - dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value); -} - #if 0 static void cx231xx_dump_SC_reg(struct cx231xx *dev) { @@ -2460,30 +2427,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode) return status; } -int cx231xx_power_suspend(struct cx231xx *dev) -{ - u8 value[4] = { 0, 0, 0, 0 }; - u32 tmp = 0; - int status = 0; - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, - value, 4); - if (status > 0) - return status; - - tmp = le32_to_cpu(*((__le32 *) value)); - tmp &= (~PWR_MODE_MASK); - - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN, - value, 4); - - return status; -} - /****************************************************************************** * S T R E A M C O N T R O L functions * ******************************************************************************/ diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 92efe6c1f47b..691f073892b3 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -679,8 +679,7 @@ struct cx231xx_board cx231xx_boards[] = { }, { .type = CX231XX_VMUX_SVIDEO, .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, + (CX231XX_VIN_3_2 << 8), .amux = CX231XX_AMUX_LINE_IN, .gpio = NULL, } @@ -990,10 +989,11 @@ struct cx231xx_board cx231xx_boards[] = { } }, }, }; -const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); /* table of devices that work with this driver */ struct usb_device_id cx231xx_id_table[] = { + {USB_DEVICE(0x1D19, 0x6108), + .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, {USB_DEVICE(0x1D19, 0x6109), .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, {USB_DEVICE(0x0572, 0x5A3C), diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index 33431d9f54c2..338e10148465 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -243,8 +243,6 @@ struct vb2_ops cx231xx_vbi_qops = { .buf_queue = vbi_buf_queue, .start_streaming = vbi_start_streaming, .stop_streaming = vbi_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 435eb0b32cb1..2cd4e333bc4b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -800,8 +800,6 @@ static const struct vb2_ops cx231xx_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /********************* v4l2 interface **************************************/ diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 74339a6a2f71..19f5036a78d7 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -790,7 +790,6 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq, u8 spectral_invert, u32 mode); void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev); void reset_s5h1432_demod(struct cx231xx *dev); -void cx231xx_dump_HH_reg(struct cx231xx *dev); void update_HH_register_after_set_DIF(struct cx231xx *dev); @@ -905,7 +904,6 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type); /* Power control functions */ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode); -int cx231xx_power_suspend(struct cx231xx *dev); /* chip specific control functions */ int cx231xx_init_ctrl_pin_status(struct cx231xx *dev); @@ -916,7 +914,7 @@ int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3); /* video audio decoder related functions */ void video_mux(struct cx231xx *dev, int index); int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input); -int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input); +int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u32 input); int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev); int cx231xx_set_audio_input(struct cx231xx *dev, u8 input); @@ -949,7 +947,6 @@ extern void cx231xx_pre_card_setup(struct cx231xx *dev); extern void cx231xx_card_setup(struct cx231xx *dev); extern struct cx231xx_board cx231xx_boards[]; extern struct usb_device_id cx231xx_id_table[]; -extern const unsigned int cx231xx_bcount; int cx231xx_tuner_callback(void *ptr, int component, int command, int arg); /* cx23885-417.c */ diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 8699846eb416..bea12cdc85e8 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -46,24 +46,15 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, state->buf); - /* We need receive one message more after dvb_usb_generic_rw due - to weird transaction flow, which is 1 x send + 2 x receive. */ + /* + * We need receive one message more after dvb_usbv2_generic_rw_locked() + * due to weird transaction flow, which is 1 x send + 2 x receive. + */ ret = dvb_usbv2_generic_rw_locked(d, state->buf, sizeof(state->buf), state->buf, sizeof(state->buf)); if (ret) goto error_unlock; - /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32 - * (EPIPE, Broken pipe). Function supports currently msleep() as a - * parameter but I would not like to use it, since according to - * Documentation/timers/timers-howto.rst it should not be used such - * short, under < 20ms, sleeps. Repeating failed message would be - * better choice as not to add unwanted delays... - * Fixing that correctly is one of those or both; - * 1) use repeat if possible - * 2) add suitable delay - */ - /* get answer, retry few times if error returned */ for (i = 0; i < 3; i++) { /* receive 2nd answer */ diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c index b5d8c6b75ae1..8253046cd6e6 100644 --- a/drivers/media/usb/dvb-usb/cxusb-analog.c +++ b/drivers/media/usb/dvb-usb/cxusb-analog.c @@ -956,8 +956,6 @@ static const struct vb2_ops cxdev_video_qops = { .start_streaming = cxusb_medion_v_start_streaming, .stop_streaming = cxusb_medion_v_stop_streaming, .buf_queue = cxusub_medion_v_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish }; static const __u32 videocaps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index b253c44c9724..8c5d95181223 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -84,6 +84,4 @@ const struct vb2_ops em28xx_vbi_qops = { .buf_queue = vbi_buffer_queue, .start_streaming = em28xx_start_analog_streaming, .stop_streaming = em28xx_stop_vbi_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 4aef584e21da..66c09bc6d59e 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1229,8 +1229,6 @@ static const struct vb2_ops em28xx_video_qops = { .buf_queue = buffer_queue, .start_streaming = em28xx_start_analog_streaming, .stop_streaming = em28xx_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int em28xx_vb2_setup(struct em28xx *dev) diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index 13256565b034..2087ffcb85a5 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -452,8 +452,6 @@ static const struct vb2_ops go7007_video_qops = { .buf_finish = go7007_buf_finish, .start_streaming = go7007_start_streaming, .stop_streaming = go7007_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int vidioc_g_parm(struct file *filp, void *priv, diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index e8c8bdb9c40b..25edd2189654 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1380,8 +1380,6 @@ static const struct vb2_ops gspca_qops = { .buf_queue = gspca_buffer_queue, .start_streaming = gspca_start_streaming, .stop_streaming = gspca_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static const struct v4l2_file_operations dev_fops = { diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 8b6a57f170d0..bdff64a29a33 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -847,7 +847,7 @@ static void set_frame_rate(struct gspca_dev *gspca_dev) r = rate_1; i = ARRAY_SIZE(rate_1); } - while (--i > 0) { + while (--i >= 0) { if (sd->frame_rate >= r->fps) break; r++; diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index 9c0ecd5f056c..0b50de8775a3 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -888,8 +888,6 @@ static const struct vb2_ops hackrf_vb2_ops = { .buf_queue = hackrf_buf_queue, .start_streaming = hackrf_start_streaming, .stop_streaming = hackrf_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int hackrf_querycap(struct file *file, void *fh, @@ -1398,6 +1396,7 @@ static int hackrf_probe(struct usb_interface *intf, dev->rx_vb2_queue.drv_priv = dev; dev->rx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer); dev->rx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + dev->rx_vb2_queue.lock = &dev->vb_queue_lock; ret = vb2_queue_init(&dev->rx_vb2_queue); if (ret) { dev_err(dev->dev, "Could not initialize rx vb2 queue\n"); @@ -1413,6 +1412,7 @@ static int hackrf_probe(struct usb_interface *intf, dev->tx_vb2_queue.drv_priv = dev; dev->tx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer); dev->tx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + dev->tx_vb2_queue.lock = &dev->vb_queue_lock; ret = vb2_queue_init(&dev->tx_vb2_queue); if (ret) { dev_err(dev->dev, "Could not initialize tx vb2 queue\n"); @@ -1474,7 +1474,6 @@ static int hackrf_probe(struct usb_interface *intf, /* Init video_device structure for receiver */ dev->rx_vdev = hackrf_template; dev->rx_vdev.queue = &dev->rx_vb2_queue; - dev->rx_vdev.queue->lock = &dev->vb_queue_lock; dev->rx_vdev.v4l2_dev = &dev->v4l2_dev; dev->rx_vdev.ctrl_handler = &dev->rx_ctrl_handler; dev->rx_vdev.lock = &dev->v4l2_lock; @@ -1494,7 +1493,6 @@ static int hackrf_probe(struct usb_interface *intf, /* Init video_device structure for transmitter */ dev->tx_vdev = hackrf_template; dev->tx_vdev.queue = &dev->tx_vb2_queue; - dev->tx_vdev.queue->lock = &dev->vb_queue_lock; dev->tx_vdev.v4l2_dev = &dev->v4l2_dev; dev->tx_vdev.ctrl_handler = &dev->tx_ctrl_handler; dev->tx_vdev.lock = &dev->v4l2_lock; diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 5138486abfa0..33099f39146a 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -883,8 +883,6 @@ static const struct vb2_ops msi2500_vb2_ops = { .buf_queue = msi2500_buf_queue, .start_streaming = msi2500_start_streaming, .stop_streaming = msi2500_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv, @@ -1199,6 +1197,7 @@ static int msi2500_probe(struct usb_interface *intf, dev->vb_queue.ops = &msi2500_vb2_ops; dev->vb_queue.mem_ops = &vb2_vmalloc_memops; dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + dev->vb_queue.lock = &dev->vb_queue_lock; ret = vb2_queue_init(&dev->vb_queue); if (ret) { dev_err(dev->dev, "Could not initialize vb2 queue\n"); @@ -1208,7 +1207,6 @@ static int msi2500_probe(struct usb_interface *intf, /* Init video_device structure */ dev->vdev = msi2500_template; dev->vdev.queue = &dev->vb_queue; - dev->vdev.queue->lock = &dev->vb_queue_lock; video_set_drvdata(&dev->vdev, dev); /* Register the v4l2_device structure */ @@ -1219,8 +1217,8 @@ static int msi2500_probe(struct usb_interface *intf, goto err_free_mem; } - /* SPI master adapter */ - ctlr = spi_alloc_master(dev->dev, 0); + /* SPI host adapter */ + ctlr = spi_alloc_host(dev->dev, 0); if (ctlr == NULL) { ret = -ENOMEM; goto err_unregister_v4l2_dev; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c index 675dc7153e2b..28ffe7981f8c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-io.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c @@ -335,8 +335,8 @@ static int pvr2_stream_buffer_count(struct pvr2_stream *sp, unsigned int cnt) if (scnt < sp->buffer_slot_count) { struct pvr2_buffer **nb = NULL; if (scnt) { - nb = kmemdup(sp->buffers, scnt * sizeof(*nb), - GFP_KERNEL); + nb = kmemdup_array(sp->buffers, scnt, sizeof(*nb), + GFP_KERNEL); if (!nb) return -ENOMEM; } kfree(sp->buffers); diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index e342199711d3..3ec9eb5956ed 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -760,8 +760,6 @@ static const struct vb2_ops pwc_vb_queue_ops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /***************************************************************************/ @@ -1054,6 +1052,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vb_queue.ops = &pwc_vb_queue_ops; pdev->vb_queue.mem_ops = &vb2_vmalloc_memops; pdev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + pdev->vb_queue.lock = &pdev->vb_queue_lock; rc = vb2_queue_init(&pdev->vb_queue); if (rc < 0) { PWC_ERROR("Oops, could not initialize vb2 queue.\n"); @@ -1064,7 +1063,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vdev = pwc_template; strscpy(pdev->vdev.name, name, sizeof(pdev->vdev.name)); pdev->vdev.queue = &pdev->vb_queue; - pdev->vdev.queue->lock = &pdev->vb_queue_lock; video_set_drvdata(&pdev->vdev, pdev); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index a6e450181fd0..899a7a67e2ba 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -704,8 +704,6 @@ static const struct vb2_ops s2255_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int vidioc_querycap(struct file *file, void *priv, diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index a1f785a5ffd8..5ba3d9c4b3fb 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -734,8 +734,6 @@ static const struct vb2_ops stk1160_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static const struct video_device v4l_template = { diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 702f1c8bd2ab..be22a9697197 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -780,8 +780,6 @@ static const struct vb2_ops usbtv_vb2_ops = { .buf_queue = usbtv_buf_queue, .start_streaming = usbtv_start_streaming, .stop_streaming = usbtv_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 0fac689c6350..b3c8411dc05c 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -371,7 +371,7 @@ static int uvc_parse_format(struct uvc_device *dev, * Parse the frame descriptors. Only uncompressed, MJPEG and frame * based formats have frame descriptors. */ - while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && + while (ftype && buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && buffer[2] == ftype) { unsigned int maxIntervalIndex; @@ -775,14 +775,27 @@ static const u8 uvc_media_transport_input_guid[16] = UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT; static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING; -static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, - unsigned int num_pads, unsigned int extra_size) +static struct uvc_entity *uvc_alloc_new_entity(struct uvc_device *dev, u16 type, + u16 id, unsigned int num_pads, + unsigned int extra_size) { struct uvc_entity *entity; unsigned int num_inputs; unsigned int size; unsigned int i; + /* Per UVC 1.1+ spec 3.7.2, the ID should be non-zero. */ + if (id == 0) { + dev_err(&dev->udev->dev, "Found Unit with invalid ID 0.\n"); + return ERR_PTR(-EINVAL); + } + + /* Per UVC 1.1+ spec 3.7.2, the ID is unique. */ + if (uvc_entity_by_id(dev, id)) { + dev_err(&dev->udev->dev, "Found multiple Units with ID %u\n", id); + return ERR_PTR(-EINVAL); + } + extra_size = roundup(extra_size, sizeof(*entity->pads)); if (num_pads) num_inputs = type & UVC_TERM_OUTPUT ? num_pads : num_pads - 1; @@ -792,7 +805,7 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, + num_inputs; entity = kzalloc(size, GFP_KERNEL); if (entity == NULL) - return NULL; + return ERR_PTR(-ENOMEM); entity->id = id; entity->type = type; @@ -904,10 +917,10 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, break; } - unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3], - p + 1, 2*n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, UVC_VC_EXTENSION_UNIT, + buffer[3], p + 1, 2 * n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->guid, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; @@ -1016,10 +1029,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3], - 1, n + p); - if (term == NULL) - return -ENOMEM; + term = uvc_alloc_new_entity(dev, type | UVC_TERM_INPUT, + buffer[3], 1, n + p); + if (IS_ERR(term)) + return PTR_ERR(term); if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) { term->camera.bControlSize = n; @@ -1075,10 +1088,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return 0; } - term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3], - 1, 0); - if (term == NULL) - return -ENOMEM; + term = uvc_alloc_new_entity(dev, type | UVC_TERM_OUTPUT, + buffer[3], 1, 0); + if (IS_ERR(term)) + return PTR_ERR(term); memcpy(term->baSourceID, &buffer[7], 1); @@ -1097,9 +1110,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], + p + 1, 0); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->baSourceID, &buffer[5], p); @@ -1119,9 +1133,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], 2, n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->baSourceID, &buffer[4], 1); unit->processing.wMaxMultiplier = @@ -1148,9 +1162,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], + p + 1, n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->guid, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; @@ -1290,9 +1305,10 @@ static int uvc_gpio_parse(struct uvc_device *dev) return dev_err_probe(&dev->udev->dev, irq, "No IRQ for privacy GPIO\n"); - unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1); - if (!unit) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, UVC_EXT_GPIO_UNIT, + UVC_EXT_GPIO_UNIT_ID, 0, 1); + if (IS_ERR(unit)) + return PTR_ERR(unit); unit->gpio.gpio_privacy = gpio_privacy; unit->gpio.irq = irq; @@ -1919,11 +1935,41 @@ static void uvc_unregister_video(struct uvc_device *dev) struct uvc_streaming *stream; list_for_each_entry(stream, &dev->streams, list) { + /* Nothing to do here, continue. */ if (!video_is_registered(&stream->vdev)) continue; + /* + * For stream->vdev we follow the same logic as: + * vb2_video_unregister_device(). + */ + + /* 1. Take a reference to vdev */ + get_device(&stream->vdev.dev); + + /* 2. Ensure that no new ioctls can be called. */ video_unregister_device(&stream->vdev); - video_unregister_device(&stream->meta.vdev); + + /* 3. Wait for old ioctls to finish. */ + mutex_lock(&stream->mutex); + + /* 4. Stop streaming. */ + uvc_queue_release(&stream->queue); + + mutex_unlock(&stream->mutex); + + put_device(&stream->vdev.dev); + + /* + * For stream->meta.vdev we can directly call: + * vb2_video_unregister_device(). + */ + vb2_video_unregister_device(&stream->meta.vdev); + + /* + * Now both vdevs are not streaming and all the ioctls will + * return -ENODEV. + */ uvc_debugfs_cleanup_stream(stream); } @@ -2116,7 +2162,6 @@ static int uvc_probe(struct usb_interface *intf, INIT_LIST_HEAD(&dev->streams); kref_init(&dev->ref); atomic_set(&dev->nmappings, 0); - mutex_init(&dev->lock); dev->udev = usb_get_dev(udev); dev->intf = usb_get_intf(intf); @@ -2288,10 +2333,7 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message) /* Controls are cached on the fly so they don't need to be saved. */ if (intf->cur_altsetting->desc.bInterfaceSubClass == UVC_SC_VIDEOCONTROL) { - mutex_lock(&dev->lock); - if (dev->users) - uvc_status_stop(dev); - mutex_unlock(&dev->lock); + uvc_status_suspend(dev); return 0; } @@ -2322,12 +2364,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset) return ret; } - mutex_lock(&dev->lock); - if (dev->users) - ret = uvc_status_start(dev, GFP_NOIO); - mutex_unlock(&dev->lock); - - return ret; + return uvc_status_resume(dev); } list_for_each_entry(stream, &dev->streams, list) { @@ -2428,12 +2465,25 @@ static const struct uvc_device_info uvc_quirk_force_y8 = { * The Logitech cameras listed below have their interface class set to * VENDOR_SPEC because they don't announce themselves as UVC devices, even * though they are compliant. + * + * Sort these by vendor/product ID. */ static const struct usb_device_id uvc_ids[] = { /* Quanta ACER HD User Facing */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x0408, + .idProduct = 0x4033, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = UVC_PC_PROTOCOL_15, + .driver_info = (kernel_ulong_t)&(const struct uvc_device_info){ + .uvc_version = 0x010a, + } }, + /* Quanta ACER HD User Facing */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0408, .idProduct = 0x4035, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, @@ -2964,6 +3014,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceProtocol = 0, .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX | UVC_QUIRK_IGNORE_SELECTOR_UNIT) }, + /* NXP Semiconductors IR VIDEO */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x1fc9, + .idProduct = 0x009b, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax }, /* Oculus VR Positional Tracker DK2 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -3072,6 +3131,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D421 Depth Module */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x1155, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, /* Generic USB Video Class */ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) }, { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) }, diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 16fa17bbd15e..26ee85657fc8 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -197,8 +197,6 @@ static const struct vb2_ops uvc_queue_qops = { .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, .buf_finish = uvc_buffer_finish, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = uvc_start_streaming, .stop_streaming = uvc_stop_streaming, }; @@ -207,8 +205,6 @@ static const struct vb2_ops uvc_meta_queue_qops = { .queue_setup = uvc_queue_setup, .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = uvc_stop_streaming, }; diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index a78a88c710e2..06c867510c8f 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -257,6 +257,8 @@ int uvc_status_init(struct uvc_device *dev) unsigned int pipe; int interval; + mutex_init(&dev->status_lock); + if (ep == NULL) return 0; @@ -292,7 +294,7 @@ int uvc_status_init(struct uvc_device *dev) void uvc_status_unregister(struct uvc_device *dev) { - usb_kill_urb(dev->int_urb); + uvc_status_suspend(dev); uvc_input_unregister(dev); } @@ -302,18 +304,25 @@ void uvc_status_cleanup(struct uvc_device *dev) kfree(dev->status); } -int uvc_status_start(struct uvc_device *dev, gfp_t flags) +static int uvc_status_start(struct uvc_device *dev, gfp_t flags) { - if (dev->int_urb == NULL) + lockdep_assert_held(&dev->status_lock); + + if (!dev->int_urb) return 0; return usb_submit_urb(dev->int_urb, flags); } -void uvc_status_stop(struct uvc_device *dev) +static void uvc_status_stop(struct uvc_device *dev) { struct uvc_ctrl_work *w = &dev->async_ctrl; + lockdep_assert_held(&dev->status_lock); + + if (!dev->int_urb) + return; + /* * Prevent the asynchronous control handler from requeing the URB. The * barrier is needed so the flush_status change is visible to other @@ -350,3 +359,49 @@ void uvc_status_stop(struct uvc_device *dev) */ smp_store_release(&dev->flush_status, false); } + +int uvc_status_resume(struct uvc_device *dev) +{ + guard(mutex)(&dev->status_lock); + + if (dev->status_users) + return uvc_status_start(dev, GFP_NOIO); + + return 0; +} + +void uvc_status_suspend(struct uvc_device *dev) +{ + guard(mutex)(&dev->status_lock); + + if (dev->status_users) + uvc_status_stop(dev); +} + +int uvc_status_get(struct uvc_device *dev) +{ + int ret; + + guard(mutex)(&dev->status_lock); + + if (!dev->status_users) { + ret = uvc_status_start(dev, GFP_KERNEL); + if (ret) + return ret; + } + + dev->status_users++; + + return 0; +} + +void uvc_status_put(struct uvc_device *dev) +{ + guard(mutex)(&dev->status_lock); + + if (dev->status_users == 1) + uvc_status_stop(dev); + WARN_ON(!dev->status_users); + if (dev->status_users) + dev->status_users--; +} diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index f4988f03640a..97c5407f6603 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -628,20 +628,13 @@ static int uvc_v4l2_open(struct file *file) return -ENOMEM; } - mutex_lock(&stream->dev->lock); - if (stream->dev->users == 0) { - ret = uvc_status_start(stream->dev, GFP_KERNEL); - if (ret < 0) { - mutex_unlock(&stream->dev->lock); - usb_autopm_put_interface(stream->dev->intf); - kfree(handle); - return ret; - } + ret = uvc_status_get(stream->dev); + if (ret) { + usb_autopm_put_interface(stream->dev->intf); + kfree(handle); + return ret; } - stream->dev->users++; - mutex_unlock(&stream->dev->lock); - v4l2_fh_init(&handle->vfh, &stream->vdev); v4l2_fh_add(&handle->vfh); handle->chain = stream->chain; @@ -670,10 +663,7 @@ static int uvc_v4l2_release(struct file *file) kfree(handle); file->private_data = NULL; - mutex_lock(&stream->dev->lock); - if (--stream->dev->users == 0) - uvc_status_stop(stream->dev); - mutex_unlock(&stream->dev->lock); + uvc_status_put(stream->dev); usb_autopm_put_interface(stream->dev->intf); return 0; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index b7d24a853ce4..07f9921d83f2 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -563,8 +563,6 @@ struct uvc_device { const struct uvc_device_info *info; - struct mutex lock; /* Protects users */ - unsigned int users; atomic_t nmappings; /* Video control interface */ @@ -586,6 +584,8 @@ struct uvc_device { struct usb_host_endpoint *int_ep; struct urb *int_urb; struct uvc_status *status; + struct mutex status_lock; /* Protects status_users */ + unsigned int status_users; bool flush_status; struct input_dev *input; @@ -752,8 +752,10 @@ int uvc_register_video_device(struct uvc_device *dev, int uvc_status_init(struct uvc_device *dev); void uvc_status_unregister(struct uvc_device *dev); void uvc_status_cleanup(struct uvc_device *dev); -int uvc_status_start(struct uvc_device *dev, gfp_t flags); -void uvc_status_stop(struct uvc_device *dev); +int uvc_status_resume(struct uvc_device *dev); +void uvc_status_suspend(struct uvc_device *dev); +int uvc_status_get(struct uvc_device *dev); +void uvc_status_put(struct uvc_device *dev); /* Controls */ extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops; diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index e5a364efd5e6..95a2202879d8 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -753,9 +753,10 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c) for (i = 0; i < master->ncontrols; i++) cur_to_new(master->cluster[i]); ret = call_op(master, g_volatile_ctrl); - new_to_user(c, ctrl); + if (!ret) + ret = new_to_user(c, ctrl); } else { - cur_to_user(c, ctrl); + ret = cur_to_user(c, ctrl); } v4l2_ctrl_unlock(master); return ret; @@ -770,7 +771,10 @@ int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control) if (!ctrl || !ctrl->is_int) return -EINVAL; ret = get_ctrl(ctrl, &c); - control->value = c.value; + + if (!ret) + control->value = c.value; + return ret; } EXPORT_SYMBOL(v4l2_g_ctrl); @@ -811,10 +815,11 @@ static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, int ret; v4l2_ctrl_lock(ctrl); - user_to_new(c, ctrl); - ret = set_ctrl(fh, ctrl, 0); + ret = user_to_new(c, ctrl); + if (!ret) + ret = set_ctrl(fh, ctrl, 0); if (!ret) - cur_to_user(c, ctrl); + ret = cur_to_user(c, ctrl); v4l2_ctrl_unlock(ctrl); return ret; } diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 3d7711cc42bc..5bcaeeba4d09 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -93,6 +93,8 @@ static struct attribute *video_device_attrs[] = { }; ATTRIBUTE_GROUPS(video_device); +static struct dentry *v4l2_debugfs_root_dir; + /* * Active devices */ @@ -227,7 +229,7 @@ static void v4l2_device_release(struct device *cd) v4l2_device_put(v4l2_dev); } -static struct class video_class = { +static const struct class video_class = { .name = VIDEO_NAME, .dev_groups = video_device_groups, }; @@ -1118,6 +1120,16 @@ void video_unregister_device(struct video_device *vdev) } EXPORT_SYMBOL(video_unregister_device); +#ifdef CONFIG_DEBUG_FS +struct dentry *v4l2_debugfs_root(void) +{ + if (!v4l2_debugfs_root_dir) + v4l2_debugfs_root_dir = debugfs_create_dir("v4l2", NULL); + return v4l2_debugfs_root_dir; +} +EXPORT_SYMBOL_GPL(v4l2_debugfs_root); +#endif + #if defined(CONFIG_MEDIA_CONTROLLER) __must_check int video_device_pipeline_start(struct video_device *vdev, @@ -1222,6 +1234,8 @@ static void __exit videodev_exit(void) class_unregister(&video_class); unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); + debugfs_remove_recursive(v4l2_debugfs_root_dir); + v4l2_debugfs_root_dir = NULL; } subsys_initcall(videodev_init); diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 942d0005c55e..d26edf157e64 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -481,25 +481,28 @@ EXPORT_SYMBOL_GPL(v4l2_calc_timeperframe); * @polarities - the horizontal and vertical polarities (same as struct * v4l2_bt_timings polarities). * @interlaced - if this flag is true, it indicates interlaced format - * @fmt - the resulting timings. + * @cap - the v4l2_dv_timings_cap capabilities. + * @timings - the resulting timings. * * This function will attempt to detect if the given values correspond to a * valid CVT format. If so, then it will return true, and fmt will be filled * in with the found CVT timings. */ -bool v4l2_detect_cvt(unsigned frame_height, - unsigned hfreq, - unsigned vsync, - unsigned active_width, +bool v4l2_detect_cvt(unsigned int frame_height, + unsigned int hfreq, + unsigned int vsync, + unsigned int active_width, u32 polarities, bool interlaced, - struct v4l2_dv_timings *fmt) + const struct v4l2_dv_timings_cap *cap, + struct v4l2_dv_timings *timings) { - int v_fp, v_bp, h_fp, h_bp, hsync; - int frame_width, image_height, image_width; + struct v4l2_dv_timings t = {}; + int v_fp, v_bp, h_fp, h_bp, hsync; + int frame_width, image_height, image_width; bool reduced_blanking; bool rb_v2 = false; - unsigned pix_clk; + unsigned int pix_clk; if (vsync < 4 || vsync > 8) return false; @@ -625,36 +628,39 @@ bool v4l2_detect_cvt(unsigned frame_height, h_fp = h_blank - hsync - h_bp; } - fmt->type = V4L2_DV_BT_656_1120; - fmt->bt.polarities = polarities; - fmt->bt.width = image_width; - fmt->bt.height = image_height; - fmt->bt.hfrontporch = h_fp; - fmt->bt.vfrontporch = v_fp; - fmt->bt.hsync = hsync; - fmt->bt.vsync = vsync; - fmt->bt.hbackporch = frame_width - image_width - h_fp - hsync; + t.type = V4L2_DV_BT_656_1120; + t.bt.polarities = polarities; + t.bt.width = image_width; + t.bt.height = image_height; + t.bt.hfrontporch = h_fp; + t.bt.vfrontporch = v_fp; + t.bt.hsync = hsync; + t.bt.vsync = vsync; + t.bt.hbackporch = frame_width - image_width - h_fp - hsync; if (!interlaced) { - fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync; - fmt->bt.interlaced = V4L2_DV_PROGRESSIVE; + t.bt.vbackporch = frame_height - image_height - v_fp - vsync; + t.bt.interlaced = V4L2_DV_PROGRESSIVE; } else { - fmt->bt.vbackporch = (frame_height - image_height - 2 * v_fp - + t.bt.vbackporch = (frame_height - image_height - 2 * v_fp - 2 * vsync) / 2; - fmt->bt.il_vbackporch = frame_height - image_height - 2 * v_fp - - 2 * vsync - fmt->bt.vbackporch; - fmt->bt.il_vfrontporch = v_fp; - fmt->bt.il_vsync = vsync; - fmt->bt.flags |= V4L2_DV_FL_HALF_LINE; - fmt->bt.interlaced = V4L2_DV_INTERLACED; + t.bt.il_vbackporch = frame_height - image_height - 2 * v_fp - + 2 * vsync - t.bt.vbackporch; + t.bt.il_vfrontporch = v_fp; + t.bt.il_vsync = vsync; + t.bt.flags |= V4L2_DV_FL_HALF_LINE; + t.bt.interlaced = V4L2_DV_INTERLACED; } - fmt->bt.pixelclock = pix_clk; - fmt->bt.standards = V4L2_DV_BT_STD_CVT; + t.bt.pixelclock = pix_clk; + t.bt.standards = V4L2_DV_BT_STD_CVT; if (reduced_blanking) - fmt->bt.flags |= V4L2_DV_FL_REDUCED_BLANKING; + t.bt.flags |= V4L2_DV_FL_REDUCED_BLANKING; + if (!v4l2_valid_dv_timings(&t, cap, NULL, NULL)) + return false; + *timings = t; return true; } EXPORT_SYMBOL_GPL(v4l2_detect_cvt); @@ -699,22 +705,25 @@ EXPORT_SYMBOL_GPL(v4l2_detect_cvt); * image height, so it has to be passed explicitly. Usually * the native screen aspect ratio is used for this. If it * is not filled in correctly, then 16:9 will be assumed. - * @fmt - the resulting timings. + * @cap - the v4l2_dv_timings_cap capabilities. + * @timings - the resulting timings. * * This function will attempt to detect if the given values correspond to a * valid GTF format. If so, then it will return true, and fmt will be filled * in with the found GTF timings. */ -bool v4l2_detect_gtf(unsigned frame_height, - unsigned hfreq, - unsigned vsync, - u32 polarities, - bool interlaced, - struct v4l2_fract aspect, - struct v4l2_dv_timings *fmt) +bool v4l2_detect_gtf(unsigned int frame_height, + unsigned int hfreq, + unsigned int vsync, + u32 polarities, + bool interlaced, + struct v4l2_fract aspect, + const struct v4l2_dv_timings_cap *cap, + struct v4l2_dv_timings *timings) { + struct v4l2_dv_timings t = {}; int pix_clk; - int v_fp, v_bp, h_fp, hsync; + int v_fp, v_bp, h_fp, hsync; int frame_width, image_height, image_width; bool default_gtf; int h_blank; @@ -783,36 +792,39 @@ bool v4l2_detect_gtf(unsigned frame_height, h_fp = h_blank / 2 - hsync; - fmt->type = V4L2_DV_BT_656_1120; - fmt->bt.polarities = polarities; - fmt->bt.width = image_width; - fmt->bt.height = image_height; - fmt->bt.hfrontporch = h_fp; - fmt->bt.vfrontporch = v_fp; - fmt->bt.hsync = hsync; - fmt->bt.vsync = vsync; - fmt->bt.hbackporch = frame_width - image_width - h_fp - hsync; + t.type = V4L2_DV_BT_656_1120; + t.bt.polarities = polarities; + t.bt.width = image_width; + t.bt.height = image_height; + t.bt.hfrontporch = h_fp; + t.bt.vfrontporch = v_fp; + t.bt.hsync = hsync; + t.bt.vsync = vsync; + t.bt.hbackporch = frame_width - image_width - h_fp - hsync; if (!interlaced) { - fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync; - fmt->bt.interlaced = V4L2_DV_PROGRESSIVE; + t.bt.vbackporch = frame_height - image_height - v_fp - vsync; + t.bt.interlaced = V4L2_DV_PROGRESSIVE; } else { - fmt->bt.vbackporch = (frame_height - image_height - 2 * v_fp - + t.bt.vbackporch = (frame_height - image_height - 2 * v_fp - 2 * vsync) / 2; - fmt->bt.il_vbackporch = frame_height - image_height - 2 * v_fp - - 2 * vsync - fmt->bt.vbackporch; - fmt->bt.il_vfrontporch = v_fp; - fmt->bt.il_vsync = vsync; - fmt->bt.flags |= V4L2_DV_FL_HALF_LINE; - fmt->bt.interlaced = V4L2_DV_INTERLACED; + t.bt.il_vbackporch = frame_height - image_height - 2 * v_fp - + 2 * vsync - t.bt.vbackporch; + t.bt.il_vfrontporch = v_fp; + t.bt.il_vsync = vsync; + t.bt.flags |= V4L2_DV_FL_HALF_LINE; + t.bt.interlaced = V4L2_DV_INTERLACED; } - fmt->bt.pixelclock = pix_clk; - fmt->bt.standards = V4L2_DV_BT_STD_GTF; + t.bt.pixelclock = pix_clk; + t.bt.standards = V4L2_DV_BT_STD_GTF; if (!default_gtf) - fmt->bt.flags |= V4L2_DV_FL_REDUCED_BLANKING; + t.bt.flags |= V4L2_DV_FL_REDUCED_BLANKING; + if (!v4l2_valid_dv_timings(&t, cap, NULL, NULL)) + return false; + *timings = t; return true; } EXPORT_SYMBOL_GPL(v4l2_detect_gtf); @@ -1154,3 +1166,70 @@ int v4l2_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port) return 0; } EXPORT_SYMBOL_GPL(v4l2_phys_addr_validate); + +#ifdef CONFIG_DEBUG_FS + +#define DEBUGFS_FOPS(type, flag) \ +static ssize_t \ +infoframe_read_##type(struct file *filp, \ + char __user *ubuf, size_t count, loff_t *ppos) \ +{ \ + struct v4l2_debugfs_if *infoframes = filp->private_data; \ + \ + return infoframes->if_read((flag), infoframes->priv, filp, \ + ubuf, count, ppos); \ +} \ + \ +static const struct file_operations infoframe_##type##_fops = { \ + .owner = THIS_MODULE, \ + .open = simple_open, \ + .read = infoframe_read_##type, \ +} + +DEBUGFS_FOPS(avi, V4L2_DEBUGFS_IF_AVI); +DEBUGFS_FOPS(audio, V4L2_DEBUGFS_IF_AUDIO); +DEBUGFS_FOPS(spd, V4L2_DEBUGFS_IF_SPD); +DEBUGFS_FOPS(hdmi, V4L2_DEBUGFS_IF_HDMI); + +struct v4l2_debugfs_if *v4l2_debugfs_if_alloc(struct dentry *root, u32 if_types, + void *priv, + v4l2_debugfs_if_read_t if_read) +{ + struct v4l2_debugfs_if *infoframes; + + if (IS_ERR_OR_NULL(root) || !if_types || !if_read) + return NULL; + + infoframes = kzalloc(sizeof(*infoframes), GFP_KERNEL); + if (!infoframes) + return NULL; + + infoframes->if_dir = debugfs_create_dir("infoframes", root); + infoframes->priv = priv; + infoframes->if_read = if_read; + if (if_types & V4L2_DEBUGFS_IF_AVI) + debugfs_create_file("avi", 0400, infoframes->if_dir, + infoframes, &infoframe_avi_fops); + if (if_types & V4L2_DEBUGFS_IF_AUDIO) + debugfs_create_file("audio", 0400, infoframes->if_dir, + infoframes, &infoframe_audio_fops); + if (if_types & V4L2_DEBUGFS_IF_SPD) + debugfs_create_file("spd", 0400, infoframes->if_dir, + infoframes, &infoframe_spd_fops); + if (if_types & V4L2_DEBUGFS_IF_HDMI) + debugfs_create_file("hdmi", 0400, infoframes->if_dir, + infoframes, &infoframe_hdmi_fops); + return infoframes; +} +EXPORT_SYMBOL_GPL(v4l2_debugfs_if_alloc); + +void v4l2_debugfs_if_free(struct v4l2_debugfs_if *infoframes) +{ + if (infoframes) { + debugfs_remove_recursive(infoframes->if_dir); + kfree(infoframes); + } +} +EXPORT_SYMBOL_GPL(v4l2_debugfs_if_free); + +#endif diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index e14db67be97c..0304daa8471d 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1327,6 +1327,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_Y14P: descr = "14-bit Greyscale (MIPI Packed)"; break; case V4L2_PIX_FMT_Y8I: descr = "Interleaved 8-bit Greyscale"; break; case V4L2_PIX_FMT_Y12I: descr = "Interleaved 12-bit Greyscale"; break; + case V4L2_PIX_FMT_Y16I: descr = "Interleaved 16-bit Greyscale"; break; case V4L2_PIX_FMT_Z16: descr = "16-bit Depth"; break; case V4L2_PIX_FMT_INZI: descr = "Planar 10:16 Greyscale Depth"; break; case V4L2_PIX_FMT_CNF4: descr = "4-bit Depth Confidence (Packed)"; break; @@ -1467,6 +1468,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_Y212: descr = "12-bit YUYV Packed"; break; case V4L2_PIX_FMT_Y216: descr = "16-bit YUYV Packed"; break; case V4L2_META_FMT_RPI_BE_CFG: descr = "RPi PiSP BE Config format"; break; + case V4L2_META_FMT_RPI_FE_CFG: descr = "RPi PiSP FE Config format"; break; + case V4L2_META_FMT_RPI_FE_STATS: descr = "RPi PiSP FE Statistics format"; break; case V4L2_META_FMT_GENERIC_8: descr = "8-bit Generic Metadata"; break; case V4L2_META_FMT_GENERIC_CSI2_10: descr = "8-bit Generic Meta, 10b CSI-2"; break; case V4L2_META_FMT_GENERIC_CSI2_12: descr = "8-bit Generic Meta, 12b CSI-2"; break; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 3a4ba08810d2..cde1774c9098 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -334,6 +334,11 @@ static int call_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, unsigned int i; int ret; +#if defined(CONFIG_MEDIA_CONTROLLER) + if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) + return -EOPNOTSUPP; +#endif + memset(fd, 0, sizeof(*fd)); ret = sd->ops->pad->get_frame_desc(sd, pad, fd); @@ -691,10 +696,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); case VIDIOC_SUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); + if (v4l2_subdev_has_op(sd, core, subscribe_event)) + return v4l2_subdev_call(sd, core, subscribe_event, + vfh, arg); + + if ((sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) && + vfh->ctrl_handler) + return v4l2_ctrl_subdev_subscribe_event(sd, vfh, arg); + + return -ENOIOCTLCMD; case VIDIOC_UNSUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); + if (v4l2_subdev_has_op(sd, core, unsubscribe_event)) + return v4l2_subdev_call(sd, core, unsubscribe_event, + vfh, arg); + + if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) + return v4l2_event_subdev_unsubscribe(sd, vfh, arg); + + return -ENOIOCTLCMD; #ifdef CONFIG_VIDEO_ADV_DEBUG case VIDIOC_DBG_G_REGISTER: @@ -1641,6 +1661,9 @@ int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name, } } + if (sd->ctrl_handler) + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + state = __v4l2_subdev_state_alloc(sd, name, key); if (IS_ERR(state)) return PTR_ERR(state); |